From 04b67bdcc9d77012c179e10239369997e847a200 Mon Sep 17 00:00:00 2001 From: Jon Johnson Date: Sat, 28 Oct 2023 16:00:34 -0700 Subject: [PATCH] Add .BUILD.apko.json to APK control section This generates the locked apko config for the guest container image that is used to build the APK and puts writes it as .BUILD.apko.json in the APK's control section. We could alternatively stick this in the (or another) SBOM, but that has triggered false positives with security scanners in the past. Signed-off-by: Jon Johnson --- pkg/build/build.go | 26 ++++++++++++++++++++++++++ pkg/build/package.go | 8 ++++++++ 2 files changed, 34 insertions(+) diff --git a/pkg/build/build.go b/pkg/build/build.go index 87a45978d..6057740b9 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -105,6 +105,8 @@ type Build struct { // mutated by Compile externalRefs []purl.PackageURL + + resolvedApkoConfig apko_types.ImageConfiguration } func New(ctx context.Context, opts ...Option) (*Build, error) { @@ -236,6 +238,26 @@ func (b *Build) Close(ctx context.Context) error { return errors.Join(errs...) } +func (b *Build) resolveConfig(ctx context.Context, bc *apko_build.Context) error { + ic := bc.ImageConfiguration() + pkgs, _, err := bc.BuildPackageList(ctx) + if err != nil { + return fmt.Errorf("resolving package versions: %w", err) + } + resolved := make([]string, 0, len(pkgs)) + for _, pkg := range pkgs { + resolved = append(resolved, fmt.Sprintf("%s=%s", pkg.Name, pkg.Version)) + } + ic.Contents.Packages = resolved + ic.Archs = []apko_types.Architecture{b.Arch} + ic.Contents.BuildRepositories = append(ic.Contents.BuildRepositories, b.ExtraRepos...) + ic.Contents.Keyring = append(ic.Contents.Keyring, b.ExtraKeys...) + + b.resolvedApkoConfig = ic + + return nil +} + // BuildGuest invokes apko to build the guest environment, returning a reference to the image // loaded by the OCI Image loader. func (b *Build) BuildGuest(ctx context.Context, imgConfig apko_types.ImageConfiguration, guestFS apkofs.FullFS) (string, error) { @@ -271,6 +293,10 @@ func (b *Build) BuildGuest(ctx context.Context, imgConfig apko_types.ImageConfig bc.Summarize(ctx) log.Infof("auth configured for: %s", maps.Keys(b.Auth)) // TODO: add this to Summarize + if err := b.resolveConfig(ctx, bc); err != nil { + return "", fmt.Errorf("locking apko config: %w", err) + } + // lay out the contents for the image in a directory. if err := bc.BuildImage(ctx); err != nil { return "", fmt.Errorf("unable to generate image: %w", err) diff --git a/pkg/build/package.go b/pkg/build/package.go index 1f793555c..cc571bc03 100644 --- a/pkg/build/package.go +++ b/pkg/build/package.go @@ -210,6 +210,14 @@ func (pc *PackageBuild) generateControlSection(ctx context.Context) ([]byte, err return nil, fmt.Errorf("unable to build control FS: %w", err) } + locked, err := json.Marshal(pc.Build.resolvedApkoConfig) + if err != nil { + return nil, fmt.Errorf("unable to marshal apko config: %w", err) + } + if err := fsys.WriteFile(".BUILD.apko.json", locked, 0644); err != nil { + return nil, fmt.Errorf("unable to write .apko.lock.json: %w", err) + } + if scriptlets := pc.Scriptlets; scriptlets != nil { if scriptlets.Trigger.Script != "" { // #nosec G306 -- scriptlets must be executable