Validação de Patch Pós-Aplicação
Valide um patch de segurança contra o bug relatado e o código ao redor que ele afeta. Forneça ao autor do patch falhas reprodutíveis para corrigir e identifique o que ainda precisa de teste. Aplique as mesmas verificações a patches humanos e de agentes. O diff, o autor, a implementação original e a prova de conceito original sozinhos não podem estabelecer a correção.
Quando Usar
- Uma correção de segurança, commit de correção, arquivo de patch ou pull request já existe.
- Um patch gerado por IA precisa de validação antes da revisão humana ou mesclagem.
- Uma correção pode cobrir um caminho de exploração enquanto perde variantes da mesma causa raiz.
- Uma correção de segurança pode alterar o comportamento legítimo ou introduzir uma nova vulnerabilidade.
- O autor do patch precisa de falhas concretas e lacunas de cobertura antes de uma nova revisão.
Quando NÃO Usar
- Nenhum patch existe ainda; use descoberta de vulnerabilidade ou implementação de correção primeiro.
- A tarefa é revisar um achado de auditoria contra um relatório sem executar evidências do patch.
- A tarefa é apenas converter um achado em um teste permanente do projeto.
- O alvo é remoto ou produção. Esta skill executa código e testes locais apenas.
- O usuário não autorizou a execução do código ou suíte de testes do repositório.
Início Rápido
-
Fixe a base vulnerável e a entrada corrigida. Prefira commits imutáveis. Para trabalho não commitado, crie um arquivo de patch binário primeiro; não valide na árvore de trabalho do usuário.
-
Estruture um plano fixado:
uv run {baseDir}/scripts/post_patch_validation.py scaffold \ --repo . \ --base-ref <vulnerable-ref> \ --patched-ref <patched-ref> \ --finding-id <stable-id> \ --finding-summary "<root cause and impact>" \ --evidence-level runtime \ --output post-patch-validation/plan.jsonUse
--patch-file <path>em vez de--patched-refpara um artefato de patch. Escolha o nível de evidência mais alto honesto:sourceapenas para invariantes de fonte/patch,buildquando o código alvo é compilado ou analisado, mas o comportamento relatado não é executado, ouruntimequando as verificações executam o comportamento relatado e suas asserções de segurança. -
Inspecione o achado, diff, chamadores, caminhos irmãos, caminhos de limpeza/erro e testes existentes. Popule
checksno plano gerado. Executeprint-schemapara o esquema estrutural:uv run {baseDir}/scripts/post_patch_validation.py print-schema -
Execute
validate-planpara a validação completa, incluindo cobertura, restrições de comando, e entradas fixadas, antes de executar o código:uv run {baseDir}/scripts/post_patch_validation.py validate-plan \ --plan post-patch-validation/plan.json -
Execute o plano de evidências:
uv run {baseDir}/scripts/post_patch_validation.py run \ --plan post-patch-validation/plan.json \ --output post-patch-validation/results -
Reporte
result.json,report.md, o nível de evidência e aassessmentcompleta. Retorne cada achado ao autor do patch com seu ID de verificação, asserção e logs salvos. Identifique cada lacuna de validação separadamente, incluindo lacunas que coexistem com achados suportados. Após o autor revisar o patch, fixe as novas entradas e salve uma nova execução de validação. Preserve a evidência anterior. Verificações fornecidas que passam ainda requerem revisão humana antes da aceitação.
Contrato de Evidências
O executor rejeita planos incompletos. Forneça pelo menos uma verificação de cada tipo:
| Tipo | Observação obrigatória |
|---|---|
control | Harness benigno tem sucesso tanto na base quanto no patch |
exploit | Asserção de segurança original falha na base e tem sucesso no patch |
variant | Uma variante distinta da causa raiz falha na base e tem sucesso no patch |
behavior | Comportamento não afetado tem sucesso com saída selecionada byte-idêntica |
regression | Verificação de regressão não relacionada à segurança tem sucesso em ambas as revisões |
security | Verificação de vulnerabilidade adjacente/nova tem sucesso na base e no patch |
suite | Suíte existente do projeto, sanitizer ou campanha de fuzz determinística tem sucesso no patch |
Comandos são arrays argv, nunca strings de shell. Coloque configuração complexa em um script verificado ou artefato do plano
e invoque-o com {plan_dir}. O executor fixa entradas de locale/timezone/hash-seed, executa
verificações em ordem lexical de ID, registra stdout/stderr bruto e nunca edita a árvore de trabalho original.
O timeout_seconds de cada verificação padrão é 300 e aceita inteiros de 1 a 3600.
Exceder o tempo limite deixa uma lacuna de validação. Um tempo limite sozinho não estabelece uma regressão.
Cada plano também contém um array submodules ordenado ([] quando nenhum). O scaffolding infere Gitlinks
afetados a partir do inventário de arquivos alterados. O executor inicializa esses commits fixados dos
objetos do módulo Git existentes do repositório de origem, nunca de URLs de rede .gitmodules; inicialize
ou busque-os no repositório de origem antes da validação.
Verificações de exploração e variante devem provar que foram executadas
Uma saída diferente de zero não significa que a vulnerabilidade foi reproduzida. Um erro de importação, uma falha de
build, uma dependência ausente e uma asserção de segurança falha todos saem com diferente de zero e são indistinguíveis para o
executor. Toda verificação exploit e variant deve imprimir e liberar PPV_REACHED imediatamente
antes de avaliar sua asserção, em ambas as revisões:
"argv": ["python3", "-c", "import app; value = app.render('<'); print('PPV_REACHED', flush=True); assert value == '<'"]
O token também está no ambiente como PPV_REACHED_MARKER. Ele deve ir para o stdout, como uma linha
própria. Stderr não é escaneado, porque um traceback SyntaxError do Python ecoa a fonte
ofensora e, de outra forma, satisfaria a verificação para um harness que não executou nada. Uma execução sem ele
deixa uma lacuna marker_missing. Achados independentes de outras verificações permanecem no resultado.
Libere explicitamente: um harness cujo payload causa segfault ou chama _exit perde a saída em buffer e perde sua própria evidência.
Essas verificações também são executadas cegas para o lado. {side} não é expandido para elas, PPV_SIDE está ausente em
seu ambiente, o diretório de checkout é nomeado aleatoriamente, e o validador do plano rejeita qualquer
verificação exploit ou variant cujo argv ou env mencione qualquer um deles. Uma asserção que pode ver em qual
revisão está pode fazer asserções nessa em vez de no código, que é a maneira mais barata possível
de fingir uma reprodução seguida de uma correção.
Ambiente
As verificações são executadas sob um ambiente mínimo fixo: PATH, HOME e um punhado de chaves temporárias/de usuário,
mais LANG/LC_ALL=C, TZ=UTC, PYTHONHASHSEED=0, NO_COLOR, TERM=dumb. Todo o resto no
ambiente do chamador é descartado. Toolchains que precisam de mais obtêm isso explicitamente:
uv run {baseDir}/scripts/post_patch_validation.py run \
--plan post-patch-validation/plan.json \
--output post-patch-validation/results \
--allow-env JAVA_HOME --allow-env CARGO_HOME
Nomes e valores encaminhados são registrados em result.json. Uma variável solicitada que não está definida é um
erro, não uma string vazia. Duas classes são recusadas imediatamente: nomes que são lidos como credenciais
(*SECRET*, *TOKEN*, *API_KEY*, …), porque o valor seria escrito no resultado; e
nomes que mudam o que é executado (LD_PRELOAD, BASH_ENV, NODE_OPTIONS, GIT_SSH_COMMAND, …),
porque essas variáveis podem alterar qual código é executado.
As variáveis fixas do executor e todo nome PPV_* também são reservados e não podem ser encaminhados.
Substituidores expandidos em argv e valores env por verificação: {checkout} (a revisão em teste),
{plan_dir} (uma cópia isolada dos artefatos do plano para aquela invocação), {scratch} (um
diretório opaco novo para aquela invocação de verificação) e
{side} (base ou patched, e não disponível para verificações exploit/variant). Os mesmos valores
chegam como PPV_CHECKOUT, PPV_PLAN_DIR, PPV_SCRATCH, PPV_SIDE e PPV_CASE_ID. Escreva apenas
sob {scratch}; o caminho do diretório de evidências não é passado para as verificações. As invocações de base e patch
não compartilham raízes de scratch, plano ou árvore de trabalho gerenciadas pelo executor. Após cada invocação sair, seu
diretório scratch é arquivado sob o caminho determinístico results/scratch/<check-id-and-side>, sua
cópia privada do plano é descartada, e todo elemento argv legível que resolve para um arquivo é hashado
em argv_files. Arquivos dentro das raízes de plano ou checkout isoladas são adicionalmente retidos sob
results/helpers/<sha256> até 16 MiB; o registro explica por que qualquer outro arquivo não foi arquivado.
Use um diretório dedicado para plan.json: seus arquivos e diretórios irmãos são copiados para cada
invocação {plan_dir}. Mantenha o código auxiliar sob o diretório checks/ desse diretório ou verificado
no repositório alvo para que seus bytes sejam revisáveis. O plano de máquina contendo pinos de commit,
o diretório de saída atual e árvores de resultado anteriores detectadas são excluídos; symlinks são rejeitados.
O snapshot limpo permanece apenas na memória do executor, e
os lados de exploração/variante são executados em ordem aleatória enquanto os nomes dos arquivos de evidência permanecem determinísticos.
Stdout/stderr usam descritores de captura anônimos ou nomeados aleatoriamente e são copiados para os arquivos de evidência
nomeados apenas após a saída do processo filho, então a inspeção de fd não pode revelar o rótulo do lado.
Este isolamento não é uma sandbox de host: as verificações são executadas com os privilégios do chamador e um auxiliar malicioso poderia usar estado externo arbitrário ou inferir deliberadamente a revisão a partir da fonte ou metadados Git. Inspecione os artefatos auxiliares endereçados por conteúdo e use uma sandbox de SO/contêiner quando o código de verificação em si não for confiável.
As árvores de trabalho de validação ativas são bloqueadas pelo Git com tokens de proprietário aleatórios apoiados por bloqueios de
arquivo do kernel, então outro validador concorrente não pode podá-las e a reutilização de PID não pode se passar por um proprietário. Se o
executor for morto à força, a próxima execução desbloqueia registros de proprietário obsoletos. Para
recuperação manual, inspecione git worktree list, então use git worktree unlock <path> e
git worktree remove --force <path> (ou git worktree prune após o caminho ter sumido).
Leia evidence-model.md ao projetar cobertura, selecionar variantes ou interpretar achados e lacunas de validação. Não o leia para execução de CLI de rotina.
Regras de Cobertura
- Derive variantes da causa raiz, não mutações cosméticas da carga original.
- Enumere locais de chamada irmãos, callbacks/saídas alternativas, caminhos de erro, teardown, propriedade, serialização e valores de limite tocados pela correção.
- Faça cada teste de exploração ou variante afirmar o comportamento seguro. Ele deve falhar na base vulnerável; um teste que passa em ambas as revisões não prova nada sobre a correção. Leia o stderr do lado base e confirme que a falha é a asserção que você escreveu, não um harness que nunca chegou lá.
- Mantenha as asserções de exploração e variante limitadas ao invariante de segurança. Teste vivacidade, tipos/mensagens de erro exatos,
tempo e compatibilidade separadamente como verificações
behaviorouregression; caso contrário, uma alteração de contrato não relacionada pode se passar por prova de que a vulnerabilidade permanece. - Mantenha o harness
controlbenigno e faça-o exercitar o componente alterado. Ele estabelece que o harness funciona em ambas as revisões. Controles falhos deixam lacunas e impedem atribuir outras falhas ao patch. As observações brutas permanecem disponíveis para revisão. - Use
behaviorapenas para comportamento que deve permanecer inalterado. A comparação exata de saída é deliberada; mova valores instáveis para trás de um harness de teste determinístico em vez de normalizá-los em prosa. - Faça as verificações
securitypassarem na base vulnerável antes de tratar uma falha corrigida como recém- introduzida. Uma linha de base falha deixa atribuição não resolvida. - Não edite o patch durante a validação. Retorne falhas ao autor do patch e inicie uma nova execução recém-fixada.
Lendo o Resultado
O esquema result.json 2.0 contém uma assessment com status, findings, gaps e
human_review_required. O status é complete quando todas as verificações necessárias produziram evidências utilizáveis,
mesmo que algumas verificações tenham encontrado falhas. O status é incomplete quando qualquer lacuna permanece.
Findings nomeiam o ID da verificação, o tipo de verificação e a expectativa falha. Gaps nomeiam o ID da verificação e a evidência ausente, com um ID de verificação nulo para problemas de nível de execução, como falhas de limpeza.
Verificações de suíte são executadas na revisão corrigida primeiro. Uma falha completa aciona a mesma verificação na linha de base. Se a linha de base passar, reporte a falha após o patch. Se ambas falharem, preserve ambos os logs e reporte que a atribuição não está resolvida. Não presuma que códigos de saída correspondentes significam a mesma falha.
O executor sai com 0 para verificações completas sem achados, 1 para verificações completas com achados, 10 para validação incompleta e 64 para entradas inválidas. Leia o artefato mesmo após saída 10: ele pode conter achados suportados junto com lacunas. Evidências de fonte ou build não podem estabelecer comportamento em tempo de execução. Declare o nível de evidência junto com qualquer resultado de aprovação.
Fluxo de Trabalho Dinâmico do Claude
O Claude Code expõe o fluxo de trabalho empacotado como /post-patch-validation:validate-patch.
Para passar entradas estruturadas através da ferramenta Workflow, use o nome sem a barra inicial:
Workflow({
name: 'post-patch-validation:validate-patch',
args: {
finding: '<finding text or local path>',
baseRef: '<vulnerable-ref>',
patchRef: '<patched-ref>',
workdir: 'post-patch-validation',
},
})
Use patchFile em vez de patchRef quando apropriado. O fluxo de trabalho usa lentes de cobertura fixas
para propor verificações e um executor fixo para executar esta skill. Agentes podem escrever
artefatos de teste. O executor Python registra achados e lacunas, e revisores reportam cobertura ou evidência
preocupações separadamente. NEEDS_REPAIR retorna falhas suportadas mesmo quando outras verificações deixaram lacunas.
BLOCKED significa que a evidência está incompleta sem uma falha suportada. Verificações de aprovação avançam para
READY_FOR_HUMAN_REVIEW apenas após ambas as revisões de evidência aprovarem, caso contrário REVIEW_REQUIRED.
O fluxo de trabalho não pode fazer perguntas após o lançamento, então passe toda entrada antecipadamente.
Racionalizações a Rejeitar
| Racionalização | Correção requerida [...]
[...truncado para tradução]