Pular para o conteúdo principal

Desafio 15: Gerenciamento de dependências e verificação de vulnerabilidades

Plataforma: ambas

Este desafio cobre fluxos de trabalho de segurança de dependências tanto no GitHub quanto no Azure DevOps.

Habilidades do exame

  • Recomendar ferramentas de gerenciamento de pacotes incluindo GitHub Packages e Azure Artifacts
  • Projetar e implementar feeds e views de pacotes para pacotes locais e upstream

Cenário

A equipe de segurança da Contoso executa uma auditoria trimestral e descobre que 3 dos 15 microsserviços em produção dependem de uma biblioteca com um CVE crítico (CVE-2024-29041, uma vulnerabilidade de path traversal no Express.js). Os problemas são:

  • Nenhum processo automatizado detecta dependências vulneráveis
  • Desenvolvedores não sabem quais dependências transitivas apresentam risco
  • Não há política para conformidade de licenças (algumas equipes incluíram acidentalmente código licenciado sob GPL em serviços proprietários)
  • A remediação leva semanas porque ninguém sabe quais serviços são afetados

Você deve implementar uma estratégia abrangente de gerenciamento de dependências e verificação de vulnerabilidades.

Tarefas

Tarefa 1: Configurar Dependabot para atualizações automáticas de dependências

O Dependabot abre automaticamente pull requests para atualizar dependências em um cronograma.

Passo 1: Criar o arquivo de configuração do Dependabot

No seu repositório, crie .github/dependabot.yml:

version: 2
updates:
# npm dependencies
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "09:00"
timezone: "America/New_York"
open-pull-requests-limit: 10
reviewers:
- "contoso/backend-team"
labels:
- "dependencies"
- "automated"
commit-message:
prefix: "deps"
include: "scope"
groups:
dev-dependencies:
dependency-type: "development"
update-types:
- "minor"
- "patch"
production-minor:
dependency-type: "production"
update-types:
- "minor"
- "patch"

# NuGet dependencies
- package-ecosystem: "nuget"
directory: "/src/Contoso.Api"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
ignore:
- dependency-name: "Microsoft.Extensions.*"
update-types: ["version-update:semver-major"]

# Docker base images
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
labels:
- "docker"
- "dependencies"

# GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "ci"
- "dependencies"

Passo 2: Verificar se o Dependabot está ativo

Após enviar a configuração:

gh api /repos/contoso/auth-service/vulnerability-alerts --method PUT

Verifique o status do Dependabot:

gh api /repos/contoso/auth-service/dependabot/alerts \
--jq '.[0:5] | .[] | {package: .security_advisory.summary, severity: .security_advisory.severity, state: .state}'

Tarefa 2: Configurar alertas de segurança do Dependabot

Alertas de segurança diferem das atualizações de versão. Eles são acionados imediatamente quando um novo CVE é publicado que afeta sua árvore de dependências.

Passo 1: Habilitar alertas de segurança para a organização

gh api --method PUT /orgs/contoso/dependabot/alerts

Habilite para todos os repositórios:

gh api --method PUT /orgs/contoso \
--field dependabot_security_updates_enabled_for_new_repositories=true \
--field dependency_graph_enabled_for_new_repositories=true \
--field dependabot_alerts_enabled_for_new_repositories=true

Passo 2: Listar alertas de segurança atuais entre repositórios

gh api /orgs/contoso/dependabot/alerts \
--jq '.[] | select(.state == "open") | {repo: .repository.name, package: .dependency.package.name, severity: .security_advisory.severity, cve: .security_advisory.cve_id}'

Filtre apenas alertas de severidade crítica e alta:

gh api "/orgs/contoso/dependabot/alerts?severity=critical,high&state=open" \
--jq '.[] | "\(.repository.name): \(.dependency.package.name) - \(.security_advisory.severity) - \(.security_advisory.cve_id)"'

Passo 3: Dispensar um alerta (falso positivo)

gh api --method PATCH /repos/contoso/auth-service/dependabot/alerts/42 \
--field state=dismissed \
--field dismissed_reason=tolerable_risk \
--field dismissed_comment="This code path is not reachable in our configuration"

Tarefa 3: Integração do Azure Artifacts com Defender for DevOps

Passo 1: Habilitar Microsoft Defender for DevOps

Conecte sua organização Azure DevOps ao Defender for Cloud:

az security devops azuredevopsorg create \
--name contoso-ado \
--resource-group rg-security \
--org-name contoso

Passo 2: Configurar a extensão Microsoft Security DevOps do Azure DevOps

Adicione a tarefa de verificação de segurança ao seu Azure Pipeline:

trigger:
- main

pool:
vmImage: ubuntu-latest

steps:
- task: MicrosoftSecurityDevOps@1
displayName: 'Run security analysis'
inputs:
categories: 'dependencies'
tools: 'eslint,trivy'

- task: PublishBuildArtifacts@1
inputs:
pathToPublish: $(System.DefaultWorkingDirectory)/.gdn
artifactName: security-results

Passo 3: Configurar alertas de vulnerabilidade de pacotes do Azure Artifacts

Habilite a verificação de pacotes no seu feed do Azure Artifacts:

az rest --method patch \
--uri "https://feeds.dev.azure.com/contoso/ContosoServices/_apis/packaging/feeds/contoso-packages?api-version=7.1-preview.1" \
--body '{
"badgesEnabled": true,
"hideDeletedPackageVersions": true
}'

Tarefa 4: Verificação de conformidade de licenças

Passo 1: Criar uma política de licenças com GitHub Actions

Crie .github/workflows/license-check.yml:

name: License compliance check
on:
pull_request:
paths:
- 'package.json'
- 'package-lock.json'
- '**/*.csproj'

jobs:
license-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install license checker
run: npm install -g license-checker

- name: Check npm licenses
run: |
license-checker --production --failOn \
"GPL-2.0-only;GPL-3.0-only;AGPL-3.0-only;SSPL-1.0" \
--summary

- name: Check for unknown licenses
run: |
UNKNOWN=$(license-checker --production --unknown | wc -l)
if [ "$UNKNOWN" -gt 1 ]; then
echo "ERROR: Found packages with unknown licenses"
license-checker --production --unknown
exit 1
fi

Passo 2: Validação de licenças NuGet

Para projetos .NET, use o dotnet-project-licenses:

dotnet tool install --global dotnet-project-licenses

dotnet-project-licenses \
--input ./src/Contoso.Api/Contoso.Api.csproj \
--output-directory ./license-report \
--banned-license-types ./banned-licenses.json

Crie o banned-licenses.json:

{
"banned": [
"GPL-2.0-only",
"GPL-3.0-only",
"AGPL-3.0-only",
"SSPL-1.0"
]
}

Tarefa 5: Criar um workflow de revisão de dependências no GitHub Actions

A action de revisão de dependências é executada em pull requests e bloqueia o merge se novas dependências introduzirem vulnerabilidades ou licenças não permitidas.

Crie .github/workflows/dependency-review.yml:

name: Dependency review
on:
pull_request:
branches: [main]

permissions:
contents: read
pull-requests: write

jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Dependency review
uses: actions/dependency-review-action@v4
with:
fail-on-severity: high
deny-licenses: GPL-2.0-only, GPL-3.0-only, AGPL-3.0-only
allow-ghsas: GHSA-xxxx-yyyy-zzzz
comment-summary-in-pr: always
warn-only: false
base-ref: ${{ github.event.pull_request.base.sha }}
head-ref: ${{ github.event.pull_request.head.sha }}

Tarefa 6: Implementar listas de permissão e bloqueio de dependências

Passo 1: Lista de permissão npm com .npmrc

Restrinja registros apenas a fontes aprovadas:

@contoso:registry=https://npm.pkg.github.com
registry=https://pkgs.dev.azure.com/contoso/ContosoServices/_packaging/contoso-packages/npm/registry/

Isso impede que desenvolvedores busquem acidentalmente pacotes diretamente do npm público.

Passo 2: Mapeamento de fontes de pacotes NuGet

No nuget.config, mapeie padrões de pacotes específicos para fontes específicas:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="contoso-packages" value="https://pkgs.dev.azure.com/contoso/ContosoServices/_packaging/contoso-packages/nuget/v3/index.json" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<packageSourceMapping>
<packageSource key="contoso-packages">
<package pattern="Contoso.*" />
</packageSource>
<packageSource key="nuget.org">
<package pattern="Microsoft.*" />
<package pattern="System.*" />
<package pattern="Newtonsoft.*" />
</packageSource>
</packageSourceMapping>
</configuration>

Passo 3: Lista de bloqueio de dependências no GitHub Actions

Bloqueie pacotes específicos conhecidos como maliciosos de serem introduzidos:

- name: Check for banned packages
run: |
BANNED_PACKAGES=("event-stream" "flatmap-stream" "ua-parser-js@0.7.29")
LOCKFILE="package-lock.json"

for pkg in "${BANNED_PACKAGES[@]}"; do
if grep -q "\"$pkg\"" "$LOCKFILE"; then
echo "ERROR: Banned package found: $pkg"
exit 1
fi
done
echo "No banned packages detected"

Exercícios de quebra e conserto

Cenário: PR do Dependabot quebra o build devido a breaking change

O Dependabot abre um PR para atualizar @contoso/auth-sdk de 1.2.0 para 2.0.0. O pipeline de CI falha com:

TypeError: AuthClient.validateToken is not a function
at Object.<anonymous> (src/middleware/auth.js:15:32)

O PR do Dependabot é um de 12 atualizações de dependências abertas. A equipe precisa de uma estratégia para lidar com isso.

Mostrar solução

Causa raiz: O Dependabot atualizou um pacote através de uma fronteira de versão major, introduzindo uma alteração quebrante na API. O método validateToken foi renomeado para verifyToken na versão 2.0.0.

Correção imediata: Feche o PR do Dependabot e fixe na faixa de versão segura:

gh pr close 847 --comment "Breaking change in v2.0.0. Pinning to 1.x until migration is complete."

Passo 1: Prevenir bumps de versão major via configuração do Dependabot

Atualize o .github/dependabot.yml para ignorar atualizações de versão major para pacotes críticos:

updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
ignore:
- dependency-name: "@contoso/auth-sdk"
update-types: ["version-update:semver-major"]

Passo 2: Fixar a faixa de versão no package.json

Use uma faixa tilde para permitir apenas atualizações de patch:

{
"dependencies": {
"@contoso/auth-sdk": "~1.2.0"
}
}

Ou use uma faixa caret para permitir minor e patch, mas não major:

{
"dependencies": {
"@contoso/auth-sdk": "^1.2.0"
}
}

Passo 3: Criar um plano de migração para a atualização major

Rastreie a alteração quebrante como um item de trabalho separado em vez de depender do Dependabot:

gh issue create \
--title "Migrate to @contoso/auth-sdk v2.0.0" \
--body "auth-sdk 2.0.0 renames validateToken to verifyToken. All services using auth middleware need updating." \
--label "breaking-change,dependencies" \
--assignee "@contoso/backend-team"

Passo 4: Adicionar verificações de CI que detectem breaking changes antecipadamente

Certifique-se de que sua suíte de testes cubra os pontos de integração. Adicione um smoke test:

const { AuthClient } = require('@contoso/auth-sdk');
const client = new AuthClient();
// Verify expected API surface exists
assert(typeof client.validateToken === 'function',
'auth-sdk API contract violated: validateToken must exist');

Passo 5: Agrupar atualizações de dependências relacionadas

Configure o Dependabot para agrupar atualizações minor/patch para que breaking changes fiquem isoladas:

groups:
contoso-internal:
patterns:
- "@contoso/*"
update-types:
- "minor"
- "patch"

Isso garante que bumps de versão major apareçam como PRs individuais que são fáceis de identificar e adiar.

Verificação de conhecimento

1. Uma configuração do Dependabot tem 'schedule.interval: "weekly"' e 'open-pull-requests-limit: 5'. O que acontece quando existem 8 dependências desatualizadas?

2. Qual action do GitHub Actions bloqueia o merge de PR quando uma nova dependência introduz uma vulnerabilidade conhecida?

3. No mapeamento de fontes de pacotes NuGet, o que acontece se um pacote não corresponder a nenhum padrão configurado?

4. Uma equipe quer remediar automaticamente CVEs críticos mas revisar manualmente todas as outras atualizações de dependências. Qual configuração do Dependabot alcança isso?

Limpeza

Remova a configuração do Dependabot:

rm .github/dependabot.yml
git add -A && git commit -m "Remove Dependabot configuration"
git push origin main

Remova os arquivos de workflow:

rm .github/workflows/license-check.yml
rm .github/workflows/dependency-review.yml
git add -A && git commit -m "Remove dependency scanning workflows"
git push origin main

Desabilite os alertas do Dependabot para o repositório:

gh api --method DELETE /repos/contoso/auth-service/vulnerability-alerts

Remova a ferramenta de verificação de licenças:

npm uninstall -g license-checker
dotnet tool uninstall --global dotnet-project-licenses

Remova o mapeamento de fontes NuGet (restaure o nuget.config original):

git checkout HEAD -- nuget.config