From 8f9e20068145c79c1517ef3c524a3e0a0440dbc4 Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani Date: Thu, 4 Apr 2024 19:39:53 +0000 Subject: [PATCH] fix: import a bom only if available from built layers It is possible that a build_only layer doesn't generate a BOM, so it cannot be imported in a derived layer. Signed-off-by: Ramkumar Chinchani --- pkg/stacker/bom.go | 7 ++++ test/bom.bats | 86 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/pkg/stacker/bom.go b/pkg/stacker/bom.go index f1633cb4..e048db8a 100644 --- a/pkg/stacker/bom.go +++ b/pkg/stacker/bom.go @@ -3,10 +3,12 @@ package stacker import ( "fmt" "io" + "io/fs" "os" "path" "path/filepath" + "github.com/pkg/errors" "stackerbuild.io/stacker/pkg/container" "stackerbuild.io/stacker/pkg/log" "stackerbuild.io/stacker/pkg/types" @@ -109,6 +111,11 @@ func ImportArtifacts(sc types.StackerConfig, src types.ImageSource, name string) // if a bom is available, add it here so it can be merged srcpath := path.Join(sc.StackerDir, "artifacts", src.Tag, fmt.Sprintf("%s.json", src.Tag)) + _, err := os.Lstat(srcpath) + if err != nil && errors.Is(err, fs.ErrNotExist) { + return nil + } + dstfp, err := os.CreateTemp(path.Join(sc.StackerDir, "artifacts", name), fmt.Sprintf("%s-*.json", name)) if err != nil { return err diff --git a/test/bom.bats b/test/bom.bats index f63b3d78..57307b58 100644 --- a/test/bom.bats +++ b/test/bom.bats @@ -365,3 +365,89 @@ EOF [ "$status" -ne 0 ] stacker clean } + +@test "skip bom generation for built layer" { + skip_slow_test + cat > stacker.yaml <<"EOF" +first: + from: + type: oci + url: ${{CENTOS_OCI}} + bom: + generate: true + namespace: "https://test.io/artifacts" + packages: + - name: pkg1 + version: 1.0.0 + license: Apache-2.0 + paths: [/pkg1] + - name: pkg2 + version: 1.0.0 + license: Apache-2.0 + paths: [/pkg2] + run: | + # our own custom packages + mkdir -p /pkg1 + touch /pkg1/file + mkdir -p /pkg2 + touch /pkg2/file + +second: + from: + type: built + tag: first + bom: + generate: true + namespace: "https://test.io/artifacts" + packages: + - name: pkg1 + version: 1.0.0 + license: Apache-2.0 + paths: [/pkg1] + - name: pkg2 + version: 1.0.0 + license: Apache-2.0 + paths: [/pkg2] + - name: pkg3 + version: 1.0.0 + license: Apache-2.0 + paths: [/pkg3] + run: | + # discover installed pkgs + /stacker/bin/stacker bom discover + # our own custom packages + mkdir -p /pkg3 + touch /pkg3/file + # cleanup + rm -rf /var/lib/alternatives /tmp/* \ + /etc/passwd- /etc/group- /etc/shadow- /etc/gshadow- \ + /etc/sysconfig/network /etc/nsswitch.conf.bak \ + /etc/rpm/macros.image-language-conf /var/lib/rpm/.dbenv.lock \ + /var/lib/rpm/Enhancename /var/lib/rpm/Filetriggername \ + /var/lib/rpm/Recommendname /var/lib/rpm/Suggestname \ + /var/lib/rpm/Supplementname /var/lib/rpm/Transfiletriggername \ + /var/log/anaconda \ + /etc/sysconfig/anaconda /etc/sysconfig/network-scripts/ifcfg-* \ + /etc/sysconfig/sshd-permitrootlogin /root/anaconda-* /root/original-* /run/nologin \ + /var/lib/rpm/.rpm.lock /etc/.pwd.lock /etc/BUILDTIME + annotations: + org.opencontainers.image.authors: bom-test + org.opencontainers.image.vendor: bom-test + org.opencontainers.image.licenses: MIT +EOF + stacker build --substitute CENTOS_OCI=${CENTOS_OCI} + # a full inventory for this image + [ -f .stacker/artifacts/second/inventory.json ] + # sbom for this image + [ -f .stacker/artifacts/second/second.json ] + if [ -n "${ZOT_HOST}:${ZOT_PORT}" ]; then + zot_setup + stacker publish --skip-tls --url docker://${ZOT_HOST}:${ZOT_PORT} --tag latest --substitute CENTOS_OCI=${CENTOS_OCI} + refs=$(regctl artifact tree ${ZOT_HOST}:${ZOT_PORT}/second:latest --format "{{json .}}" | jq '.referrer | length') + [ $refs -eq 2 ] + refs=$(regctl artifact get --subject ${ZOT_HOST}:${ZOT_PORT}/second:latest --filter-artifact-type "application/spdx+json" | jq '.SPDXID') + [ $refs == \"SPDXRef-DOCUMENT\" ] + zot_teardown + fi + stacker clean +}