Testland
Browse all skills & agents

syft-generation

Generates Software Bill of Materials (SBOMs) using Anchore Syft - supports container images / directories / archives across OCI / Docker / Singularity formats; output formats CycloneDX-JSON / SPDX-JSON / Syft-JSON / table / GitHub-JSON; pairs with `grype-scanning` for SBOM-driven vuln scanning. Use when the team needs SBOM artifacts for compliance (US EO 14028, EU CRA, FDA medical-device guidance) or as input to vuln scanners.

syft-generation

Overview

Per github.com/anchore/syft:

Syft generates SBOMs from "container images, filesystems, archives" with multi-container-standard support (OCI, Docker, Singularity). The generated SBOM is the input artifact for vuln scanning (grype-scanning) and compliance delivery (SPDX or CycloneDX format per consumer requirement).

Why generate SBOMs:

  • US Executive Order 14028 (May 2021) requires SBOMs for software sold to US federal agencies
  • EU Cyber Resilience Act (in effect 2024+) requires SBOMs for products with digital elements
  • FDA medical-device cybersecurity guidance requires SBOMs
  • Internal supply-chain audits need a manifest of every dependency shipped

When to use

  • The team ships software to customers requiring an SBOM (federal, EU regulated, medical device, etc.).
  • Internal compliance program requires SBOM as evidence artifact.
  • The vuln-scanning workflow needs an SBOM input (Grype, OSV-Scanner with --sbom).
  • Container-image build pipelines need accompanying SBOM for delivery alongside the image.

Step 1 - Install

Per sf-gh:

# curl install
curl -sSfL https://get.anchore.io/syft | sudo sh -s -- -b /usr/local/bin

# Homebrew
brew install syft

# Docker
docker run --rm -v "$PWD:/scan" anchore/syft scan dir:/scan -o cyclonedx-json

Other paths (consult sf-gh): Scoop, Chocolatey, Nix.

Step 2 - Basic SBOM generation

Per sf-gh:

# Container image
syft alpine:latest

# Local directory
syft ./my-project

# Specific output format to stdout
syft <image> -o cyclonedx-json

# Multiple formats to files in one pass
syft <image> -o spdx-json=./spdx.json -o cyclonedx-json=./cdx.json

The default output is the table format (human-readable); use explicit -o for machine-readable formats in CI.

Step 3 - Output format catalog

Per sf-gh format support:

FormatUse
cyclonedx-jsonCycloneDX 1.5+ JSON; broad ecosystem support
cyclonedx-xmlCycloneDX XML (older toolchains)
spdx-jsonSPDX 2.3 JSON; preferred by US Federal procurement
spdx-tag-valueSPDX tag-value format (legacy)
syft-jsonSyft-native JSON; richest metadata
tableHuman-readable terminal table (default)
github-jsonGitHub dependency-graph submission format

For grype-scanning input, use syft-json (richest metadata) or cyclonedx-json (broader compat).

For compliance delivery, the consumer's requirement dictates - SPDX-JSON for US federal, CycloneDX-JSON for most EU contexts.

Step 4 - Source types

Per sf-gh supported sources:

SourceSyntax
Local Docker daemonsyft alpine:latest
OCI / remote registrysyft registry:docker.io/alpine:latest
OCI archive (tar)syft oci-archive:./image.tar
Docker archive (tar)syft docker-archive:./image.tar
Local directorysyft dir:./my-project (or syft ./my-project)
Filesyft file:./pom.xml
Singularity imagesyft singularity:./image.sif

Step 5 - Attestation pattern (cosign)

For supply-chain integrity, attach the SBOM to the container image via Sigstore cosign:

# Generate SBOM
syft my-image:1.0 -o cyclonedx-json=sbom.json

# Sign + attach to image (Sigstore)
cosign attest --predicate sbom.json --type cyclonedx my-image:1.0

# Verify
cosign verify-attestation --type cyclonedx my-image:1.0

The attestation lives alongside the image in the registry; downstream consumers can verify provenance + retrieve the SBOM.

Step 6 - False-positive triage analogue

Syft generates inventories, not findings - there's no FP triage per se. The analogue here is inventory accuracy: ensuring Syft correctly identifies all components.

MechanismUse
--exclude=PATH_PATTERNSkip directories from scan (vendor / generated)
--catalogers=CATALOGERRestrict to specific catalogers (e.g., npm, python)
--source-name=NAME / --source-version=VERSIONOverride SBOM-level metadata
--platform=linux/amd64Target specific platform for multi-arch images

Inventory accuracy validation:

# Compare two SBOMs (e.g., before vs after a build change)
syft image:1.0 -o syft-json=v1-sbom.json
syft image:1.1 -o syft-json=v1.1-sbom.json
diff <(jq -S . v1-sbom.json) <(jq -S . v1.1-sbom.json)

If Syft misses a component (false negative on inventory), the downstream vuln scan misses any CVEs against that component. Periodic accuracy validation against known dependencies catches this.

Step 7 - CI integration

jobs:
  sbom:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: anchore/sbom-action@v0
        with:
          path: ./
          format: cyclonedx-json
          output-file: sbom.cyclonedx.json
      - uses: anchore/sbom-action@v0
        with:
          path: ./
          format: spdx-json
          output-file: sbom.spdx.json
      - uses: actions/upload-artifact@v4
        with:
          name: sboms
          path: sbom.*.json

The anchore/sbom-action GHA wraps Syft + handles GitHub dependency-graph submission automatically when format: github-json.

Step 8 - Composition with sister tools

Sister toolUse
grype-scanningSBOM-driven vuln scanning (grype sbom:./sbom.json)
cyclonedx-formatReference for CycloneDX schema + spec compliance
spdx-formatReference for SPDX schema + spec compliance
trivy-imageAlternative scanner (built-in SBOM gen + scan in one pass)
osv-scannerCross-plugin: also accepts SBOM input

Anti-patterns

Anti-patternWhy it failsFix
Generate SBOM only at release timeMisses build-time inventory differencesGenerate per CI build + attest
Use single format onlyDifferent consumers need different formatsGenerate both CycloneDX + SPDX (Step 2)
Skip platform targeting on multi-arch imagesMisses platform-specific deps--platform=linux/amd64 (Step 6)
Generate SBOM but don't attest / signProvenance unverifiable downstreamCosign attest pattern (Step 5)
Trust Syft inventory without validationMisses components → misses CVEsPeriodic accuracy check (Step 6)

Limitations

  • Syft can't scan what it can't see - encrypted archives, custom package formats may produce incomplete SBOMs.
  • Some language-specific catalogers have edge cases (e.g., npm workspaces, Python wheel quirks); validate against known deps.
  • SBOM generation alone doesn't prove the deps are vulnerability-free - pair with grype-scanning.
  • Multi-arch container scanning is per-platform; combine SBOMs manually or via tooling for unified view.

References