STP
SBOM Observer/

Automation Strategies

Approaches for automating SBOM generation, validation, distribution, and VEX publication

Manual SBOM processes don't scale. Generating SBOMs by hand for every release, manually validating quality, individually distributing to customers, tracking updates through spreadsheets—these approaches work for pilot programs with handful of products but collapse under operational load. Organizations with dozens or hundreds of products releasing weekly need automation or SBOM programs become unsustainable overhead consuming resources without delivering proportional value.

Automation transforms SBOM from periodic compliance burden to continuous operational capability. Build pipelines automatically generate SBOMs. Validation gates catch quality problems before release. Distribution happens automatically when releases publish. VEX documents trigger from vulnerability monitoring. Metrics update in real-time. What required days of manual effort becomes minutes of automated processing. Automation is investment with ongoing returns—upfront configuration effort pays dividends through reduced operational costs, improved quality, and faster response times.

Automation Maturity Levels

Level 0: Fully Manual

Characteristics:

  • Developer manually runs SBOM generation tool
  • Manual file editing for corrections
  • Email or manual upload for distribution
  • Spreadsheet tracking of SBOM versions
  • No validation beyond "looks reasonable"

Effort: 2-4 hours per product per release

Suitable for: Initial pilots (under 5 products), proof-of-concept

Limitations: Doesn't scale, error-prone, inconsistent quality, knowledge concentrated in individuals

Level 1: Scripted Generation

Characteristics:

  • Shell scripts automate generation steps
  • Manual invocation but automated execution
  • Basic validation through scripts
  • Distribution still mostly manual
  • Version tracking in files or simple database

Example:

#!/bin/bash
# generate-sbom.sh - Run manually when releasing

set -e

echo "Generating SBOM..."
cyclonedx-npm --output-file sbom.json

echo "Validating..."
cyclonedx-cli validate --input-file sbom.json

echo "Calculating hash..."
sha256sum sbom.json > sbom.json.sha256

echo "Signing..."
gpg --detach-sign --armor sbom.json

echo "Done! Files ready for manual distribution."

Effort: 30-60 minutes per product per release

Suitable for: 5-20 products, early scaling phase

Advantages: Consistency improvement over fully manual, reduces errors, faster execution

Limitations: Still requires human to remember and execute, no automatic quality gates, scaling challenges remain

Level 2: CI/CD Integration

Characteristics:

  • SBOM generation automatic on every build
  • Automated validation as build gates
  • Build fails if SBOM quality insufficient
  • Artifacts published to artifact repository automatically
  • Notifications on generation failures

Example (GitHub Actions):

name: Build and SBOM

on:
  push:
    branches: [main]
  release:
    types: [published]

jobs:
  build-and-sbom:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build application
        run: npm ci && npm run build

      - name: Generate SBOM
        run: npx @cyclonedx/cyclonedx-npm --output-file sbom.json

      - name: Validate SBOM
        run: |
          npx @cyclonedx/cyclonedx-cli validate --input-file sbom.json
          node scripts/quality-check.js sbom.json --min-score 80

      - name: Sign SBOM
        env:
          GPG_PRIVATE_KEY: €{{ secrets.GPG_PRIVATE_KEY }}
        run: |
          echo "€GPG_PRIVATE_KEY" | gpg --import
          gpg --detach-sign --armor sbom.json

      - name: Upload artifacts
        uses: actions/upload-artifact@v3
        with:
          name: sbom-artifacts
          path: |
            sbom.json
            sbom.json.asc

      - name: Publish to SBOM repository
        if: github.event_name == 'release'
        env:
          SBOM_REPO_TOKEN: €{{ secrets.SBOM_REPO_TOKEN }}
        run: |
          curl -X POST https://sbom.example.com/api/upload \
            -H "Authorization: Bearer €SBOM_REPO_TOKEN" \
            -F "product=€{{ github.repository }}" \
            -F "version=€{{ github.ref_name }}" \
            -F "sbom=@sbom.json"

Effort: Minimal per-release (automatic), 4-8 hours initial setup per product

Suitable for: 10-100+ products, operational scale

Advantages: Scales effortlessly, consistent quality, no human forgetting, immediate feedback on problems

Limitations: Requires CI/CD infrastructure, one-time setup per product, cross-team coordination for pipeline modifications

Level 3: Fully Automated Ecosystem

Characteristics:

  • Zero-touch SBOM generation and distribution
  • Continuous monitoring and alerting
  • Automated VEX publication workflows
  • Integration with security tools (vulnerability scanners, dependency tracking)
  • Automated metrics and reporting
  • Self-service tooling for developers

Architecture:

  • Central SBOM repository with APIs
  • Automated ingestion from all CI/CD pipelines
  • Webhook-driven distribution to customers
  • Event-driven VEX publication
  • Continuous vulnerability correlation
  • Real-time dashboards and analytics

Effort: Minimal ongoing (highly automated), 3-6 months initial ecosystem build

Suitable for: 100+ products, enterprise scale, mature security operations

Advantages: Scales to unlimited products, minimal manual intervention, rapid response to vulnerabilities, comprehensive visibility

Limitations: Significant initial investment, requires dedicated platform team, organizational coordination across many teams

CI/CD Integration Patterns

Build-Time Generation

Pattern: Generate SBOM during application build process.

Advantages:

  • SBOM reflects exactly what was built
  • Build environment has full dependency information
  • Natural integration point—every build creates SBOM
  • Can validate SBOM before allowing build to complete

Implementation considerations:

  • Add SBOM generation step to build scripts/pipelines
  • Ensure build tools have SBOM plugin support
  • Handle build failures gracefully when SBOM generation fails
  • Store SBOM alongside build artifacts

Language-specific examples:

Node.js/npm:

{
  "scripts": {
    "build": "tsc && npm run sbom",
    "sbom": "cyclonedx-npm --output-file dist/sbom.json"
  }
}

Java/Maven:

<build>
  <plugins>
    <plugin>
      <groupId>org.cyclonedx</groupId>
      <artifactId>cyclonedx-maven-plugin</artifactId>
      <version>2.7.10</version>
      <executions>
        <execution>
          <phase>package</phase>
          <goals>
            <goal>makeAggregateBom</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Python:

# In CI/CD pipeline
python -m pip install cyclonedx-bom
cyclonedx-py --output sbom.json

Post-Build Analysis

Pattern: Analyze built artifacts to generate SBOM.

Advantages:

  • Works when build process can't be modified
  • Can analyze any artifact regardless of build method
  • Suitable for legacy or third-party builds
  • Discovers actual deployed components

Implementation:

# GitHub Actions example
- name: Build application
  run: make build

- name: Analyze artifacts for SBOM
  run: |
    syft packages dist/app.tar.gz -o cyclonedx-json=sbom.json

Tools:

  • Syft: Universal package analyzer
  • Grype: Vulnerability scanner with SBOM output
  • Tern: Container analysis
  • Language-specific analyzers for compiled artifacts

Limitations:

  • May miss build-time-only dependencies
  • Version detection can be imprecise
  • Requires post-processing for quality

Container Build Integration

Pattern: Generate SBOM as part of container image build and attach to registry.

Advantages:

  • SBOM travels with image
  • OCI registry native support
  • Consumers retrieve SBOM with image pull
  • Automatic versioning via image tags

Implementation:

# Dockerfile multi-stage build with SBOM generation
FROM node:18 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build && \
    npx @cyclonedx/cyclonedx-npm --output-file /sbom.json

FROM node:18-slim
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /sbom.json ./sbom.json
COPY package*.json ./
RUN npm ci --production
CMD ["node", "dist/index.js"]

Registry attachment:

# Push image
docker push registry.example.com/app:v1.2.3

# Attach SBOM as artifact
oras attach --artifact-type application/cyclonedx+json \
  registry.example.com/app:v1.2.3 \
  sbom.json

Validation Automation

Automated validation catches quality problems before they reach consumers.

Multi-Level Validation Pipeline

# validation-pipeline.py
def validate_sbom_pipeline(sbom_file):
    """Comprehensive automated validation"""

    results = {
        'passed': True,
        'errors': [],
        'warnings': [],
        'score': 0
    }

    # Level 1: Schema validation
    schema_result = validate_schema(sbom_file)
    if not schema_result['valid']:
        results['passed'] = False
        results['errors'].append(f"Schema validation failed: {schema_result['error']}")
        return results  # Fatal error, stop validation

    # Level 2: Completeness checks
    sbom = load_sbom(sbom_file)
    completeness = check_completeness(sbom)

    if completeness['score'] < 60:
        results['passed'] = False
        results['errors'].append(f"Completeness score {completeness['score']} below minimum 60")

    if completeness['missing_purls'] > 0.1:  # Over 10% missing PURLs
        results['warnings'].append(f"{completeness['missing_purls']:.0%} components lack PURLs")

    # Level 3: Accuracy spot checks
    accuracy = spot_check_accuracy(sbom)
    if accuracy['discrepancies'] > 2:
        results['warnings'].append(f"{accuracy['discrepancies']} version discrepancies detected")

    # Level 4: Security checks
    security = check_security_metadata(sbom)
    if security['unsigned']:
        results['warnings'].append("SBOM is not cryptographically signed")

    # Calculate composite score
    results['score'] = calculate_validation_score(schema_result, completeness, accuracy, security)

    return results

# Usage in CI/CD
result = validate_sbom_pipeline('sbom.json')
if not result['passed']:
    print("SBOM validation failed!")
    for error in result['errors']:
        print(f"ERROR: {error}")
    sys.exit(1)

if result['warnings']:
    print("Validation warnings:")
    for warning in result['warnings']:
        print(f"WARNING: {warning}")

print(f"Validation passed with score: {result['score']}")

Quality Gates

Pre-commit hooks: Prevent committing changes that break SBOM generation:

# .git/hooks/pre-commit
#!/bin/bash
# Validate SBOM can be generated before allowing commit

echo "Generating test SBOM..."
npm run sbom:generate --silent > /dev/null 2>&1

if [ €? -ne 0 ]; then
  echo "ERROR: SBOM generation failed. Commit rejected."
  echo "Fix dependency issues before committing."
  exit 1
fi

echo "SBOM generation successful."

Pull request gates: Automated PR checks validate SBOM quality before merge:

name: PR SBOM Check

on: [pull_request]

jobs:
  sbom-quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Generate SBOM
        run: npm run sbom:generate

      - name: Quality check
        run: |
          SCORE=€(node scripts/sbom-quality-score.js sbom.json)
          if [ "€SCORE" -lt 80 ]; then
            echo "SBOM quality score €SCORE below required 80"
            exit 1
          fi

      - name: Comment on PR
        uses: actions/github-script@v7
        with:
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: '✅ SBOM quality check passed (score: ' + process.env.SCORE + ')'
            })

Distribution Automation

Automated distribution ensures SBOMs reach consumers without manual intervention.

Multi-Channel Publication

# automated-distribution.py
def distribute_sbom(sbom_file, product, version):
    """Publish SBOM to multiple channels"""

    # Channel 1: Upload to SBOM repository API
    upload_to_repository(
        sbom_file=sbom_file,
        api_url=SBOM_REPO_URL,
        product=product,
        version=version
    )

    # Channel 2: Attach to GitHub release
    if GITHUB_RELEASE:
        attach_to_github_release(
            sbom_file=sbom_file,
            repo=GITHUB_REPO,
            tag=version
        )

    # Channel 3: Publish to customer portal
    upload_to_customer_portal(
        sbom_file=sbom_file,
        portal_url=CUSTOMER_PORTAL_URL,
        product=product,
        version=version
    )

    # Channel 4: Trigger webhook notifications
    notify_subscribers(
        event='sbom.published',
        product=product,
        version=version,
        sbom_url=construct_sbom_url(product, version)
    )

    # Channel 5: Update download page
    update_documentation_site(
        product=product,
        version=version,
        sbom_url=construct_sbom_url(product, version)
    )

    print(f"SBOM distributed to all channels for {product} {version}")

Webhook-Based Distribution

Consumers subscribe to webhooks for automatic SBOM delivery:

# webhook-publisher.py
@app.route('/api/sbom/publish', methods=['POST'])
def publish_sbom():
    """Webhook endpoint for SBOM publication events"""

    sbom_data = request.json
    product = sbom_data['product']
    version = sbom_data['version']

    # Fetch all webhook subscriptions for this product
    subscriptions = get_webhook_subscriptions(product)

    for subscription in subscriptions:
        try:
            # Call subscriber webhook
            response = requests.post(
                subscription['webhook_url'],
                json={
                    'event': 'sbom.published',
                    'product': product,
                    'version': version,
                    'sbom_url': sbom_data['url'],
                    'timestamp': datetime.utcnow().isoformat()
                },
                headers={'X-Webhook-Signature': calculate_signature(subscription['secret'], sbom_data)},
                timeout=10
            )

            if response.status_code == 200:
                log_webhook_success(subscription['id'])
            else:
                log_webhook_failure(subscription['id'], response.status_code)

        except Exception as e:
            log_webhook_error(subscription['id'], str(e))
            # Queue for retry

    return {'status': 'published', 'subscribers_notified': len(subscriptions)}

VEX Automation

Automate VEX document creation and publication in response to vulnerability disclosures.

Monitoring-Driven VEX Publication

# vex-automation.py
def monitor_and_publish_vex():
    """Continuous vulnerability monitoring with automated VEX"""

    # Monitor vulnerability databases
    new_cves = fetch_new_cves_since(last_check_time)

    for cve in new_cves:
        # Query SBOM repository for affected products
        affected_products = query_sboms_for_component(
            component=cve['affected_component'],
            version_range=cve['version_range']
        )

        if not affected_products:
            continue  # CVE doesn't affect our products

        # Initiate assessment workflow
        for product in affected_products:
            assessment_ticket = create_assessment_ticket(product, cve)

            # Publish initial "under_investigation" VEX
            publish_vex(
                product=product,
                cve=cve['id'],
                status='under_investigation',
                detail='Assessment in progress. ETA for status determination: 48 hours.',
                action_statement='Monitor this advisory for updates.'
            )

            # Notify security team
            notify_security_team(product, cve, assessment_ticket)

# Scheduled execution
schedule.every(6).hours.do(monitor_and_publish_vex)

Status Update Automation

# vex-status-updater.py
@app.route('/api/vex/update-status', methods=['POST'])
def update_vex_status():
    """Update VEX status when assessment completes"""

    data = request.json
    product = data['product']
    cve_id = data['cve_id']
    new_status = data['status']  # not_affected, affected, or fixed
    justification = data.get('justification')
    detail = data['detail']

    # Generate VEX document
    vex_doc = generate_vex_document(
        product=product,
        cve_id=cve_id,
        status=new_status,
        justification=justification,
        detail=detail
    )

    # Publish to repository
    publish_vex_to_repository(vex_doc)

    # Distribute to customers
    distribute_vex(
        vex_doc=vex_doc,
        product=product,
        channels=['api', 'webhook', 'email']
    )

    # Update internal tracking
    update_vulnerability_tracking(product, cve_id, new_status)

    return {'status': 'published', 'vex_url': construct_vex_url(product, cve_id)}

Metrics and Monitoring Automation

Automated metrics collection and alerting ensures program health visibility.

Automated Dashboard Updates

# metrics-collector.py
def collect_sbom_metrics():
    """Collect and publish program metrics"""

    metrics = {
        'coverage': {
            'total_products': count_total_products(),
            'products_with_sbom': count_products_with_sbom(),
            'coverage_percentage': calculate_coverage_percentage()
        },
        'quality': {
            'average_completeness_score': calculate_avg_completeness(),
            'percentage_signed': calculate_signed_percentage(),
            'percentage_valid': calculate_valid_percentage()
        },
        'responsiveness': {
            'avg_time_to_vex': calculate_avg_vex_publication_time(),
            'avg_sbom_freshness': calculate_avg_sbom_age(),
            'update_compliance_rate': calculate_update_sla_compliance()
        },
        'supplier': {
            'suppliers_providing_sboms': count_suppliers_with_sboms(),
            'supplier_compliance_rate': calculate_supplier_compliance(),
            'avg_supplier_quality_score': calculate_avg_supplier_quality()
        }
    }

    # Publish to dashboard
    publish_metrics_to_dashboard(metrics)

    # Check for concerning trends
    alerts = check_metric_thresholds(metrics)
    if alerts:
        send_alerts_to_team(alerts)

    return metrics

# Run daily
schedule.every().day.at("02:00").do(collect_sbom_metrics)

Automation Implementation Roadmap

Month 1-2: Foundation

  • Implement CI/CD SBOM generation for 5 pilot products
  • Basic validation scripts
  • Manual distribution with automated notifications

Month 3-4: Expansion

  • Roll out CI/CD generation to 20+ products
  • Automated quality gates in pipelines
  • Semi-automated distribution (scripted multi-channel)

Month 5-6: Integration

  • SBOM repository deployment
  • API-based distribution
  • Automated VEX workflow (monitoring + publication)

Month 7-8: Optimization

  • Metrics automation and dashboarding
  • Advanced quality checks
  • Self-service tooling for developers
  • Documentation and training

Month 9-12: Maturity

  • Full ecosystem automation
  • Continuous improvement based on metrics
  • Advanced integrations (SIEM, ticketing, compliance)
  • Organizational scaling

Next Steps

On this page