From e8982d18e809b2e28fc1a6749d5f66f20ad63264 Mon Sep 17 00:00:00 2001 From: Daniel Kreling Date: Fri, 3 Jul 2026 16:37:52 -0300 Subject: [PATCH] konflux: generate SBOM using syft and mobster Replace the empty SBOM placeholder with a proper SPDX 2.3 SBOM generated by syft and mobster, matching the approach used by osc-caa and other OSC components and aligned with the buildah-remote-oci-ta task in konflux-ci/build-definitions. The RPM database and /usr/lib/os-release are extracted from the QCOW2 guest image via virt-copy-out and transferred back to the Tekton pod. Syft scans the RPM database to produce a complete package inventory with PURLs, CPEs, and licenses. Mobster wraps the syft output with OCI image metadata and a reference to the osc-podvm-payload base image. Also updates the mobster image from v0.6.0 to v1.2.1 to match the version used by buildah-remote-oci-ta. Ref: KATA-5098 Signed-off-by: Daniel Kreling Co-Authored-By: Claude Opus 4.6 --- .tekton/build-dm-verity-image-debug.yaml | 63 +++++++++++++++---- task/README.md | 10 +-- .../0.1/build-dm-verity-image.yaml | 63 +++++++++++++++---- 3 files changed, 106 insertions(+), 30 deletions(-) diff --git a/.tekton/build-dm-verity-image-debug.yaml b/.tekton/build-dm-verity-image-debug.yaml index 5f5db98e..96e3661f 100644 --- a/.tekton/build-dm-verity-image-debug.yaml +++ b/.tekton/build-dm-verity-image-debug.yaml @@ -175,6 +175,9 @@ spec: -v $BUILD_DIR/activation-key/:/activation-key/:Z \ -t builder -f $BUILD_DIR/source/konflux/Dockerfile $BUILD_DIR/source + # Extract osc-podvm-payload digest from Dockerfile for SBOM + grep 'osc-podvm-payload@sha256:' $BUILD_DIR/source/konflux/Dockerfile | head -1 | grep -o 'sha256:[a-f0-9]*' > output/payload-digest.txt || true + time sudo podman run -d --authfile=$BUILD_DIR/.docker/config.json --rm -it --privileged --pull=newer \ -v ${BUILD_DIR}:/workspace \ -v $(pwd)/output:/output \ @@ -221,6 +224,10 @@ spec: "$BUILDAH_IMAGE" \ /script-push.sh $DISK $MEASUREMENTS + # Copy SBOM data to BUILD_DIR for transfer back to Tekton pod + cp -r output/rootfs $BUILD_DIR/ 2>/dev/null || true + cp output/payload-digest.txt $BUILD_DIR/ 2>/dev/null || true + REMOTESSHEOF cat >>scripts/script-disk-mods.sh <>scripts/podvm-setup.sh <<'REMOTESSHEOF' @@ -652,33 +666,56 @@ spec: ssh -v $SSH_ARGS "$SSH_HOST" $BUILD_DIR/scripts/script-build.sh rsync -ra "$SSH_HOST:$BUILD_DIR/tekton-results/*" "/tekton/results/" + + # Retrieve SBOM data from remote host + rsync -ra "$SSH_HOST:$BUILD_DIR/rootfs/" "/var/workdir/rootfs/" 2>/dev/null || true + rsync "$SSH_HOST:$BUILD_DIR/payload-digest.txt" "/var/workdir/" 2>/dev/null || true volumeMounts: - mountPath: /ssh name: ssh readOnly: true - mountPath: /activation-key name: activation-key + - name: sbom-syft-generate + image: ghcr.io/anchore/syft:latest@sha256:484dc49cd5869780d8a8e1b2fa2d9381cc1388fc32caeb69e8be81e3ae08bbb1 + command: + - /syft + args: + - scan + - dir:/var/workdir/rootfs + - -o + - spdx-json=/var/workdir/syft-sbom.json + volumeMounts: + - mountPath: /var/workdir + name: workdir - name: sbom-generate - image: quay.io/konflux-ci/mobster@sha256:45298b363ff4b96a084bf77a627b3e23471dcfb821eab55a3fa49a60f0ac43f3 + image: quay.io/konflux-ci/mobster@sha256:1374bc35c71781987cce00ef5efe2be42923f83def19b60a570e947189b90d15 script: | #!/bin/bash set -euo pipefail - OCI_COPY_FILE_PATH=empty-oci-copy.yaml - - # This generates an empty SBOM. Fix this in the future to generate one with real contents - echo "artifacts: []" > $OCI_COPY_FILE_PATH - IMAGE_URL=$(cat "$(results.IMAGE_URL.path)") IMAGE_DIGEST=$(cat "$(results.IMAGE_DIGEST.path)") - mobster generate \ - --output /var/workdir/sbom.json \ - oci-artifact \ - --oci-copy-yaml "$OCI_COPY_FILE_PATH" \ - --image-pullspec "$IMAGE_URL" \ - --image-digest "$IMAGE_DIGEST" \ - --sbom-type "$SBOM_TYPE" + SYFT_SBOM="/var/workdir/syft-sbom.json" + SBOM_FILE="/var/workdir/sbom.json" + PAYLOAD_DIGEST_FILE="/var/workdir/payload-digest.txt" + + MOBSTER_ARGS=( + generate --output "$SBOM_FILE" oci-image + --from-syft "$SYFT_SBOM" + --image-pullspec "$IMAGE_URL" + --image-digest "$IMAGE_DIGEST" + ) + + if [ -f "$PAYLOAD_DIGEST_FILE" ]; then + PAYLOAD_DIGEST=$(tr -d '[:space:]' < "$PAYLOAD_DIGEST_FILE") + if [ -n "$PAYLOAD_DIGEST" ]; then + MOBSTER_ARGS+=(--additional-base-image "quay.io/redhat-user-workloads/ose-osc-tenant/osc-podvm-payload:latest@${PAYLOAD_DIGEST}") + fi + fi + + mobster "${MOBSTER_ARGS[@]}" - name: upload-sbom image: quay.io/konflux-ci/appstudio-utils:1610c1fc4cfc9c9053dbefc1146904a4df6659ef@sha256:90ac97b811073cb99a23232c15a08082b586c702b85da6200cf54ef505e3c50c diff --git a/task/README.md b/task/README.md index d6000baf..1c2c3af7 100644 --- a/task/README.md +++ b/task/README.md @@ -31,7 +31,7 @@ At a high level, the task is doing the following: and verify checksum. 2. Copy sources and required files to the remote SSH build host and run a script remotely to build the QCOW image. -3. Generate a minimal SBOM for the published image. +3. Generate an SBOM for the published image. Additional steps and code exist in the task to share context with the other tasks in our CI (running before or after it). We won't detail them in this document. @@ -102,10 +102,12 @@ them to build our image. Uses Buildah to package the QCOW2 file into a container image and pushes it to the registry. -### step "sbom-generate" +### steps "sbom-syft-generate" and "sbom-generate" -This step is required for Konflux CI, but we are currently doing a very simple -(empty) SBOM. We need to improve this. +These steps generate an SPDX 2.3 SBOM for the published image. First, syft scans +the RPM database extracted from the QCOW2 guest image to produce an SBOM listing +all installed RPM packages. Then, mobster wraps the syft output with the OCI image +metadata and a reference to the `osc-podvm-payload` container (by digest). ## Build and publish the task diff --git a/task/build-dm-verity-image/0.1/build-dm-verity-image.yaml b/task/build-dm-verity-image/0.1/build-dm-verity-image.yaml index cfa0b728..c76bb708 100644 --- a/task/build-dm-verity-image/0.1/build-dm-verity-image.yaml +++ b/task/build-dm-verity-image/0.1/build-dm-verity-image.yaml @@ -175,6 +175,9 @@ spec: -v $BUILD_DIR/activation-key/:/activation-key/:Z \ -t builder -f $BUILD_DIR/source/konflux/Dockerfile $BUILD_DIR/source + # Extract osc-podvm-payload digest from Dockerfile for SBOM + grep 'osc-podvm-payload@sha256:' $BUILD_DIR/source/konflux/Dockerfile | head -1 | grep -o 'sha256:[a-f0-9]*' > output/payload-digest.txt || true + time sudo podman run -d --authfile=$BUILD_DIR/.docker/config.json --rm -it --privileged --pull=newer \ -v ${BUILD_DIR}:/workspace \ -v $(pwd)/output:/output \ @@ -221,6 +224,10 @@ spec: "$BUILDAH_IMAGE" \ /script-push.sh $DISK $MEASUREMENTS + # Copy SBOM data to BUILD_DIR for transfer back to Tekton pod + cp -r output/rootfs $BUILD_DIR/ 2>/dev/null || true + cp output/payload-digest.txt $BUILD_DIR/ 2>/dev/null || true + REMOTESSHEOF cat >>scripts/script-disk-mods.sh <>scripts/podvm-setup.sh <<'REMOTESSHEOF' @@ -652,33 +666,56 @@ spec: ssh -v $SSH_ARGS "$SSH_HOST" $BUILD_DIR/scripts/script-build.sh rsync -ra "$SSH_HOST:$BUILD_DIR/tekton-results/*" "/tekton/results/" + + # Retrieve SBOM data from remote host + rsync -ra "$SSH_HOST:$BUILD_DIR/rootfs/" "/var/workdir/rootfs/" 2>/dev/null || true + rsync "$SSH_HOST:$BUILD_DIR/payload-digest.txt" "/var/workdir/" 2>/dev/null || true volumeMounts: - mountPath: /ssh name: ssh readOnly: true - mountPath: /activation-key name: activation-key + - name: sbom-syft-generate + image: ghcr.io/anchore/syft:latest@sha256:484dc49cd5869780d8a8e1b2fa2d9381cc1388fc32caeb69e8be81e3ae08bbb1 + command: + - /syft + args: + - scan + - dir:/var/workdir/rootfs + - -o + - spdx-json=/var/workdir/syft-sbom.json + volumeMounts: + - mountPath: /var/workdir + name: workdir - name: sbom-generate - image: quay.io/konflux-ci/mobster@sha256:45298b363ff4b96a084bf77a627b3e23471dcfb821eab55a3fa49a60f0ac43f3 + image: quay.io/konflux-ci/mobster@sha256:1374bc35c71781987cce00ef5efe2be42923f83def19b60a570e947189b90d15 script: | #!/bin/bash set -euo pipefail - OCI_COPY_FILE_PATH=empty-oci-copy.yaml - - # This generates an empty SBOM. Fix this in the future to generate one with real contents - echo "artifacts: []" > $OCI_COPY_FILE_PATH - IMAGE_URL=$(cat "$(results.IMAGE_URL.path)") IMAGE_DIGEST=$(cat "$(results.IMAGE_DIGEST.path)") - mobster generate \ - --output /var/workdir/sbom.json \ - oci-artifact \ - --oci-copy-yaml "$OCI_COPY_FILE_PATH" \ - --image-pullspec "$IMAGE_URL" \ - --image-digest "$IMAGE_DIGEST" \ - --sbom-type "$SBOM_TYPE" + SYFT_SBOM="/var/workdir/syft-sbom.json" + SBOM_FILE="/var/workdir/sbom.json" + PAYLOAD_DIGEST_FILE="/var/workdir/payload-digest.txt" + + MOBSTER_ARGS=( + generate --output "$SBOM_FILE" oci-image + --from-syft "$SYFT_SBOM" + --image-pullspec "$IMAGE_URL" + --image-digest "$IMAGE_DIGEST" + ) + + if [ -f "$PAYLOAD_DIGEST_FILE" ]; then + PAYLOAD_DIGEST=$(tr -d '[:space:]' < "$PAYLOAD_DIGEST_FILE") + if [ -n "$PAYLOAD_DIGEST" ]; then + MOBSTER_ARGS+=(--additional-base-image "quay.io/redhat-user-workloads/ose-osc-tenant/osc-podvm-payload:latest@${PAYLOAD_DIGEST}") + fi + fi + + mobster "${MOBSTER_ARGS[@]}" - name: upload-sbom image: quay.io/konflux-ci/appstudio-utils:1610c1fc4cfc9c9053dbefc1146904a4df6659ef@sha256:90ac97b811073cb99a23232c15a08082b586c702b85da6200cf54ef505e3c50c