Skip to content

Commit

Permalink
feat(ISV-5447): refactor SBOM data generation
Browse files Browse the repository at this point in the history
Signed-off-by: Martin Jediny <jedinym@proton.me>
  • Loading branch information
jedinym committed Dec 9, 2024
1 parent 0440c20 commit 230fd54
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 42 deletions.
8 changes: 0 additions & 8 deletions schema/dataKeys.json
Original file line number Diff line number Diff line change
Expand Up @@ -232,14 +232,6 @@
"type": "string",
"description": "The package URL representing the image e.g. pkg:example/openstack@sha256:abcde?repository_url=quay.io/example/rhosp16-rhel8"
},
"multiarch": {
"type": "boolean",
"description": "Indicates if the image is multi-arch."
},
"imageSha": {
"type": "string",
"description": "The SHA256 value of the image, without the 'sha256:' part e.g. 8ee2ac2e7572cd5053e1416c67f6bc314d349979f064615470ba84d103d96a8b"
},
"cves": {
"type": "object",
"properties": {
Expand Down
3 changes: 2 additions & 1 deletion tasks/populate-release-notes-images/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -11,7 +12,7 @@ in place so that downstream tasks relying on the releaseNotes data can use it.
| snapshotPath | Path to the JSON string of the mapped Snapshot in the data workspace | No | - |

## Changes in 2.2.4
* Add `multiarch` and `imageSha` fields to release notes images
* Export additional image data for component SBOM generation

## Changes in 2.2.3
* Rename `components` in the CVE struct to `packages`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -60,15 +68,15 @@ 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")
cveJson=$(jq -n \
--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;
Expand Down Expand Up @@ -98,20 +106,37 @@ spec:
jsonString=$(jq -cn \
--arg component "$name" \
--arg arch "$arch" \
--arg multiarch "$multiarch" \
--arg sha "$sha" \
--arg containerImage "$containerImage" \
--arg purl "$purl" \
--arg repository "$deliveryRepo" \
--argjson tags "$tags" \
'{"architecture": $arch, "multiarch": $multiarch, "imageSha": $sha,
"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
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,15 @@ spec:
runAfter:
- setup
- name: check-result
params:
- name: sbomDataPath
value: $(tasks.run-task.results.sbomDataPath)
workspaces:
- name: data
workspace: tests-workspace
taskSpec:
workspaces:
- name: data
params:
- name: sbomDataPath
steps:
- name: check-result
image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f
Expand All @@ -119,8 +122,12 @@ spec:
"pkg:oci/repo@sha256%3Aabcdefg?arch=amd64&repository_url=registry.redhat.io/product&tag=9.4.0-1723436855"
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 -rc '.multiarch' <<< "$image1arch1")" == "true"
test "$(jq -rc '.imageSha' <<< "$image1arch1")" == "123456"
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")
Expand All @@ -130,8 +137,12 @@ spec:
"pkg:oci/repo@sha256%3Adeadbeef?arch=s390x&repository_url=registry.redhat.io/product&tag=9.4.0-1723436855"
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 -rc '.multiarch' <<< "$image1arch2")" == "false"
test "$(jq -rc '.imageSha' <<< "$image1arch2")" == "123456"
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")
Expand All @@ -142,8 +153,12 @@ spec:
"pkg:oci/repo2@sha256%3Aabcdefg?arch=amd64&repository_url=registry.stage.redhat.io/product2"
test $(jq -r '.repository' <<< $image2arch1) == "registry.stage.redhat.io/product2/repo2"
test $(jq -rc '.tags' <<< $image2arch1) == '["foo","bar"]'
test "$(jq -rc '.multiarch' <<< "$image2arch1")" == "true"
test "$(jq -rc '.imageSha' <<< "$image2arch1")" == "abcde"
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")
Expand All @@ -154,7 +169,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 -rc '.multiarch' <<< "$image2arch2")" == "false"
test "$(jq -rc '.imageSha' <<< "$image2arch2")" == "abcde"
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
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -107,8 +112,6 @@ spec:
test $(jq -r '.repository' <<< $imagearch1) == "registry.redhat.io/product/repo"
test $(jq -rc '.tags' <<< $imagearch1) == '["foo","bar"]'
test "$(jq -rc '.component' <<< "$imagearch1")" == "comp"
test "$(jq -rc '.multiarch' <<< "$imagearch1")" == "true"
test "$(jq -rc '.imageSha' <<< "$imagearch1")" == "123456"
imagearch2=$(jq '.releaseNotes.content.images[1]' "$(workspaces.data.path)/data.json")
test $(jq -r '.architecture' <<< $imagearch2) == "s390x"
Expand All @@ -118,7 +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 "$(jq -rc '.multiarch' <<< "$imagearch2")" == "false"
test "$(jq -rc '.imageSha' <<< "$imagearch2")" == "123456"
# 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
7 changes: 5 additions & 2 deletions tasks/update-component-sbom/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ spec:
taskRef:
name: update-component-sbom
params:
- name: dataJsonPath
- name: sbomJsonPath
value: "data.json"
- name: downloadedSbomPath
value: downloaded-sboms
Expand Down
10 changes: 5 additions & 5 deletions tasks/update-component-sbom/update-component-sbom.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ 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
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: |
Expand All @@ -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
Expand All @@ -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"

0 comments on commit 230fd54

Please sign in to comment.