Skip to content

Commit 7fd8b23

Browse files
committed
Change BuildOptions to take in a generator directly.
1 parent 3bddcb0 commit 7fd8b23

File tree

11 files changed

+86
-77
lines changed

11 files changed

+86
-77
lines changed

internal/cli/build.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import (
3737
"chainguard.dev/apko/pkg/build"
3838
"chainguard.dev/apko/pkg/build/oci"
3939
"chainguard.dev/apko/pkg/build/types"
40-
"chainguard.dev/apko/pkg/sbom"
40+
"chainguard.dev/apko/pkg/sbom/generator"
4141
"chainguard.dev/apko/pkg/tarfs"
4242
)
4343

@@ -85,8 +85,9 @@ Along the image, apko will generate SBOMs (software bill of materials) describin
8585
return fmt.Errorf("parsing annotations from command line: %w", err)
8686
}
8787

88-
if !writeSBOM {
89-
sbomFormats = []string{}
88+
var sbomGenerators []generator.Generator
89+
if writeSBOM && len(sbomFormats) > 0 {
90+
sbomGenerators = generator.Generators(sbomFormats...)
9091
}
9192

9293
tmp, err := os.MkdirTemp(os.TempDir(), "apko-temp-*")
@@ -102,7 +103,7 @@ Along the image, apko will generate SBOMs (software bill of materials) describin
102103
build.WithConfig(args[0], includePaths),
103104
build.WithBuildDate(buildDate),
104105
build.WithSBOM(sbomPath),
105-
build.WithSBOMFormats(sbomFormats),
106+
build.WithSBOMGenerators(sbomGenerators...),
106107
build.WithExtraKeys(extraKeys),
107108
build.WithExtraBuildRepos(extraBuildRepos),
108109
build.WithExtraRepos(extraRepos),
@@ -125,7 +126,7 @@ Along the image, apko will generate SBOMs (software bill of materials) describin
125126
cmd.Flags().StringVar(&sbomPath, "sbom-path", "", "generate SBOMs in dir (defaults to image directory)")
126127
cmd.Flags().StringSliceVar(&archstrs, "arch", nil, "architectures to build for (e.g., x86_64,ppc64le,arm64) -- default is all, unless specified in config. Can also use 'host' to indicate arch of host this is running on")
127128
cmd.Flags().StringSliceVarP(&extraKeys, "keyring-append", "k", []string{}, "path to extra keys to include in the keyring")
128-
cmd.Flags().StringSliceVar(&sbomFormats, "sbom-formats", sbom.DefaultOptions.Formats, "SBOM formats to output")
129+
cmd.Flags().StringSliceVar(&sbomFormats, "sbom-formats", []string{"spdx"}, "SBOM formats to output")
129130
cmd.Flags().StringSliceVarP(&extraBuildRepos, "build-repository-append", "b", []string{}, "path to extra repositories to include")
130131
cmd.Flags().StringSliceVarP(&extraRepos, "repository-append", "r", []string{}, "path to extra repositories to include")
131132
cmd.Flags().StringSliceVarP(&extraPackages, "package-append", "p", []string{}, "extra packages to include")
@@ -285,7 +286,7 @@ func buildImageComponents(ctx context.Context, workDir string, archs []types.Arc
285286
}
286287

287288
var outputs []types.SBOM
288-
if len(o.SBOMFormats) != 0 {
289+
if len(o.SBOMGenerators) != 0 {
289290
outputs, err = bc.GenerateImageSBOM(ctx, arch, img)
290291
if err != nil {
291292
return fmt.Errorf("generating sbom for %s: %w", arch, err)
@@ -301,7 +302,7 @@ func buildImageComponents(ctx context.Context, workDir string, archs []types.Arc
301302
multiArchBDE = bde
302303
}
303304

304-
if len(o.SBOMFormats) != 0 {
305+
if len(o.SBOMGenerators) != 0 {
305306
sboms = append(sboms, outputs...)
306307
}
307308

@@ -333,7 +334,7 @@ func buildImageComponents(ctx context.Context, workDir string, archs []types.Arc
333334
}
334335

335336
// the sboms are saved to the same working directory as the image components
336-
if len(o.SBOMFormats) != 0 {
337+
if len(o.SBOMGenerators) != 0 {
337338
files, err := build.GenerateIndexSBOM(ctx, *o, *ic, finalDigest, imgs)
338339
if err != nil {
339340
return nil, nil, fmt.Errorf("generating index SBOM: %w", err)

internal/cli/build_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"chainguard.dev/apko/internal/cli"
3131
"chainguard.dev/apko/pkg/build"
3232
"chainguard.dev/apko/pkg/build/types"
33+
"chainguard.dev/apko/pkg/sbom/generator/spdx"
3334
)
3435

3536
func TestBuild(t *testing.T) {
@@ -43,7 +44,7 @@ func TestBuild(t *testing.T) {
4344
archs := types.ParseArchitectures([]string{"amd64", "arm64"})
4445
opts := []build.Option{
4546
build.WithConfig(config, []string{}),
46-
build.WithSBOMFormats([]string{"spdx"}),
47+
build.WithSBOMGenerators(spdx.New()),
4748
build.WithTags("golden:latest"),
4849
build.WithAnnotations(map[string]string{
4950
"org.opencontainers.image.vendor": "Vendor",
@@ -126,7 +127,7 @@ func TestBuildWithBase(t *testing.T) {
126127
lockfile := filepath.Join("testdata", "image_on_top.apko.lock.json")
127128

128129
archs := types.ParseArchitectures([]string{"amd64", "arm64"})
129-
opts := []build.Option{build.WithConfig(config, []string{}), build.WithSBOMFormats([]string{"spdx"}), build.WithTags("golden_top:latest"), build.WithLockFile(lockfile), build.WithTempDir(apkoTempDir)}
130+
opts := []build.Option{build.WithConfig(config, []string{}), build.WithSBOMGenerators(spdx.New()), build.WithTags("golden_top:latest"), build.WithLockFile(lockfile), build.WithTempDir(apkoTempDir)}
130131

131132
sbomPath := filepath.Join(tmp, "sboms")
132133
err := os.MkdirAll(sbomPath, 0o750)

internal/cli/publish.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import (
3535
"chainguard.dev/apko/pkg/build"
3636
"chainguard.dev/apko/pkg/build/oci"
3737
"chainguard.dev/apko/pkg/build/types"
38-
"chainguard.dev/apko/pkg/sbom"
38+
"chainguard.dev/apko/pkg/sbom/generator"
3939
)
4040

4141
func publish() *cobra.Command {
@@ -70,8 +70,9 @@ in a keychain.`,
7070
return fmt.Errorf("requires at least 2 arg(s), 1 config file and at least 1 tag for the image")
7171
}
7272

73-
if !writeSBOM {
74-
sbomFormats = []string{}
73+
var sbomGenerators []generator.Generator
74+
if writeSBOM && len(sbomFormats) > 0 {
75+
sbomGenerators = generator.Generators(sbomFormats...)
7576
}
7677
archs := types.ParseArchitectures(archstrs)
7778
annotations, err := parseAnnotations(rawAnnotations)
@@ -109,7 +110,7 @@ in a keychain.`,
109110
build.WithConfig(args[0], []string{}),
110111
build.WithBuildDate(buildDate),
111112
build.WithSBOM(sbomPath),
112-
build.WithSBOMFormats(sbomFormats),
113+
build.WithSBOMGenerators(sbomGenerators...),
113114
build.WithExtraKeys(extraKeys),
114115
build.WithExtraBuildRepos(extraBuildRepos),
115116
build.WithExtraRepos(extraRepos),
@@ -140,7 +141,7 @@ in a keychain.`,
140141
cmd.Flags().StringVar(&sbomPath, "sbom-path", "", "path to write the SBOMs")
141142
cmd.Flags().StringSliceVar(&archstrs, "arch", nil, "architectures to build for (e.g., x86_64,ppc64le,arm64) -- default is all, unless specified in config.")
142143
cmd.Flags().StringSliceVarP(&extraKeys, "keyring-append", "k", []string{}, "path to extra keys to include in the keyring")
143-
cmd.Flags().StringSliceVar(&sbomFormats, "sbom-formats", sbom.DefaultOptions.Formats, "SBOM formats to output")
144+
cmd.Flags().StringSliceVar(&sbomFormats, "sbom-formats", []string{"spdx"}, "SBOM formats to output")
144145
cmd.Flags().StringSliceVarP(&extraBuildRepos, "build-repository-append", "b", []string{}, "path to extra repositories to include")
145146
cmd.Flags().StringSliceVarP(&extraRepos, "repository-append", "r", []string{}, "path to extra repositories to include")
146147
cmd.Flags().StringSliceVarP(&extraPackages, "package-append", "p", []string{}, "extra packages to include")

internal/cli/publish_test.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,7 @@ import (
4141
"chainguard.dev/apko/internal/tarfs"
4242
"chainguard.dev/apko/pkg/build"
4343
"chainguard.dev/apko/pkg/build/types"
44-
"chainguard.dev/apko/pkg/sbom"
45-
46-
_ "chainguard.dev/apko/pkg/sbom/generator/spdx"
44+
"chainguard.dev/apko/pkg/sbom/generator/spdx"
4745
)
4846

4947
func TestPublish(t *testing.T) {
@@ -74,7 +72,7 @@ func TestPublish(t *testing.T) {
7472
opts := []build.Option{
7573
build.WithConfig(config, []string{}),
7674
build.WithTags(dst),
77-
build.WithSBOMFormats(sbom.DefaultOptions.Formats),
75+
build.WithSBOMGenerators(spdx.New()),
7876
build.WithAnnotations(map[string]string{"foo": "bar"}),
7977
}
8078
publishOpts := []cli.PublishOption{cli.WithTags(dst)}
@@ -148,7 +146,7 @@ func TestPublishLayering(t *testing.T) {
148146
opts := []build.Option{
149147
build.WithConfig(config, []string{}),
150148
build.WithTags(dst),
151-
build.WithSBOMFormats(sbom.DefaultOptions.Formats),
149+
build.WithSBOMGenerators(spdx.New()),
152150
build.WithAnnotations(map[string]string{"foo": "bar"}),
153151
}
154152
publishOpts := []cli.PublishOption{cli.WithTags(dst)}

pkg/build/build.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ func (bc *Context) Arch() types.Architecture {
498498
}
499499

500500
func (bc *Context) WantSBOM() bool {
501-
return len(bc.o.SBOMFormats) != 0
501+
return len(bc.o.SBOMGenerators) != 0
502502
}
503503

504504
func (bc *Context) APK() *apk.APK {

pkg/build/options.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"chainguard.dev/apko/pkg/apk/apk"
2727
"chainguard.dev/apko/pkg/apk/auth"
2828
"chainguard.dev/apko/pkg/build/types"
29+
"chainguard.dev/apko/pkg/sbom/generator"
2930

3031
"github.com/chainguard-dev/clog"
3132
)
@@ -110,9 +111,20 @@ func WithSBOM(path string) Option {
110111
}
111112
}
112113

114+
// WithSBOMFormats sets the SBOM generators to use.
115+
//
116+
// Deprecated: use WithSBOMGenerators instead.
113117
func WithSBOMFormats(formats []string) Option {
114118
return func(bc *Context) error {
115-
bc.o.SBOMFormats = formats
119+
bc.o.SBOMGenerators = generator.Generators(formats...)
120+
return nil
121+
}
122+
}
123+
124+
// WithSBOMGenerators sets the SBOM generators to use.
125+
func WithSBOMGenerators(generators ...generator.Generator) Option {
126+
return func(bc *Context) error {
127+
bc.o.SBOMGenerators = generators
116128
return nil
117129
}
118130
}

pkg/build/sbom.go

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ import (
3838
"chainguard.dev/apko/pkg/build/types"
3939
"chainguard.dev/apko/pkg/options"
4040
"chainguard.dev/apko/pkg/sbom"
41-
"chainguard.dev/apko/pkg/sbom/generator"
4241
soptions "chainguard.dev/apko/pkg/sbom/options"
4342
)
4443

@@ -60,7 +59,6 @@ func newSBOM(ctx context.Context, fsys apkfs.FullFS, o options.Options, ic types
6059
}
6160

6261
sopt.ImageInfo.SourceDateEpoch = bde
63-
sopt.Formats = o.SBOMFormats
6462
sopt.ImageInfo.VCSUrl = ic.VCSUrl
6563
sopt.ImageInfo.ImageMediaType = ggcrtypes.OCIManifestSchema1
6664

@@ -125,20 +123,14 @@ func (bc *Context) GenerateImageSBOM(ctx context.Context, arch types.Architectur
125123
s.ImageInfo.Arch = arch
126124

127125
var sboms = make([]types.SBOM, 0)
128-
generators := generator.Generators()
129-
for _, format := range s.Formats {
130-
gen, ok := generators[format]
131-
if !ok {
132-
return nil, fmt.Errorf("unable to generate sboms: no generator available for format %s", format)
133-
}
134-
126+
for _, gen := range bc.o.SBOMGenerators {
135127
filename := filepath.Join(s.OutputDir, s.FileName+"."+gen.Ext())
136128
if err := gen.Generate(ctx, &s, filename); err != nil {
137-
return nil, fmt.Errorf("generating %s sbom: %w", format, err)
129+
return nil, fmt.Errorf("generating %s sbom: %w", gen.Key(), err)
138130
}
139131
sboms = append(sboms, types.SBOM{
140132
Path: filename,
141-
Format: format,
133+
Format: gen.Key(),
142134
Arch: arch.String(),
143135
Digest: h,
144136
})
@@ -212,7 +204,7 @@ func GenerateIndexSBOM(ctx context.Context, o options.Options, ic types.ImageCon
212204
_, span := otel.Tracer("apko").Start(ctx, "GenerateIndexSBOM")
213205
defer span.End()
214206

215-
if len(o.SBOMFormats) == 0 {
207+
if len(o.SBOMGenerators) == 0 {
216208
log.Warn("skipping SBOM generation")
217209
return nil, nil
218210
}
@@ -238,14 +230,8 @@ func GenerateIndexSBOM(ctx context.Context, o options.Options, ic types.ImageCon
238230
return archs[i].String() < archs[j].String()
239231
})
240232

241-
generators := generator.Generators()
242-
var sboms = make([]types.SBOM, 0, len(generators))
243-
for _, format := range s.Formats {
244-
gen, ok := generators[format]
245-
if !ok {
246-
return nil, fmt.Errorf("unable to generate sboms: no generator available for format %s", format)
247-
}
248-
233+
var sboms = make([]types.SBOM, 0, len(o.SBOMGenerators))
234+
for _, gen := range o.SBOMGenerators {
249235
archImageInfos := make([]soptions.ArchImageInfo, 0, len(archs))
250236
for _, arch := range archs {
251237
i := imgs[arch]
@@ -270,11 +256,11 @@ func GenerateIndexSBOM(ctx context.Context, o options.Options, ic types.ImageCon
270256

271257
filename := filepath.Join(s.OutputDir, "sbom-index."+gen.Ext())
272258
if err := gen.GenerateIndex(&s, filename); err != nil {
273-
return nil, fmt.Errorf("generating %s sbom: %w", format, err)
259+
return nil, fmt.Errorf("generating %s sbom: %w", gen.Key(), err)
274260
}
275261
sboms = append(sboms, types.SBOM{
276262
Path: filename,
277-
Format: format,
263+
Format: gen.Key(),
278264
Digest: h,
279265
})
280266
}

pkg/options/options.go

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,38 +25,39 @@ import (
2525
"chainguard.dev/apko/pkg/apk/apk"
2626
"chainguard.dev/apko/pkg/apk/auth"
2727
"chainguard.dev/apko/pkg/build/types"
28+
"chainguard.dev/apko/pkg/sbom/generator"
2829
)
2930

3031
type Options struct {
3132
WithVCS bool `json:"withVCS,omitempty"`
3233
// ImageConfigFile might, but does not have to be a filename. It might be any abstract configuration identifier.
3334
ImageConfigFile string `json:"imageConfigFile,omitempty"`
3435
// ImageConfigChecksum (when set) allows to detect mismatch between configuration and the lockfile.
35-
ImageConfigChecksum string `json:"configChecksum,omitempty"`
36-
TarballPath string `json:"tarballPath,omitempty"`
37-
Tags []string `json:"tags,omitempty"`
38-
SourceDateEpoch time.Time `json:"sourceDateEpoch,omitempty"`
39-
SBOMPath string `json:"sbomPath,omitempty"`
40-
SBOMFormats []string `json:"sbomFormats,omitempty"`
41-
ExtraKeyFiles []string `json:"extraKeyFiles,omitempty"`
42-
ExtraBuildRepos []string `json:"extraBuildRepos,omitempty"`
43-
ExtraRepos []string `json:"extraRepos,omitempty"`
44-
ExtraPackages []string `json:"extraPackages,omitempty"`
45-
Arch types.Architecture `json:"arch,omitempty"`
46-
TempDirPath string `json:"tempDirPath,omitempty"`
47-
PackageVersionTag string `json:"packageVersionTag,omitempty"`
48-
PackageVersionTagStem bool `json:"packageVersionTagStem,omitempty"`
49-
PackageVersionTagPrefix string `json:"packageVersionTagPrefix,omitempty"`
50-
TagSuffix string `json:"tagSuffix,omitempty"`
51-
Local bool `json:"local,omitempty"`
52-
CacheDir string `json:"cacheDir,omitempty"`
53-
Offline bool `json:"offline,omitempty"`
54-
SharedCache *apk.Cache `json:"-"`
55-
Lockfile string `json:"lockfile,omitempty"`
56-
Auth auth.Authenticator `json:"-"`
57-
IncludePaths []string `json:"includePaths,omitempty"`
58-
IgnoreSignatures bool `json:"ignoreSignatures,omitempty"`
59-
Transport http.RoundTripper `json:"-"`
36+
ImageConfigChecksum string `json:"configChecksum,omitempty"`
37+
TarballPath string `json:"tarballPath,omitempty"`
38+
Tags []string `json:"tags,omitempty"`
39+
SourceDateEpoch time.Time `json:"sourceDateEpoch,omitempty"`
40+
SBOMPath string `json:"sbomPath,omitempty"`
41+
SBOMGenerators []generator.Generator `json:"-"`
42+
ExtraKeyFiles []string `json:"extraKeyFiles,omitempty"`
43+
ExtraBuildRepos []string `json:"extraBuildRepos,omitempty"`
44+
ExtraRepos []string `json:"extraRepos,omitempty"`
45+
ExtraPackages []string `json:"extraPackages,omitempty"`
46+
Arch types.Architecture `json:"arch,omitempty"`
47+
TempDirPath string `json:"tempDirPath,omitempty"`
48+
PackageVersionTag string `json:"packageVersionTag,omitempty"`
49+
PackageVersionTagStem bool `json:"packageVersionTagStem,omitempty"`
50+
PackageVersionTagPrefix string `json:"packageVersionTagPrefix,omitempty"`
51+
TagSuffix string `json:"tagSuffix,omitempty"`
52+
Local bool `json:"local,omitempty"`
53+
CacheDir string `json:"cacheDir,omitempty"`
54+
Offline bool `json:"offline,omitempty"`
55+
SharedCache *apk.Cache `json:"-"`
56+
Lockfile string `json:"lockfile,omitempty"`
57+
Auth auth.Authenticator `json:"-"`
58+
IncludePaths []string `json:"includePaths,omitempty"`
59+
IgnoreSignatures bool `json:"ignoreSignatures,omitempty"`
60+
Transport http.RoundTripper `json:"-"`
6061
}
6162

6263
type Auth struct{ User, Pass string }

pkg/sbom/generator/generator.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@ import (
2121
"chainguard.dev/apko/pkg/sbom/options"
2222
)
2323

24+
// Generator defines the interface for SBOM generators.
2425
type Generator interface {
2526
Key() string
2627
Ext() string
2728
Generate(context.Context, *options.Options, string) error
2829
GenerateIndex(*options.Options, string) error
2930
}
3031

31-
// GeneratorFactory is a function that creates a new SBOM Generator.
32+
// GeneratorFactory is a function that creates a Generator.
3233
type GeneratorFactory func() Generator
3334

3435
var (
@@ -45,13 +46,25 @@ func RegisterGenerator(key string, factory GeneratorFactory) {
4546
registry[key] = factory
4647
}
4748

48-
func Generators() map[string]Generator {
49-
generators := map[string]Generator{}
49+
// Generators returns a map of registered generators.
50+
// If names are provided, only generators with those keys will be returned.
51+
func Generators(names ...string) []Generator {
52+
generators := []Generator{}
53+
54+
nameIdx := map[string]bool{}
55+
for _, n := range names {
56+
nameIdx[n] = true
57+
}
58+
// If no names are provided, return all generators.
59+
all := len(nameIdx) == 0
5060

5161
registryMu.RLock()
5262
defer registryMu.RUnlock()
63+
5364
for key, factory := range registry {
54-
generators[key] = factory()
65+
if all || nameIdx[key] {
66+
generators = append(generators, factory())
67+
}
5568
}
5669

5770
return generators

pkg/sbom/options/options.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,6 @@ type Options struct {
4848
// FileName is the base name for the sboms, the proper extension will get appended
4949
FileName string
5050

51-
// Formats dictates which SBOM formats we will output
52-
Formats []string
53-
5451
// Packages is a list of packages which will be listed in the SBOM
5552
Packages []*apk.InstalledPackage
5653
}

0 commit comments

Comments
 (0)