ibcli: add new --extra-artifacts option with sbom support

This commit adds an option --extra-artifacts that can be
used to generate extra artifacts during the build or manifest
generation. Initially supported is `sbom` (but `manifest` is
planned too).

To use it run `--extra-artifacts=sbom` and it will generate
files like `centos-9-qcow2-x86_64.image-os.spdx.json` in
the output directory next to the generate runable artifact.

Closes: https://github.com/osbuild/image-builder-cli/issues/46
This commit is contained in:
Michael Vogt 2025-01-16 13:58:35 +01:00 committed by Simon de Vlieger
parent db7cad2239
commit d485bc3a44
6 changed files with 178 additions and 17 deletions

View file

@ -1,9 +1,6 @@
package main
import (
"fmt"
"path/filepath"
"github.com/osbuild/images/pkg/imagefilter"
"github.com/osbuild/images/pkg/osbuild"
)
@ -12,9 +9,7 @@ func buildImage(res *imagefilter.Result, osbuildManifest []byte, osbuildStoreDir
// XXX: support output dir via commandline
// XXX2: support output filename via commandline (c.f.
// https://github.com/osbuild/images/pull/1039)
outputDir := "."
buildName := fmt.Sprintf("%s-%s-%s", res.Distro.Name(), res.ImgType.Name(), res.Arch.Name())
jobOutputDir := filepath.Join(outputDir, buildName)
jobOutputDir := outputDirFor(res)
// XXX: support stremaing via images/pkg/osbuild/monitor.go
_, err := osbuild.RunOSBuild(osbuildManifest, osbuildStoreDir, jobOutputDir, res.ImgType.Exports(), nil, nil, false, osStderr)

View file

@ -22,6 +22,11 @@ var (
osStderr io.Writer = os.Stderr
)
// generate the default output directory name for the given image
func outputDirFor(img *imagefilter.Result) string {
return fmt.Sprintf("%s-%s-%s", img.Distro.Name(), img.ImgType.Name(), img.Arch.Name())
}
func cmdListImages(cmd *cobra.Command, args []string) error {
filter, err := cmd.Flags().GetStringArray("filter")
if err != nil {
@ -80,6 +85,10 @@ func cmdManifestWrapper(cmd *cobra.Command, args []string, w io.Writer, archChec
if err != nil {
return nil, err
}
extraArtifacts, err := cmd.Flags().GetStringArray("extra-artifacts")
if err != nil {
return nil, err
}
ostreeImgOpts, err := ostreeImageOptions(cmd)
if err != nil {
return nil, err
@ -121,9 +130,10 @@ func cmdManifestWrapper(cmd *cobra.Command, args []string, w io.Writer, archChec
}
opts := &manifestOptions{
BlueprintPath: blueprintPath,
Ostree: ostreeImgOpts,
RpmDownloader: rpmDownloader,
BlueprintPath: blueprintPath,
Ostree: ostreeImgOpts,
RpmDownloader: rpmDownloader,
ExtraArtifacts: extraArtifacts,
}
err = generateManifest(dataDir, img, w, opts)
return img, err
@ -171,6 +181,7 @@ operating sytsems like centos and RHEL with easy customizations support.`,
SilenceErrors: true,
}
rootCmd.PersistentFlags().String("datadir", "", `Override the default data direcotry for e.g. custom repositories/*.json data`)
rootCmd.PersistentFlags().StringArray("extra-artifacts", nil, `Export extra artifacts to the output dir (e.g. "sbom")`)
rootCmd.SetOut(osStdout)
rootCmd.SetErr(osStderr)

View file

@ -2,6 +2,9 @@ package main
import (
"io"
"os"
"path/filepath"
"slices"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/imagefilter"
@ -13,9 +16,23 @@ import (
)
type manifestOptions struct {
BlueprintPath string
Ostree *ostree.ImageOptions
RpmDownloader osbuild.RpmDownloader
BlueprintPath string
Ostree *ostree.ImageOptions
RpmDownloader osbuild.RpmDownloader
ExtraArtifacts []string
}
func sbomWriter(outputDir, filename string, content io.Reader) error {
p := filepath.Join(outputDir, filename)
f, err := os.Create(p)
if err != nil {
return err
}
defer f.Close()
if _, err := io.Copy(f, content); err != nil {
return err
}
return nil
}
func generateManifest(dataDir string, img *imagefilter.Result, output io.Writer, opts *manifestOptions) error {
@ -24,13 +41,25 @@ func generateManifest(dataDir string, img *imagefilter.Result, output io.Writer,
return err
}
// XXX: add --rpmmd/cachedir option like bib
mg, err := manifestgen.New(repos, &manifestgen.Options{
manifestGenOpts := &manifestgen.Options{
Output: output,
RpmDownloader: opts.RpmDownloader,
})
}
if slices.Contains(opts.ExtraArtifacts, "sbom") {
outputDir := outputDirFor(img)
if err := os.MkdirAll(outputDir, 0755); err != nil {
return err
}
manifestGenOpts.SBOMWriter = func(filename string, content io.Reader) error {
return sbomWriter(outputDir, filename, content)
}
}
mg, err := manifestgen.New(repos, manifestGenOpts)
if err != nil {
return err
}
bp, err := blueprintload.Load(opts.BlueprintPath)
if err != nil {
return err