Skip to content

SBOM — Software Bill of Materials (Syft)

A Software Bill of Materials is a complete, machine-readable inventory of every dependency in a container image or build artefact. Microtec generates CycloneDX SBOMs using Syft as part of every container build pipeline.


Why SBOM Matters

Why We Generate SBOMs

  • Supply chain transparency — Know exactly which open-source packages ship inside every image.
  • Vulnerability triage — When a CVE drops, query the SBOM to identify which services are affected without rescanning all images.
  • Compliance — Executive Order 14028 (US) and EU Cyber Resilience Act both mandate machine-readable SBOMs for software suppliers.
  • Audit trail — Every production release has a signed SBOM attached as a pipeline artefact, giving auditors a verifiable record.

Tool: Syft

PropertyValue
ToolSyft by Anchore
SBOM FormatCycloneDX 1.4 (JSON)
Pipeline stageStage 9 — SBOM Generation (runs after Trivy image scan)
Artefact namesbom-<service>-<buildId>.cdx.json
Retention90 days in Azure Pipelines

Pipeline Integration

yaml
- stage: SBOM
  displayName: 'Stage 9 - SBOM Generation (Syft)'
  dependsOn: TrivyScan
  condition: succeeded()
  jobs:
    - job: GenerateSBOM
      pool:
        vmImage: 'ubuntu-latest'
      steps:
        - task: Bash@3
          displayName: 'Install Syft'
          inputs:
            targetType: inline
            script: |
              curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh \
                | sh -s -- -b /usr/local/bin

        - task: Bash@3
          displayName: 'Generate CycloneDX SBOM'
          inputs:
            targetType: inline
            script: |
              IMAGE="${ACR_NAME}.azurecr.io/$(serviceName):$(Build.BuildId)"
              syft "${IMAGE}" \
                --output cyclonedx-json \
                --file "$(Build.ArtifactStagingDirectory)/sbom-$(serviceName)-$(Build.BuildId).cdx.json"

        - task: PublishBuildArtifacts@1
          displayName: 'Attach SBOM to pipeline run'
          inputs:
            PathtoPublish: '$(Build.ArtifactStagingDirectory)'
            ArtifactName: 'sbom'
            publishLocation: 'Container'

CycloneDX Format Overview

CycloneDX JSON produced by Syft contains:

json
{
  "bomFormat": "CycloneDX",
  "specVersion": "1.4",
  "version": 1,
  "metadata": {
    "timestamp": "2024-01-15T10:30:00Z",
    "component": {
      "name": "mic-gateway",
      "version": "1.0.0+build.42"
    }
  },
  "components": [
    {
      "type": "library",
      "name": "Microsoft.AspNetCore",
      "version": "8.0.1",
      "purl": "pkg:nuget/Microsoft.AspNetCore@8.0.1",
      "licenses": [{ "license": { "id": "MIT" } }]
    }
  ]
}

Key fields:

FieldDescription
metadata.componentThe scanned image / service name
components[].purlPackage URL — universally unique identifier for the dependency
components[].licensesSPDX license identifier
components[].hashesSHA-256 hash for integrity verification

What Syft Scans

Syft catalogues packages from all ecosystems present in the image layers:

EcosystemSource files scanned
NuGet (.NET)*.deps.json, packages.lock.json
npm (Angular)package-lock.json, node_modules/
Dart/Pub (Flutter)pubspec.lock
OS packagesdpkg, rpm, apk databases in base image
Pythonrequirements.txt, site-packages/

Syft + Trivy Complement Each Other

Trivy flags vulnerabilities; Syft lists packages. Both run in the pipeline. Trivy is the security gate; Syft is the audit artefact. Use Syft output to answer "what version of package X ships in this image?"


Querying the SBOM

After downloading sbom-<service>-<buildId>.cdx.json from a pipeline run:

bash
# List all NuGet packages
jq '.components[] | select(.purl | startswith("pkg:nuget")) | "\(.name) \(.version)"' sbom.cdx.json

# Find a specific package across all components
jq '.components[] | select(.name == "System.Text.Json")' sbom.cdx.json

# List all licenses in use
jq '[.components[].licenses[]?.license.id] | unique | sort' sbom.cdx.json

# Check if a vulnerable package version is present (e.g. CVE triage)
jq '.components[] | select(.name == "Newtonsoft.Json" and .version == "12.0.3")' sbom.cdx.json

SBOM in the DevSecOps Pipeline


Known Limitations

Runtime Dependencies Not Captured

Syft scans image layers at build time. Packages loaded at runtime via reflection or dynamic assembly loading (common in .NET plugin architectures) will not appear in the SBOM. Supplement with runtime RASP tooling if full runtime coverage is required.

  • SBOM is generated per-service, not per-environment. The same SBOM covers all environments a given image tag is deployed to.
  • Syft does not assign CVE scores — use Trivy for vulnerability scoring.

Internal Documentation — Microtec Platform Team