Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 45 additions & 3 deletions .github/workflows/sbomify.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,13 @@ jobs:
uses: actions/checkout@v4

- name: Generate additional packages from Dockerfile
run: ./scripts/generate_additional_packages.sh > additional_packages.txt
run: ./scripts/generate_additional_packages.sh > container_additional_packages.txt

- name: Determine version
id: version
run: |
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
echo "short_sha=${SHORT_SHA}" >> $GITHUB_OUTPUT

- name: Upload SBOM to Staging
if: github.ref == 'refs/heads/master'
Expand All @@ -227,12 +233,28 @@ jobs:
COMPONENT_ID: 'XNsX40tonzvv'
LOCK_FILE: 'uv.lock'
COMPONENT_NAME: 'sbomify Action'
COMPONENT_VERSION: ${{ format('{0}-{1}', github.ref_name, github.sha) }}
COMPONENT_VERSION: ${{ steps.version.outputs.short_sha }}
AUGMENT: true
ENRICH: true
UPLOAD: true
OUTPUT_FILE: github-action.cdx.json

- name: Upload Container SBOM to Staging
if: github.ref == 'refs/heads/master'
uses: sbomify/github-action@master
env:
TOKEN: ${{ secrets.SBOMIFY_STAGE_TOKEN }}
API_BASE_URL: https://stage.sbomify.com
COMPONENT_ID: 'gco2pG10whmy'
DOCKER_IMAGE: 'sbomifyhub/sbomify-action:latest'
COMPONENT_NAME: 'sbomify Action Container'
COMPONENT_VERSION: ${{ steps.version.outputs.short_sha }}
ADDITIONAL_PACKAGES_FILE: container_additional_packages.txt
AUGMENT: true
ENRICH: true
UPLOAD: true
OUTPUT_FILE: github-action-container.cdx.json

- name: Upload SBOM to Production
if: startsWith(github.ref, 'refs/tags/')
uses: sbomify/github-action@master
Expand All @@ -247,7 +269,27 @@ jobs:
UPLOAD: true
OUTPUT_FILE: github-action.cdx.json

- name: Attest
- name: Upload Container SBOM to Production
if: startsWith(github.ref, 'refs/tags/')
uses: sbomify/github-action@master
env:
TOKEN: ${{ secrets.SBOMIFY_TOKEN }}
COMPONENT_ID: 'ryD0Hcu4vq6y'
DOCKER_IMAGE: 'sbomifyhub/sbomify-action:${{ github.ref_name }}'
COMPONENT_NAME: 'sbomify Action Container'
COMPONENT_VERSION: ${{ github.ref_name }}
ADDITIONAL_PACKAGES_FILE: container_additional_packages.txt
AUGMENT: true
ENRICH: true
UPLOAD: true
OUTPUT_FILE: github-action-container.cdx.json

- name: Attest Source SBOM
uses: actions/attest-build-provenance@v1
with:
subject-path: '${{ github.workspace }}/github-action.cdx.json'

- name: Attest Container SBOM
uses: actions/attest-build-provenance@v1
with:
subject-path: '${{ github.workspace }}/github-action-container.cdx.json'
40 changes: 35 additions & 5 deletions sbomify_action/augmentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from pathlib import Path
from typing import Any, Dict, List, Literal, Optional, Tuple

from cyclonedx.model import AttachedText, ExternalReference, ExternalReferenceType, XsUri
from cyclonedx.model import AttachedText, BomRef, ExternalReference, ExternalReferenceType, XsUri
from cyclonedx.model.bom import Bom, OrganizationalContact, OrganizationalEntity, Tool
from cyclonedx.model.component import Component, ComponentType
from cyclonedx.model.license import DisjunctiveLicense, LicenseExpression
Expand Down Expand Up @@ -106,15 +106,15 @@ def _propagate_supplier_to_lockfile_components(bom: Bom) -> None:

def _update_component_purl_version(component: Component, new_version: str) -> bool:
"""
Update the version in a CycloneDX component's PURL if present.
Update the version in a CycloneDX component's PURL and bom-ref if present.

When COMPONENT_VERSION is set to override the component version, this function
ensures the PURL is also updated to maintain consistency between the component's
version field and its PURL.
ensures the PURL and bom-ref are also updated to maintain consistency between
the component's version field, PURL, and bom-ref.

Args:
component: The CycloneDX Component object with optional purl attribute
new_version: The new version to set in the PURL
new_version: The new version to set in the PURL and bom-ref

Returns:
True if PURL was updated, False if component has no PURL or update failed
Expand All @@ -124,6 +124,14 @@ def _update_component_purl_version(component: Component, new_version: str) -> bo

try:
old_purl = component.purl

# Guard against PURLs without version (e.g., pkg:npm/lodash)
if old_purl.version is None:
logger.debug(f"Skipping PURL version update - no existing version: {old_purl}")
return False

old_version = old_purl.version

# Create new PURL with updated version, preserving all other fields
new_purl = PackageURL(
type=old_purl.type,
Expand All @@ -135,6 +143,28 @@ def _update_component_purl_version(component: Component, new_version: str) -> bo
)
component.purl = new_purl
logger.debug(f"Updated component PURL version: {old_purl} -> {new_purl}")

# Also update bom-ref if it is a PURL-based bom-ref with a matching version
if component.bom_ref and component.bom_ref.value:
old_bom_ref = component.bom_ref.value
try:
bom_ref_purl = PackageURL.from_string(old_bom_ref)
except ValueError:
bom_ref_purl = None

if bom_ref_purl and bom_ref_purl.version == old_version:
new_bom_ref_purl = PackageURL(
type=bom_ref_purl.type,
namespace=bom_ref_purl.namespace,
name=bom_ref_purl.name,
version=new_version,
qualifiers=bom_ref_purl.qualifiers,
subpath=bom_ref_purl.subpath,
)
new_bom_ref = str(new_bom_ref_purl)
component.bom_ref = BomRef(new_bom_ref)
logger.debug(f"Updated component bom-ref: {old_bom_ref} -> {new_bom_ref}")

return True
except Exception as e:
logger.warning(f"Failed to update component PURL version: {e}")
Expand Down