Automatizando SBOM (Software Bill of Materials) em Pipelines GitHub Actions

O que é SBOM e por que ele se tornou obrigatório

SBOM (Software Bill of Materials) é um inventário estruturado de todos os componentes, bibliotecas e dependências que compõem um artefato de software. Ele permite rastrear a origem de cada peça, identificar vulnerabilidades conhecidas (CVEs) e atender a requisitos regulatórios como a Executive Order 14028 dos EUA ou a ISO/IEC 5230. Em ambientes de entrega contínua, a geração manual de SBOM é inviável; a automação dentro do pipeline de CI/CD garante que cada build tenha um manifesto atualizado e verificável.

Arquitetura típica de um pipeline GitHub Actions com SBOM

Um workflow padrão no GitHub Actions contém três estágios principais: checkout, build e deploy. Para integrar SBOM, inserimos duas etapas adicionais: geração e validação. A geração pode ser feita com ferramentas como Syft, CycloneDX ou SPDX. A validação verifica a conformidade com políticas internas (por exemplo, proibição de licenças GPL) e checa vulnerabilidades usando Grype ou Trivy. O diagrama abaixo ilustra o fluxo:

Fluxo resumido

  • checkout → build → generate SBOM → scan SBOM → publish artifacts → deploy

Escolhendo a ferramenta de geração de SBOM

Existem três padrões amplamente adotados:

  • SPDX (Software Package Data Exchange): foco em licenças e metadados de origem.
  • CycloneDX: otimizado para análise de vulnerabilidades e integração com scanners.
  • Syft: ferramenta de código aberto da Anchore que produz SBOM em múltiplos formatos (SPDX, CycloneDX, JSON).

A escolha depende do ecossistema da sua organização. Se a prioridade for auditoria de licenças, SPDX costuma ser a melhor opção. Para pipelines que já utilizam Trivy, CycloneDX oferece compatibilidade nativa.

Implementação prática: exemplo de workflow YAML

A seguir, um exemplo completo de um arquivo .github/workflows/sbom.yml que gera e valida SBOM para um projeto Node.js. Cada passo está comentado para facilitar a manutenção.

name: Build & SBOM
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build-and-sbom:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      id-token: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build application
        run: npm run build

      # ---------- SBOM Generation ----------
      - name: Install Syft
        run: |
          curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b $HOME/.local/bin
          echo "$HOME/.local/bin" >> $GITHUB_PATH

      - name: Generate SBOM (CycloneDX)
        id: generate-sbom
        run: |
          syft packages . -o cyclonedx-json > sbom.cdx.json
          echo "sbom_path=sbom.cdx.json" >> $GITHUB_OUTPUT

      # ---------- Vulnerability Scan ----------
      - name: Install Trivy
        uses: aquasecurity/[email protected]
        with:
          scan-type: 'fs'
          format: 'json'
          output: 'trivy-report.json'
          severity: 'CRITICAL,HIGH'
          ignore-unfixed: true

      - name: Scan SBOM with Trivy
        run: |
          trivy sbom ${{ steps.generate-sbom.outputs.sbom_path }} --format json --output sbom-vulns.json

      # ---------- Policy Enforcement ----------
      - name: Enforce license policy (SPDX)
        if: always()
        run: |
          # Exemplo simples: falha se houver licença GPL-3.0
          grep -q "GPL-3.0" sbom.cdx.json && exit 1 || echo "License policy passed"

      # ---------- Publish SBOM as artifact ----------
      - name: Upload SBOM artifact
        uses: actions/upload-artifact@v4
        with:
          name: sbom
          path: sbom.cdx.json

      # ---------- Optional: Push SBOM to Dependency Track ----------
      - name: Submit SBOM to Dependency-Track
        if: github.ref == 'refs/heads/main'
        env:
          DT_API_KEY: ${{ secrets.DEPENDENCY_TRACK_API_KEY }}
          DT_URL: ${{ secrets.DEPENDENCY_TRACK_URL }}
        run: |
          curl -X POST "$DT_URL/api/v1/bom" 
            -H "X-Api-Key: $DT_API_KEY" 
            -F "[email protected]"

Observe que o workflow utiliza variáveis de ambiente seguras (secrets) para credenciais externas e que a política de licença está implementada como um simples grep. Em ambientes corporativos, recomenda‑se usar ferramentas como OPA (Open Policy Agent) para políticas declarativas mais robustas.

Integração com repositórios de artefatos e registries

Depois de gerar o SBOM, ele deve ser armazenado junto ao artefato binário (Docker image, JAR, etc.). No caso de imagens Docker, a prática recomendada é anexar o SBOM como um label ou como um artifact no registro (por exemplo, GitHub Container Registry ou Docker Hub). O comando abaixo demonstra como empurrar a imagem com um label contendo o hash do SBOM:

# Build Docker image
docker build -t ghcr.io/empresa/app:${{ github.sha }} .
# Compute SBOM hash
SBOM_HASH=$(sha256sum sbom.cdx.json | cut -d' ' -f1)
# Tag image with SBOM hash
docker tag ghcr.io/empresa/app:${{ github.sha }} ghcr.io/empresa/app:${SBOM_HASH}
# Push both tags
docker push ghcr.io/empresa/app:${{ github.sha }}
docker push ghcr.io/empresa/app:${SBOM_HASH}

Essa estratégia permite que consumidores da imagem verifiquem a correspondência entre o binário e o SBOM, facilitando auditorias de supply chain.

Validação contínua: monitoramento de vulnerabilidades pós‑deploy

Mesmo após a publicação, novas vulnerabilidades podem ser descobertas. Ferramentas como Dependency‑Track ou GitHub Advanced Security podem consumir SBOMs periodicamente e gerar alertas. A integração típica envolve um webhook que notifica o repositório quando um CVE crítico afeta um componente presente no SBOM. O fluxo de resposta costuma ser:

  1. Webhook dispara um issue automático no GitHub.
  2. Pipeline de correção é disparado (dependabot ou Renovate).
  3. Nova versão da dependência é construída, SBOM regenerado e re‑publicado.

Automatizar esse ciclo reduz o tempo médio de remediação (MTTR) de vulnerabilidades de dias para horas.

Boas práticas de governança de SBOM

  • Versionamento explícito: inclua o número da versão do SBOM no nome do artefato (ex.: sbom-1.0.3.cdx.json).
  • Armazenamento imutável: use buckets S3 com versionamento ou repositórios de artefatos que garantam integridade.
  • Assinatura criptográfica: assine o SBOM com GPG ou cosign para garantir autenticidade.
  • Retenção de histórico: mantenha SBOMs de releases antigas para auditorias de compliance.
  • Documentação de políticas: descreva regras de aceitação de licenças e limites de severidade em arquivos .policy versionados.

Desafios comuns e como mitigá‑los

Componentes transitivos não detectados: algumas ferramentas analisam apenas dependências diretas. A solução é usar scanners que resolvem a árvore completa de dependências (ex.: syft packages . --scope all).

Falsos positivos em licenças: arquivos de licença mal formatados podem gerar alertas indevidos. Automatize a normalização de arquivos LICENSE e use ferramentas como licensee para validação pré‑build.

Performance do pipeline: geração de SBOM pode ser custosa em projetos monolíticos. Estratégias de cache (ex.: salvar o diretório node_modules) e paralelização de etapas reduzem o tempo total em até 30%.

Roadmap futuro: SBOM como código

O conceito emergente de “SBOM as Code” propõe tratar o manifesto como parte do código‑fonte, versionado em Git e submetido a revisões de pull‑request. Isso permite revisões de segurança de dependências da mesma forma que revisamos código. Integrações com ferramentas como pre-commit podem impedir merges que introduzam componentes proibidos.

Além disso, a especificação SPDX 3.0 traz suporte a metadados de build, provenance e relacionamentos entre múltiplos SBOMs (por exemplo, entre micro‑serviços). Adotar essas extensões prepara a organização para auditorias de supply chain cada vez mais rigorosas.

Resumo técnico e próximos passos

Automatizar SBOM em pipelines GitHub Actions envolve três pilares: geração confiável (Syft, CycloneDX), validação contínua (Trivy, OPA) e publicação segura (artefatos, registries, assinatura). Ao implementar o workflow exemplificado, sua equipe ganha visibilidade total da cadeia de suprimentos, reduz o risco de vulnerabilidades não detectadas e cumpre requisitos regulatórios sem sobrecarga manual.

Para avançar, recomendamos:

  1. Adotar um padrão único (SPDX ou CycloneDX) em toda a organização.
  2. Integrar o SBOM ao Dependency‑Track e habilitar alertas de CVE.
  3. Implementar assinatura de SBOMs com cosign.
  4. Estabelecer políticas de licença via OPA e versioná‑las no repositório.
  5. Monitorar métricas de tempo de geração e taxa de falhas para otimizar o pipeline.

Com essas práticas, sua cadeia de entrega de software se torna resiliente, auditável e pronta para os desafios de segurança da próxima geração.