From f6013eae7c2e74b19045dae43fe746cff8f00897 Mon Sep 17 00:00:00 2001 From: Wai Cheang Date: Tue, 3 Dec 2024 23:38:15 -0500 Subject: [PATCH] feat(ISV-5447): add multi-arch and sha info to release note images Signed-off-by: Wai Cheang feat(ISV-5447): refactor SBOM data generation Signed-off-by: Martin Jediny --- tasks/populate-release-notes-images/README.md | 4 ++ .../populate-release-notes-images.yaml | 48 +++++++++++++++---- .../tests/mocks.sh | 4 +- ...-release-notes-images-multiple-images.yaml | 29 +++++++++++ ...ate-release-notes-images-single-image.yaml | 12 +++++ tasks/update-component-sbom/README.md | 7 ++- .../test-update-component-sbom-basic.yaml | 2 +- .../update-component-sbom.yaml | 10 ++-- 8 files changed, 96 insertions(+), 20 deletions(-) diff --git a/tasks/populate-release-notes-images/README.md b/tasks/populate-release-notes-images/README.md index e6e366d0c..ff1b8c936 100644 --- a/tasks/populate-release-notes-images/README.md +++ b/tasks/populate-release-notes-images/README.md @@ -2,6 +2,7 @@ Tekton task to populate the releaseNotes.content.images key in the data.json file. It will update the data.json in place so that downstream tasks relying on the releaseNotes data can use it. +Additionally, it outputs a result with data used in component SBOM generation. ## Parameters @@ -10,6 +11,9 @@ in place so that downstream tasks relying on the releaseNotes data can use it. | dataPath | Path to the JSON string of the merged data to update | No | - | | snapshotPath | Path to the JSON string of the mapped Snapshot in the data workspace | No | - | +## Changes in 2.2.4 +* Export additional image data for component SBOM generation + ## Changes in 2.2.3 * Rename `components` in the CVE struct to `packages` diff --git a/tasks/populate-release-notes-images/populate-release-notes-images.yaml b/tasks/populate-release-notes-images/populate-release-notes-images.yaml index 789a3fcac..f7fe1ba1e 100644 --- a/tasks/populate-release-notes-images/populate-release-notes-images.yaml +++ b/tasks/populate-release-notes-images/populate-release-notes-images.yaml @@ -4,7 +4,7 @@ kind: Task metadata: name: populate-release-notes-images labels: - app.kubernetes.io/version: "2.2.3" + app.kubernetes.io/version: "2.2.4" annotations: tekton.dev/pipelines.minVersion: "0.12.1" tekton.dev/tags: release @@ -18,6 +18,9 @@ spec: - name: snapshotPath description: Path to the JSON string of the mapped Snapshot spec in the data workspace type: string + results: + - name: sbomDataPath + description: Path to data used in the component SBOM creation in the data workspace workspaces: - name: data description: The workspace where the data JSON file resides @@ -42,6 +45,11 @@ spec: UNIQUE_TAG_REGEX="(rhel-)?v?[0-9]+\.[0-9]+(\.[0-9]+)?-[0-9]{8,}" + # Initialize the SBOM data result + sbomDataPath="$(workspaces.data.path)/$(dirname "$(params.dataPath)")/sbom_data.json" + echo -n "$(dirname "$(params.dataPath)")/sbom_data.json" > "$(results.sbomDataPath.path)" + cp "${DATA_FILE}" "${sbomDataPath}" + NUM_COMPONENTS=$(jq '.components | length' "${SNAPSHOT_FILE}") for ((i = 0; i < $NUM_COMPONENTS; i++)) do @@ -60,7 +68,7 @@ spec: containerImage="${deliveryRepo}@sha256:${sha}" # Construct CVE json CVEsJson='{"cves":{"fixed":{}}}' - CVES=$(jq -c '[.releaseNotes.cves[]? | select(.component=="'$name'")]' ${DATA_FILE}) + CVES=$(jq -c '[.releaseNotes.cves[]? | select(.component=="'"$name"'")]' "${DATA_FILE}") NUM_CVES=$(jq 'length' <<< "$CVES") for ((j = 0; j < $NUM_CVES; j++)); do cve=$(jq -c --argjson j "$j" '.[$j]' <<< "$CVES") @@ -68,13 +76,14 @@ spec: --arg id "$(jq -r '.key' <<< "$cve")" \ --argjson packages "$(jq -c '.packages // []' <<< "$cve")" \ '{($id): {"packages": $packages}}') - CVEsJson=$(jq --argjson cve "$cveJson" '.cves.fixed += $cve' <<< $CVEsJson) + CVEsJson=$(jq --argjson cve "$cveJson" '.cves.fixed += $cve' <<< "$CVEsJson") done # Add one entry per arch (amd64 for example) get-image-architectures "${image}" | while IFS= read -r arch_json; do arch=$(jq -r .platform.architecture <<< "${arch_json}") digest=$(jq -r .digest <<< "${arch_json}") + multiarch=$(jq -r .multiarch <<< "${arch_json}") containerImage="${deliveryRepo}@${digest}" # purl should be pkg:oci/bar@sha256%3Aabcde?arch=amd64&repository_url=registry.redhat.io/foo purl="pkg:oci/${deliveryRepo##*/}@${digest/:/%3A}?arch=${arch}&repository_url=${deliveryRepo%/*}" @@ -101,14 +110,33 @@ spec: --arg purl "$purl" \ --arg repository "$deliveryRepo" \ --argjson tags "$tags" \ - '{"architecture": $arch, "containerImage":$containerImage, - "purl": $purl, "repository": $repository, "tags": $tags, - "component": $component}') - if [ $(jq '.cves.fixed | length' <<< $CVEsJson) -gt 0 ]; then - jsonString=$(jq --argjson cves "$CVEsJson" '. += $cves' <<< $jsonString) + '{"architecture": $arch, "containerImage": $containerImage, "purl": $purl, + "repository": $repository, "tags": $tags, "component": $component}') + if [ "$(jq '.cves.fixed | length' <<< "$CVEsJson")" -gt 0 ]; then + jsonString=$(jq --argjson cves "$CVEsJson" '. += $cves' <<< "$jsonString") fi + # Inject JSON into data.json - jq --argjson image "$jsonString" '.releaseNotes.content.images += [$image]' ${DATA_FILE} > \ - /tmp/data.tmp && mv /tmp/data.tmp ${DATA_FILE} + jq --argjson image "$jsonString" '.releaseNotes.content.images += [$image]' "${DATA_FILE}" > \ + /tmp/data.tmp && mv /tmp/data.tmp "${DATA_FILE}" + + # Inject SBOM-related data into the result + sbomJsonString=$(jq -cn \ + --arg component "$name" \ + --arg arch "$arch" \ + --arg containerImage "$containerImage" \ + --arg purl "$purl" \ + --arg repository "$deliveryRepo" \ + --arg multiarch "$multiarch" \ + --arg imageSha "$sha" \ + --argjson tags "$tags" \ + '{"architecture": $arch, "containerImage": $containerImage, "purl": $purl, + "multiarch": $multiarch, "imageSha": $imageSha, "repository": $repository, + "tags": $tags, "component": $component}') + + jq --argjson image "$sbomJsonString" \ + '.releaseNotes.content.images += [$image]' \ + "${sbomDataPath}" > \ + /tmp/sbomData.tmp && mv /tmp/sbomData.tmp "${sbomDataPath}" done done diff --git a/tasks/populate-release-notes-images/tests/mocks.sh b/tasks/populate-release-notes-images/tests/mocks.sh index 38739f665..62103e4ac 100644 --- a/tasks/populate-release-notes-images/tests/mocks.sh +++ b/tasks/populate-release-notes-images/tests/mocks.sh @@ -4,6 +4,6 @@ set -eux # mocks to be injected into task step scripts function get-image-architectures() { - echo '{"platform":{"architecture": "amd64", "os": "linux"}, "digest": "sha256:abcdefg"}' - echo '{"platform":{"architecture": "s390x", "os": "linux"}, "digest": "sha256:deadbeef"}' + echo '{"platform":{"architecture": "amd64", "os": "linux"}, "digest": "sha256:abcdefg", "multiarch": true}' + echo '{"platform":{"architecture": "s390x", "os": "linux"}, "digest": "sha256:deadbeef", "multiarch": false}' } diff --git a/tasks/populate-release-notes-images/tests/test-populate-release-notes-images-multiple-images.yaml b/tasks/populate-release-notes-images/tests/test-populate-release-notes-images-multiple-images.yaml index 57b6e9999..7d589f7bc 100644 --- a/tasks/populate-release-notes-images/tests/test-populate-release-notes-images-multiple-images.yaml +++ b/tasks/populate-release-notes-images/tests/test-populate-release-notes-images-multiple-images.yaml @@ -98,10 +98,15 @@ spec: runAfter: - setup - name: check-result + params: + - name: sbomDataPath + value: $(tasks.run-task.results.sbomDataPath) workspaces: - name: data workspace: tests-workspace taskSpec: + params: + - name: sbomDataPath workspaces: - name: data steps: @@ -120,6 +125,12 @@ spec: test $(jq -r '.repository' <<< $image1arch1) == "registry.redhat.io/product/repo" test "$(jq -rc '.tags' <<< "$image1arch1")" == '["9.4-1723436855","9.4.0-1723436855","foo","bar"]' + test "$(jq -r '.releaseNotes.content.images[0].multiarch' \ + "$(workspaces.data.path)/$(params.sbomDataPath)")" == "true" + + test "$(jq -r '.releaseNotes.content.images[0].imageSha' \ + "$(workspaces.data.path)/$(params.sbomDataPath)")" == "123456" + echo Checking image1arch2... image1arch2=$(jq '.releaseNotes.content.images[1]' "$(workspaces.data.path)/data.json") test $(jq -r '.architecture' <<< $image1arch2) == "s390x" @@ -129,6 +140,12 @@ spec: test $(jq -r '.repository' <<< $image1arch2) == "registry.redhat.io/product/repo" test "$(jq -rc '.tags' <<< "$image1arch2")" == '["9.4-1723436855","9.4.0-1723436855","foo","bar"]' + test "$(jq -r '.releaseNotes.content.images[1].multiarch' \ + "$(workspaces.data.path)/$(params.sbomDataPath)")" == "false" + + test "$(jq -r '.releaseNotes.content.images[1].imageSha' \ + "$(workspaces.data.path)/$(params.sbomDataPath)")" == "123456" + echo Checking image2arch1... image2arch1=$(jq '.releaseNotes.content.images[2]' "$(workspaces.data.path)/data.json") test $(jq -r '.architecture' <<< $image2arch1) == "amd64" @@ -139,6 +156,12 @@ spec: test $(jq -r '.repository' <<< $image2arch1) == "registry.stage.redhat.io/product2/repo2" test $(jq -rc '.tags' <<< $image2arch1) == '["foo","bar"]' + test "$(jq -r '.releaseNotes.content.images[2].multiarch' \ + "$(workspaces.data.path)/$(params.sbomDataPath)")" == "true" + + test "$(jq -r '.releaseNotes.content.images[2].imageSha' \ + "$(workspaces.data.path)/$(params.sbomDataPath)")" == "abcde" + echo Checking image2arch2... image2arch2=$(jq '.releaseNotes.content.images[3]' "$(workspaces.data.path)/data.json") test $(jq -r '.architecture' <<< $image2arch2) == "s390x" @@ -148,5 +171,11 @@ spec: "pkg:oci/repo2@sha256%3Adeadbeef?arch=s390x&repository_url=registry.stage.redhat.io/product2" test $(jq -r '.repository' <<< $image2arch2) == "registry.stage.redhat.io/product2/repo2" test $(jq -rc '.tags' <<< $image2arch2) == '["foo","bar"]' + + test "$(jq -r '.releaseNotes.content.images[3].multiarch' \ + "$(workspaces.data.path)/$(params.sbomDataPath)")" == "false" + + test "$(jq -r '.releaseNotes.content.images[3].imageSha' \ + "$(workspaces.data.path)/$(params.sbomDataPath)")" == "abcde" runAfter: - run-task diff --git a/tasks/populate-release-notes-images/tests/test-populate-release-notes-images-single-image.yaml b/tasks/populate-release-notes-images/tests/test-populate-release-notes-images-single-image.yaml index c673e0779..2b6c8d1df 100644 --- a/tasks/populate-release-notes-images/tests/test-populate-release-notes-images-single-image.yaml +++ b/tasks/populate-release-notes-images/tests/test-populate-release-notes-images-single-image.yaml @@ -86,10 +86,15 @@ spec: runAfter: - setup - name: check-result + params: + - name: sbomDataPath + value: $(tasks.run-task.results.sbomDataPath) workspaces: - name: data workspace: tests-workspace taskSpec: + params: + - name: sbomDataPath workspaces: - name: data steps: @@ -116,5 +121,12 @@ spec: test $(jq -r '.repository' <<< $imagearch2) == "registry.redhat.io/product/repo" test $(jq -rc '.tags' <<< $imagearch2) == '["foo","bar"]' test "$(jq -rc '.component' <<< "$imagearch2")" == "comp" + + # Test SBOM injection + test "$(jq -r '.releaseNotes.content.images[0].multiarch' \ + "$(workspaces.data.path)/$(params.sbomDataPath)")" == "true" + + test "$(jq -r '.releaseNotes.content.images[0].imageSha' \ + "$(workspaces.data.path)/$(params.sbomDataPath)")" == "123456" runAfter: - run-task diff --git a/tasks/update-component-sbom/README.md b/tasks/update-component-sbom/README.md index 9ef82afe2..de2d25692 100644 --- a/tasks/update-component-sbom/README.md +++ b/tasks/update-component-sbom/README.md @@ -5,9 +5,12 @@ Tekton task to update component-level SBOMs with purls containing release-time i ## Parameters | Name | Description | Optional | Default value | -| ------------------ | ------------------------------------------------------------------------ | -------- | ------------- | -| dataJsonPath | Path to the JSON string of the merged data containing the release notes | No | - | +|--------------------|--------------------------------------------------------------------------|----------|---------------| +| sbomJsonPath | Path to the JSON string of the merged data containing the release notes | No | - | | downloadedSbomPath | Path to the directory holding previously downloaded SBOMs to be updated. | No | - | +## Changes in 0.2.0 +- Rename dataPath parameter to sbomJsonPath to better reflect usage + ## Changes in 0.1.1 - (ISV-5321) Set a `name` of SPDX document to external reference of the component. The name is set to external image pullspec given by the public registry + repository + digest. Example: registry.redhat.io/ubi8/ubi-minimal@sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef. diff --git a/tasks/update-component-sbom/tests/test-update-component-sbom-basic.yaml b/tasks/update-component-sbom/tests/test-update-component-sbom-basic.yaml index a21340053..47cb7b4d2 100644 --- a/tasks/update-component-sbom/tests/test-update-component-sbom-basic.yaml +++ b/tasks/update-component-sbom/tests/test-update-component-sbom-basic.yaml @@ -16,7 +16,7 @@ spec: taskRef: name: update-component-sbom params: - - name: dataJsonPath + - name: sbomJsonPath value: "data.json" - name: downloadedSbomPath value: downloaded-sboms diff --git a/tasks/update-component-sbom/update-component-sbom.yaml b/tasks/update-component-sbom/update-component-sbom.yaml index b4a87ab1d..e295bda8c 100644 --- a/tasks/update-component-sbom/update-component-sbom.yaml +++ b/tasks/update-component-sbom/update-component-sbom.yaml @@ -4,7 +4,7 @@ kind: Task metadata: name: update-component-sbom labels: - app.kubernetes.io/version: "0.1.1" + app.kubernetes.io/version: "0.2.0" annotations: tekton.dev/pipelines.minVersion: "0.12.1" tekton.dev/tags: release @@ -12,8 +12,8 @@ spec: description: >- Update component-level SBOM with purls with release-time info. params: - - name: dataJsonPath - description: Relative path to the JSON data file in the workspace. + - name: sbomJsonPath + description: Relative path to the SBOM data file in the workspace. type: string - name: downloadedSbomPath description: | @@ -24,7 +24,7 @@ spec: description: The workspace where the SBOM files reside. steps: - name: update-component-sbom-purls - image: quay.io/konflux-ci/release-service-utils:e15023773e138c7d3449f288c8c16de4e3a8d249 + image: quay.io/konflux-ci/release-service-utils:3e107dfec5342ef61ae89337458d26c6efe97938 script: | #!/usr/bin/env bash set -eux @@ -33,6 +33,6 @@ spec: #update the SBOM files in place update_component_sbom \ - --data-path "$(workspaces.data.path)/$(params.dataJsonPath)" \ + --data-path "$(workspaces.data.path)/$(params.sbomJsonPath)" \ --input-path "$INPUT_PATH" \ --output-path "$INPUT_PATH"