WASViking Docs
⌘K
Primeiros passos

SCA, SBOM e secrets em CI/CD com Bitbucket Pipelines

Execute o WASViking Sentinel dentro do Bitbucket Pipelines para montar um SBOM CycloneDX, verificar dependências contra OSV e CISA KEV, analisar a working tree e o histórico do git em busca de credenciais embutidas no código e barrar uma release vulnerável antes que ela chegue à sua branch principal.

Este guia executa Análise de Composição de Software (SCA) e um scan de secrets dentro de um build do Bitbucket Pipelines. O WASViking® Sentinel lê os seus manifestos de dependências, monta um SBOM CycloneDX, enriquece-o com OSV e CISA KEV, percorre a working tree e o histórico do git em busca de credenciais embutidas no código e faz o build falhar antes que uma dependência vulnerável ou uma chave vazada chegue à sua branch principal.

Os dois gates usam o mesmo binário e a mesma API do guia de GitHub Actions. Nenhum deles está preso a um fornecedor de CI: o agente roda como um comando de execução única, autentica com uma chave de API da organização e envia os dados por HTTPS REST. O que muda entre fornecedores é o YAML em volta, mais dois detalhes do Bitbucket que passam despercebidos com facilidade e que esta página destaca explicitamente (a profundidade do clone e as variáveis protegidas).

Não há túnel mTLS neste fluxo. Nenhum código-fonte sai do runner, apenas o grafo de dependências (nomes e versões de pacotes) e as ocorrências de secrets mascaradas.

A configuração tem duas metades, e a ordem importa: configure primeiro o portal da WASViking (uma chave de API com os escopos ci:scan, sca:submit e secrets:submit) e depois conecte-a ao Bitbucket.

O que esta integração faz

  • Gera um SBOM CycloneDX 1.5 a partir dos seus manifestos (npm, pip, go, composer, Maven, gem, pub) em pull requests e em pushes para main.
  • Enriquece os componentes com OSV e CISA KEV (vulnerabilidades com exploração conhecida).
  • Analisa a working tree e, com --git, o histórico do repositório em busca de secrets embutidos no código, enviando apenas ocorrências mascaradas.
  • Opcionalmente verifica uma ocorrência no endpoint de identidade do provedor com --verify, para que uma chave já rotacionada não pareça um incidente em andamento.
  • Faz o build falhar por severidade com --fail-on, o que bloqueia o merge.
  • Grava o SARIF 2.1.0 e o JSON CycloneDX bruto como artefatos do build.
  • Monta um inventário de software consolidado por organização e detecta drift entre envios consecutivos.
  • Não deixa nada para trás no runner. O agente é instalado a cada build e morre junto com o container.

Como funciona

  1. O container do build baixa e instala o agente Sentinel usando a chave de API.
  2. O agente executa uma verificação prévia de licença (preflight) na API da WASViking. A aprovação fica em cache por 30 minutos em ~/.wasviking/, o que, em um build do Bitbucket, significa que ela é buscada de novo a cada execução.
  3. Ele percorre os manifestos do projeto e monta um SBOM CycloneDX.
  4. Ele enriquece os componentes com dados do OSV e aplica a validação CISA KEV.
  5. Ele analisa a árvore, e o histórico do git quando --git está definido, em busca de credenciais embutidas no código.
  6. Ele envia o SBOM e as ocorrências mascaradas por HTTPS REST. A API valida a cota, registra o snapshot, detecta drift de componentes e promove achados.
  7. O agente grava as saídas JSON e SARIF em --out, e o Bitbucket coleta esse diretório como artefato do build.

Postura de acesso

  • Apenas os manifestos e o grafo de dependências são lidos. Nenhum código-fonte, nenhuma variável do repositório além da chave que você informa e nada fora de .wasviking/ é coletado.
  • Os valores brutos dos secrets nunca saem do runner. Os envios carregam um hash e uma prévia mascarada.
  • O envio é feito por HTTPS REST com a chave de API em um header. Não há túnel mTLS nem conexão de entrada para o runner.
  • --verify adiciona chamadas somente leitura aos endpoints de identidade dos provedores das credenciais encontradas (por exemplo, a API de identidade do GitHub ou da AWS). Remova a flag se chamadas de saída para terceiros não forem aceitáveis na sua rede de build.
  • --air-gapped no gate sbom garante zero tráfego externo de saída: sem consulta ao OSV e sem envio.
  • Revogue o acesso a qualquer momento revogando a chave de API no portal.

Pré-requisitos

Requisito Detalhe
Plano da WASViking Envios de SBOM e de secrets ativados (Pro ou superior).
Papel no portal Admin ou Manager, para emitir chaves de API.
Bitbucket Pipelines ativado no repositório, em Repository settings → Pipelines → Settings.
Permissão no Bitbucket Admin no repositório, para criar variáveis de repositório protegidas e fazer o commit do bitbucket-pipelines.yml.
Imagem de build Qualquer imagem Linux x86_64 com curl, sha256sum e dpkg-deb (ou ar, do binutils). A atlassian/default-image:5 tem todos eles.
Profundidade do clone clone: depth: full quando você analisa o histórico do git com --git. O Bitbucket faz clone raso (shallow) por padrão.
Manifestos do projeto Pelo menos um lockfile suportado: package-lock.json, yarn.lock, pnpm-lock.yaml, requirements.txt, Pipfile.lock, go.sum, composer.lock, pom.xml, Gemfile.lock, pubspec.lock. O lockfile precisa estar commitado no repositório.
Saída de rede HTTPS para api.wasviking.com e api.osv.dev na porta 443. Nenhuma conexão de entrada é necessária.

Usa GitLab CI, Jenkins, CircleCI ou qualquer outra ferramenta capaz de executar um binário Linux? Os comandos abaixo são idênticos. Só o dialeto do YAML muda. Comece por wasviking-sentinel em CI/CD.


Passo 1: Crie uma chave de API para o pipeline (portal)

Uma única chave de API cobre o build inteiro: ela autoriza o download do instalador do agente e os dois envios. Nenhum token de agente Sentinel entra aqui, isso pertence ao fluxo do túnel.

Vá em Settings → System Settings → API Keys e clique em + New Key.

Campo Valor
Label Algo que você ainda reconheça daqui a seis meses, por exemplo Bitbucket SCA, checkout-api. Use uma chave por repositório, para que revogá-la não derrube outros pipelines.
Scopes ci:scan (Trigger scans from a CI/CD pipeline, que também é o que autoriza o download do instalador), sca:submit (Send SBOMs from the Sentinel agent. OWASP A06) e secrets:submit (Send hard-coded credential matches from the Sentinel agent. OWASP A07).
Expiration 90 dias é um padrão sensato. Faça a rotação nessa cadência.

Salve e copie a chave, que aparece uma única vez. Você vai colá-la no Bitbucket no Passo 2 como WASV_SCA_API_KEY.

A WASViking autentica com o header Authorization: ApiKey <key>, e não Bearer. Os escopos podem ser ajustados depois com Edit, sem alterar o valor da chave, de modo que o pipeline continua funcionando.

System Settings, aba API Keys, com a lista de chaves Settings → System Settings → API Keys.

Seletor de escopos da chave de API com os escopos do pipeline selecionados Selecione os três escopos do pipeline ao criar a chave.


Passo 2: Guarde a chave como variável de repositório protegida

Nunca faça commit de uma chave no repositório. No Bitbucket, vá em Repository settings → Pipelines → Repository variables e adicione:

Nome Valor Secured
WASV_SCA_API_KEY A chave de API do Passo 1. Sim

Marque Secured (protegida) para que o valor seja mascarado no log do build e não possa ser lido de volta pela interface. Se vários repositórios compartilham uma mesma chave, uma variável de workspace funciona do mesmo jeito, embora uma chave por repositório deixe a revogação bem mais limpa.

Um comportamento do Bitbucket que vale prever: builds de pull request disparados a partir de um repositório que é um fork não recebem variáveis protegidas. A primeira linha do step abaixo é uma proteção que faz o build falhar imediatamente nesse caso, em vez de deixar o scan rodar sem autenticação e reportar um falso resultado limpo.


Passo 3: Adicione o pipeline

Crie o bitbucket-pipelines.yml na raiz do repositório:

image: atlassian/default-image:5

# Full Git history is required when using the secrets --git option.
clone:
  depth: full

definitions:
  steps:
    - step: &wasviking-security-scan
        name: WASViking SCA + SBOM + Secrets
        max-time: 20

        script:
          - test -n "$WASV_SCA_API_KEY"

          # Run from the repository root.
          - cd "$BITBUCKET_CLONE_DIR"

          # WASViking API endpoint.
          - export WASV_API_BASE="https://api.wasviking.com"

          # Install WASViking Sentinel.
          - |
            curl -fsSL \
              -H "Authorization: ApiKey $WASV_SCA_API_KEY" \
              "$WASV_API_BASE/api/v1/sentinel/install.sh" | sh

          - mkdir -p wasviking-reports

          # Generate CycloneDX SBOM, run SCA, and submit results.
          - |
            ./.wasviking/wasviking-sentinel sbom \
              --api "$WASV_API_BASE" \
              --api-key "$WASV_SCA_API_KEY" \
              --path . \
              --app-name "$BITBUCKET_REPO_FULL_NAME" \
              --app-version "$BITBUCKET_COMMIT" \
              --fail-on high \
              --submit \
              --out ./wasviking-reports

          # Scan the working tree and Git history for hard-coded secrets.
          - |
            ./.wasviking/wasviking-sentinel secrets \
              --api "$WASV_API_BASE" \
              --api-key "$WASV_SCA_API_KEY" \
              --path . \
              --git \
              --verify \
              --fail-on high \
              --submit \
              --out ./wasviking-reports

        artifacts:
          - wasviking-reports/**

pipelines:
  pull-requests:
    '**':
      - step: *wasviking-security-scan

  branches:
    main:
      - step: *wasviking-security-scan

  custom:
    wasviking-security-scan:
      - step: *wasviking-security-scan

Vale entender quatro escolhas desse arquivo antes de adaptá-lo:

  • clone: depth: full. A flag --git percorre o histórico de commits. Com o clone raso padrão do Bitbucket, o agente só enxerga os últimos commits, então uma credencial commitada meses atrás e depois removida da working tree continua invisível. Remova depth: full e --git juntos se você quer analisar apenas a árvore atual, o que deixa os builds mais rápidos.
  • A âncora YAML (&wasviking-security-scan). O step é declarado uma vez em definitions e referenciado três vezes. Pull requests e a main recebem o gate automaticamente, e a entrada custom permite que qualquer pessoa o execute sob demanda em Pipelines → Run pipeline, o que ajuda no primeiro rollout.
  • max-time: 20. Um teto em minutos para o step. Repositórios com histórico profundo ou muitos manifestos devem aumentá-lo. O agente tem os seus próprios timeouts, 5 minutos para o pipeline de SBOM e 10 para secrets, ambos ajustáveis com --timeout.
  • artifacts. O Bitbucket mantém wasviking-reports/** anexado ao build, então as saídas SARIF e JSON podem ser baixadas na aba Artifacts depois da execução.

Faça o commit do arquivo e o pipeline começa no próximo push ou pull request.


Passo 4: Flags dos comandos

sbom (SCA e SBOM)

wasviking-sentinel sbom [flags]
Flag Obrigatória Descrição
--api-key Sim Chave de API com o escopo sca:submit. Também lê WASV_API_KEY.
--api Não URL base da API da WASViking. Padrão: https://api.wasviking.com.
--path Não Diretório analisado recursivamente em busca de manifestos. Padrão: diretório atual.
--app-name Não Nome do projeto nos metadados CycloneDX. $BITBUCKET_REPO_FULL_NAME entrega workspace/repo. Informe-o: sem ele o agente recorre ao nome do repositório no CI, já que o diretório de checkout no Bitbucket sempre se chama build e daria um rótulo ruim para o inventário.
--app-version Não Versão do projeto nos metadados. $BITBUCKET_COMMIT amarra o SBOM ao commit exato.
--fail-on Não Menor severidade que faz o build falhar: critical, high, medium, low, none. Padrão: high.
--submit Não Envia o SBOM para a WASViking. Omita para uma execução apenas local.
--out Não Diretório de saída para o JSON CycloneDX e o SARIF. Padrão: diretório atual.
--no-osv Não Pula o enriquecimento com OSV e entrega um SBOM sem enriquecimento.
--from-cyclonedx Não Ingere um SBOM produzido por outra ferramenta em vez de gerar um.
--air-gapped Não Totalmente offline. Sem consulta ao OSV e sem envio.
--timeout Não Tempo máximo total (wall-clock) para o pipeline de SBOM. Padrão: 5 minutos.

Saídas: wasviking-sbom.cdx.json (CycloneDX 1.5) e wasviking-sbom.sarif (SARIF 2.1.0).

secrets

wasviking-sentinel secrets [flags]
Flag Obrigatória Descrição
--api-key Sim Chave de API com o escopo secrets:submit.
--api Não URL base da API da WASViking.
--path Não Diretório analisado recursivamente. Padrão: diretório atual.
--git Não Percorre também o histórico do git. Exige clone: depth: full.
--verify Não Confirma as ocorrências nos endpoints de identidade dos provedores, somente leitura.
--fail-on Não Mesma escala e mesmo padrão (high) do gate de SBOM.
--submit Não Envia as ocorrências mascaradas para a WASViking.
--out Não Diretório de saída.
--timeout Não Tempo máximo total (wall-clock). Padrão: 10 minutos.

Saídas: wasviking-secrets.json e wasviking-secrets.sarif.

Exit codes

O Bitbucket faz o step falhar em qualquer saída diferente de zero, então são estes códigos que transformam um achado em um merge bloqueado.

Código Significado
0 Nada no limite de --fail-on ou acima dele.
70 Gate de SCA: uma dependência sinalizada no KEV, no limite ou acima dele. Trate como urgente, é uma vulnerabilidade com exploração conhecida.
71 Gate de SCA: achados no limite ou acima dele, nenhum deles no KEV.
73 Gate de secrets: uma credencial confirmada como ativa pelo --verify.
74 Gate de secrets: ocorrências no limite ou acima dele que não foram verificadas.
79 Falha de cobertura: a raiz do scan não pôde ser percorrida, então nada foi analisado. Veja abaixo.
1 / 2 Erro operacional: manifesto ilegível, chave de API rejeitada, falha de rede no --submit.

Falha de cobertura (exit 79)

Um gate que não analisa nada não encontra nada e, sem uma verificação, isso se lê exatamente como uma execução limpa. O exit 79 separa as duas situações: o agente mede o que cobriu em relação ao que a raiz do scan realmente continha, e interrompe a execução em vez de reportar aprovação sobre uma varredura vazia.

Não é um achado, e não dispara em um repositório vazio nem em um sem manifesto suportado. Esses casos são percorridos corretamente e passam, e o log informa quantas entradas foram percorridas para que você veja a diferença.

O Bitbucket merece uma observação aqui. $BITBUCKET_CLONE_DIR é sempre /opt/atlassian/pipelines/agent/build, então nesta plataforma a raiz do scan se chama build, que também é um nome que o agente exclui dentro dos projetos. As exclusões valem apenas para subdiretórios, então o checkout é analisado por inteiro e o log registra que o nome da raiz foi reconhecido. Um diretório build/ dentro do seu repositório continua excluído, como deve ser. A referência completa está em Falhas de cobertura.

Política de fail-on

--fail-on define a menor severidade que faz o build falhar, e tudo acima dela também falha.

Configuração Comportamento
--fail-on none Nunca falha. Apenas relata, útil na primeira semana.
--fail-on critical Falha apenas em critical.
--fail-on high Falha em high e critical. É o padrão, e um bom padrão para pull requests.
--fail-on medium Falha em medium e acima. Mais rigoroso, mais atrito.
--fail-on low Postura máxima. Realista em projetos novos, sem dívida acumulada.

Um rollout que costuma sobreviver ao contato com uma equipe de verdade: comece com none em pull requests para ver o volume, passe para high quando o backlog estiver triado e mantenha a main mais rigorosa do que as feature branches.

Como ler os resultados

O portal é o sistema de registro. Os dados de dependências ficam em Inventory → SBOM e as ocorrências de credenciais em Inventory → Secrets, ambos com os achados promovidos vinculados à postura da sua organização.

Os arquivos SARIF são gravados para ferramentas que consomem o formato. O Bitbucket não ingere SARIF nativamente, então nesta plataforma eles são artefatos do build que você pode baixar ou entregar a outra ferramenta, e não uma camada de anotações no pull request. O log do build traz a linha de resumo, e o portal guarda o histórico.

O drift compara o conjunto de componentes deste envio com o do envio anterior que carrega o mesmo --app-name, e ignora --app-version por completo. Um commit que não altera nenhuma dependência não reporta drift, mesmo que a string de versão tenha mudado.

Isso faz de --app-name o valor a manter estável. Se ele varia entre execuções, cada envio inicia a sua própria linhagem, sem nada com que comparar, e o drift silenciosamente nunca dispara. Derivá-lo de $BITBUCKET_REPO_FULL_NAME, como faz o pipeline acima, mantém o valor constante durante toda a vida do repositório.

Modo air-gapped

Redes de build sem saída externa ainda conseguem produzir um SBOM:

./.wasviking/wasviking-sentinel sbom \
  --path . \
  --air-gapped \
  --out ./wasviking-reports

--air-gapped pula a consulta ao OSV e o envio, trabalhando com os dados de KEV embutidos. Use em build farms isoladas ou para validar localmente antes de entregar um artefato manualmente.

O que é e o que não é coletado

A WASViking não coleta o código-fonte do seu repositório, variáveis do repositório além da chave que você informa, arquivos fora de .wasviking/ nem qualquer dado de produção. O SBOM contém o grafo de dependências (nomes de pacotes, versões, licenças, hashes de manifestos). O gate de secrets envia um hash e uma prévia mascarada, nunca a credencial em si. Os dados são processados na região dos Estados Unidos, criptografados em trânsito (TLS 1.2+) e em repouso (AES-256), com retenção definida pelo seu plano. Um DPA e residência de dados na UE estão disponíveis sob solicitação. Consulte o Trust Center para o mapeamento completo de conformidade (ISO 27001, SOC 2, LGPD, GDPR, NIST SSDF, OWASP Top 10 A06/A07, OWASP DSOMM, elementos mínimos de SBOM da CISA).

Problemas comuns

Problema Causa provável
O step falha na primeira linha, antes de qualquer saída WASV_SCA_API_KEY não está definida. Em um pull request vindo de um fork, as variáveis protegidas não são entregues ao build.
HTTP 401 Unauthorized Chave revogada, expirada ou sem ci:scan, sca:submit ou secrets:submit. O header é Authorization: ApiKey <key>, e não Bearer.
HTTP 402 quota exceeded Cota mensal de envios atingida. Aguarde o próximo ciclo, faça upgrade ou adicione um pacote.
O scan de secrets não encontra nada no histórico Falta clone: depth: full, então o clone raso não tem histórico para percorrer.
neither dpkg-deb nor ar is available Uma imagem de build mínima (Alpine e similares). Instale o binutils ou troque o step para atlassian/default-image:5.
Erro no download do install.sh Política de rede bloqueando api.wasviking.com ou o bucket de releases.
Step encerrado aos 20 minutos Histórico profundo somado a --verify em um repositório grande. Aumente o max-time e o --timeout do agente, ou remova --verify nos pull requests e mantenha na main.
Exit 79 A raiz do scan não pôde ser percorrida. Compare a linha Root: com o layout do seu repositório e depois confira se o step consegue ler o checkout.
manifest not detected Nenhum lockfile suportado em --path. Faça o commit dos seus lockfiles.
Timeout do OSV api.osv.dev lento ou inacessível. Use --no-osv para um SBOM sem enriquecimento, ou --air-gapped.
Os achados diferem entre execuções Um lockfile regenerado durante o build. Instale com npm ci ou equivalente e faça o commit do lockfile.
Exit 70 inesperado em uma mudança pequena Uma nova dependência transitiva chegou pelo lockfile e corresponde ao CISA KEV. Inspecione com npm ls <package> ou equivalente.

Onde isto se encaixa na plataforma

  • O inventário de software fica em Inventory → SBOM, e as ocorrências de credenciais em Application Security → Hard-coded Secrets.
  • A versão deste mesmo pipeline para GitHub Actions é SCA, SBOM e secrets no CI/CD com GitHub Actions.
  • O gate de DAST a partir da nuvem é um terceiro subcomando do mesmo binário, com o mesmo modelo de chave de API. Veja DAST em CI/CD com Bitbucket Pipelines para o exemplo completo no Bitbucket, wasviking-sentinel em CI/CD para a referência e DAST em CI/CD com GitHub Actions para a versão do GitHub.
  • Prefere não mudar nada no pipeline? O Code Security executa os mesmos mecanismos de SBOM e de secrets no lado do servidor, nos repositórios que você conecta pelo GitHub App ou pelo Bitbucket OAuth, na cadência do seu plano e a cada push; o gate no pipeline continua sendo o caminho para bloquear um build.
  • O roteamento de alertas está documentado em Slack e Teams e Webhooks.