Validación Posterior al Parche
Valida un parche de seguridad contra el error reportado y el código circundante que afecta. Proporciona al autor del parche fallos reproducibles para corregir e identifica qué aún necesita pruebas. Aplica las mismas verificaciones a parches humanos y de agente. El diff, el autor, la implementación ascendente y la prueba de concepto original por sí solos no pueden establecer la corrección.
Cuándo Usarlo
- Ya existe una corrección de seguridad, un commit de remediación, un archivo de parche o una solicitud de extracción.
- Un parche generado por IA necesita validación antes de la revisión humana o la fusión.
- Una corrección puede cubrir una ruta de exploit mientras omite variantes de la misma causa raíz.
- Una corrección de seguridad puede alterar el comportamiento legítimo o introducir una nueva vulnerabilidad.
- El autor de un parche necesita fallos concretos y brechas de cobertura antes de otra revisión.
Cuándo NO Usarlo
- Aún no existe un parche; use primero el descubrimiento de vulnerabilidad o la implementación de la corrección.
- La tarea es revisar un hallazgo de auditoría contra un informe sin ejecutar evidencia del parche.
- La tarea es solo convertir un hallazgo en una prueba permanente del proyecto.
- El objetivo es remoto o de producción. Esta habilidad solo ejecuta código y pruebas locales.
- El usuario no ha autorizado la ejecución del código o suite de pruebas del repositorio.
Inicio Rápido
-
Fije la base vulnerable y la entrada parcheada. Prefiera commits inmutables. Para trabajo no confirmado, cree primero un archivo de parche binario; no valide en el árbol de trabajo del usuario.
-
Andamie un plan fijado:
uv run {baseDir}/scripts/post_patch_validation.py scaffold \ --repo . \ --base-ref <ref-vulnerable> \ --patched-ref <ref-parcheada> \ --finding-id <id-estable> \ --finding-summary "<causa raíz e impacto>" \ --evidence-level runtime \ --output post-patch-validation/plan.jsonUse
--patch-file <ruta>en lugar de--patched-refpara un artefacto de parche. Elija el nivel de evidencia honesto más alto:sourcesolo para invariantes de fuente/parche,buildcuando el código objetivo se compila o analiza pero el comportamiento reportado no se ejecuta, oruntimecuando las comprobaciones ejecutan el comportamiento reportado y sus aserciones de seguridad. -
Inspeccione el hallazgo, el diff, los llamadores, las rutas hermanas, las rutas de limpieza/error y las pruebas existentes. Complete
checksen el plan generado. Ejecuteprint-schemapara el esquema estructural:uv run {baseDir}/scripts/post_patch_validation.py print-schema -
Ejecute
validate-planpara la validación completa, incluyendo cobertura, restricciones de comandos, y entradas fijadas, antes de ejecutar código:uv run {baseDir}/scripts/post_patch_validation.py validate-plan \ --plan post-patch-validation/plan.json -
Ejecute el plan de evidencia:
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, el nivel de evidencia y laassessmentcompleta. Devuelva cada hallazgo al autor del parche con su ID de verificación, aserción y registros guardados. Identifique cada brecha de validación por separado, incluyendo brechas que coexistan con hallazgos compatibles. Después de que el autor revise el parche, fije las nuevas entradas y guarde una ejecución de validación nueva. Preserve la evidencia anterior. Las verificaciones suministradas que pasan aún requieren revisión humana antes de la aceptación.
Contrato de Evidencia
El ejecutor rechaza planes incompletos. Proporcione al menos una verificación de cada tipo:
| Tipo | Observación requerida |
|---|---|
control | El harness benigno tiene éxito tanto en base como en parche |
exploit | La aserción de seguridad original falla en base y tiene éxito en parche |
variant | Una variante de causa raíz distinta falla en base y tiene éxito en parche |
behavior | El comportamiento no afectado tiene éxito con salida seleccionada byte-idéntica |
regression | La verificación de regresión no dirigida específica tiene éxito en ambas revisiones |
security | La verificación de vulnerabilidad adyacente/nueva tiene éxito en base y parche |
suite | La suite de pruebas existente, el sanitizador o la campaña de fuzzing determinista tienen éxito en el parche |
Los comandos son arreglos argv, nunca cadenas de shell. Coloque la configuración compleja en un script de artefacto verificado o del plan
e invóquelo con {plan_dir}. El ejecutor fija las entradas locale/timezone/hash-seed, ejecuta
las verificaciones en orden ID léxico, registra stdout/stderr sin procesar y nunca edita el árbol de trabajo original.
El timeout_seconds de cada verificación tiene como valor predeterminado 300 y acepta enteros de 1 a 3600.
Superar el tiempo de espera deja una brecha de validación. Un tiempo de espera por sí solo no establece una regresión.
Cada plan también contiene un arreglo submodules ordenado ([] cuando no hay ninguno). El andamiaje infiere los Gitlinks afectados
del inventario de archivos modificados. El ejecutor inicializa esos commits fijados de los objetos de módulo Git existentes del repositorio fuente,
nunca de las URL de red de .gitmodules; inicialícelos o búsquelos en el repositorio fuente antes de la validación.
Las verificaciones de exploit y variante deben demostrar que se ejecutaron
Una salida distinta de cero no significa que la vulnerabilidad se haya reproducido. Un error de importación, una compilación fallida, una
dependencia faltante y una aserción de seguridad fallida tienen salida distinta de cero y son indistinguibles para el
ejecutor. Cada verificación exploit y variant debe imprimir y vaciar PPV_REACHED inmediatamente
antes de evaluar su aserción, en ambas revisiones:
"argv": ["python3", "-c", "import app; value = app.render('<'); print('PPV_REACHED', flush=True); assert value == '<'"]
El token también está en el entorno como PPV_REACHED_MARKER. Debe llegar a stdout, como una línea
propia. Stderr no se escanea, porque un traceback de SyntaxError de Python hace eco de la fuente ofensiva
y, de lo contrario, satisfaría la verificación para un harness que no ejecutó nada. Una ejecución sin él
deja una brecha marker_missing. Los hallazgos independientes de otras verificaciones permanecen en el resultado.
Vació explícitamente: un harness cuya carga útil provoca un segfault o llama a _exit pierde la salida almacenada en búfer y pierde su propia evidencia.
Estas verificaciones también se ejecutan ciegas al lado. {side} no se expande para ellas, PPV_SIDE está ausente de
su entorno, el directorio de checkout tiene un nombre aleatorio y el validador del plan rechaza cualquier
verificación exploit o variant cuyo argv o env lo mencione. Una aserción que puede ver en qué
revisión se encuentra puede afirmar sobre eso en lugar de sobre el código, que es la forma más barata posible
de falsificar una reproducción seguida de una corrección.
Entorno
Las verificaciones se ejecutan bajo un entorno mínimo fijo: PATH, HOME y un puñado de claves temporales/de usuario,
más LANG/LC_ALL=C, TZ=UTC, PYTHONHASHSEED=0, NO_COLOR, TERM=dumb. Todo lo demás en
el entorno de la persona que llama se elimina. Las cadenas de herramientas que necesitan más lo reciben explícitamente:
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
Los nombres y valores reenviados se registran en result.json. Una variable solicitada que no está establecida es un
error, no una cadena vacía. Dos clases se rechazan de plano: los nombres que se leen como credenciales
(*SECRET*, *TOKEN*, *API_KEY*, …), porque el valor se escribiría en el resultado; y
los nombres que cambian lo que se ejecuta (LD_PRELOAD, BASH_ENV, NODE_OPTIONS, GIT_SSH_COMMAND, …),
porque esas variables pueden cambiar qué código se ejecuta.
Las variables fijas del ejecutor y cada nombre PPV_* también están reservados y no se pueden reenviar.
Los marcadores de posición expandidos en argv y los valores env por verificación: {checkout} (la revisión bajo prueba),
{plan_dir} (una copia aislada de los artefactos del plan para esa invocación), {scratch} (un
directorio opaco nuevo para esa invocación de verificación) y
{side} (base o patched, y no disponible para verificaciones exploit/variant). Los mismos valores
llegan como PPV_CHECKOUT, PPV_PLAN_DIR, PPV_SCRATCH, PPV_SIDE y PPV_CASE_ID. Escriba solo
bajo {scratch}; la ruta del directorio de evidencia no se pasa a las verificaciones. Las invocaciones base y parcheada
no comparten raíces de scratch, plan o árbol de trabajo administradas por el ejecutor. Después de que cada invocación sale, su
árbol de scratch se archiva bajo la ruta determinista results/scratch/<check-id-and-side>, su copia privada del plan
se descarta y cada elemento argv legible que se resuelve como un archivo se hashea
en argv_files. Los archivos dentro de las raíces aisladas del plan o checkout se retienen adicionalmente bajo
results/helpers/<sha256> hasta 16 MiB; el registro explica por qué cualquier otro archivo no se archivó.
Use un directorio dedicado para plan.json: sus archivos y directorios hermanos se copian en cada
invocación de {plan_dir}. Mantenga el código auxiliar bajo el directorio checks/ de ese directorio o verificado
en el repositorio objetivo para que sus bytes sean revisables. El plan de máquina que contiene los pines de commit,
el directorio de salida actual y los árboles de resultados anteriores detectados se excluyen; los enlaces simbólicos se rechazan.
La instantánea limpia permanece solo en la memoria del ejecutor, y
los lados de exploit/variante se ejecutan en orden aleatorio mientras los nombres de archivo de evidencia permanecen deterministas.
Stdout/stderr usan descriptores de captura anónimos o con nombres aleatorios y se copian a los archivos de evidencia nombrados
solo después de que el proceso hijo sale, por lo que la inspección de fd no puede revelar la etiqueta del lado.
Este aislamiento no es una caja de arena del host: las verificaciones se ejecutan con los privilegios de la persona que llama y un auxiliar malicioso podría usar cualquier estado externo arbitrario o deducir deliberadamente la revisión de la fuente o metadatos de Git. Inspeccione los artefactos auxiliares con dirección de contenido y use una caja de arena SO/contenedor cuando el código de verificación en sí mismo no sea de confianza.
Los árboles de trabajo de validación activos están bloqueados por Git con tokens de propietario aleatorios respaldados por bloqueos de archivos del kernel, por lo que
otro validador concurrente no puede podarlos y la reutilización de PID no puede hacerse pasar por un propietario. Si el
ejecutor se mata por la fuerza, la siguiente ejecución desbloquea los registros caducados propiedad del validador. Para
recuperación manual, inspeccione git worktree list, luego use git worktree unlock <ruta> y
git worktree remove --force <ruta> (o git worktree prune después de que la ruta desaparezca).
Lea evidence-model.md al diseñar la cobertura, seleccionar variantes o interpretar hallazgos y brechas de validación. No lo lea para la ejecución rutinaria de CLI.
Reglas de Cobertura
- Derive variantes de la causa raíz, no mutaciones cosméticas de la carga útil original.
- Enumere los sitios de llamada hermanos, devoluciones de llamada/salidas alternativas, rutas de error, desmontaje, propiedad, serialización y valores límite tocados por la corrección.
- Haga que cada prueba de exploit o variante afirme el comportamiento seguro. Debe fallar en la base vulnerable; una prueba que pasa en ambas revisiones no prueba nada sobre la remediación. Lea el stderr del lado base y confirme que el fallo es la aserción que escribió, no un harness que nunca llegó allí.
- Mantenga las aserciones de exploit y variante limitadas al invariante de seguridad. Pruebe la actividad, los tipos/mensajes de error exactos, la sincronización y la compatibilidad por separado como verificaciones de
behaviororegression; de lo contrario, un cambio de contrato no relacionado puede hacerse pasar por una prueba de que la vulnerabilidad permanece. - Mantenga el harness
controlbenigno y haga que ejercite el componente modificado. Establece que el harness funciona en ambas revisiones. Los controles fallidos dejan brechas e impiden atribuir otras fallas al parche. Las observaciones sin procesar permanecen disponibles para revisión. - Use
behaviorsolo para el comportamiento que debe permanecer sin cambios. La comparación exacta de salida es deliberada; mueva los valores inestables detrás de un harness de prueba determinista en lugar de normalizarlos en prosa. - Haga que las verificaciones
securitypasen en la base vulnerable antes de tratar una falla parcheada como una nueva introducida. Una línea base fallida deja la atribución sin resolver. - No edite el parche durante la validación. Devuelva las fallas al autor del parche y comience una nueva ejecución recién fijada.
Lectura del Resultado
El esquema 2.0 de result.json contiene una assessment con status, findings, gaps y
human_review_required. El estado es complete cuando todas las verificaciones requeridas produjeron evidencia utilizable,
incluso si algunas verificaciones encontraron fallas. El estado es incomplete cuando queda alguna brecha. Los hallazgos nombran el
ID de verificación, el tipo de verificación y la expectativa fallida. Las brechas nombran el ID de verificación y la evidencia faltante, con un
ID de verificación nulo para problemas a nivel de ejecución, como fallas de limpieza.
Las verificaciones de suite se ejecutan primero en la revisión parcheada. Una falla completada activa la misma verificación en línea de base. Si la línea de base pasa, reporte la falla después del parche. Si ambas fallan, preserve ambos registros y reporte que la atribución no está resuelta. No asuma que los códigos de salida coincidentes significan la misma falla.
El ejecutor sale con 0 para verificaciones completas sin hallazgos, 1 para verificaciones completas con hallazgos, 10 para validación incompleta y 64 para entradas no válidas. Lea el artefacto incluso después de la salida 10: puede contener hallazgos compatibles junto con brechas. La evidencia de fuente o compilación no puede establecer el comportamiento en tiempo de ejecución. Indique el nivel de evidencia junto con cualquier resultado exitoso.
Flujo de Trabajo Dinámico de Claude
Claude Code expone el flujo de trabajo empaquetado como /post-patch-validation:validate-patch.
Para pasar entradas estructuradas a través de la herramienta Workflow, use el nombre sin una barra inclinada inicial:
Workflow({
name: 'post-patch-validation:validate-patch',
args: {
finding: '<texto o ruta local del hallazgo>',
baseRef: '<ref-vulnerable>',
patchRef: '<ref-parcheada>',
workdir: 'post-patch-validation',
},
})
Use patchFile en lugar de patchRef cuando sea apropiado. El flujo de trabajo usa lentes de cobertura fija
para proponer verificaciones y un ejecutor fijo para ejecutar esta habilidad. Los agentes pueden crear artefactos de prueba.
El ejecutor de Python registra los hallazgos y brechas, y los revisores reportan preocupaciones de cobertura o evidencia
por separado. NEEDS_REPAIR devuelve fallas compatibles incluso cuando otras verificaciones dejaron brechas.
BLOCKED significa que la evidencia está incompleta sin una falla compatible. Las verificaciones exitosas avanzan a
READY_FOR_HUMAN_REVIEW solo después de que ambas revisiones de evidencia aprueben, de lo contrario REVIEW_REQUIRED.
El flujo de trabajo no puede hacer preguntas después del lanzamiento, así que pase todas las entradas por adelantado.
Racionalizaciones a Rechazar
| Racionalización | Relectura requerida |
|---|---|
| "El exploit produce el mismo código de salida en ambos lados, por lo que el parche no lo arregla" | Verifique que la aserción se alcanzó; un error de importación o una ruta muerta tambié |
| ... |
[truncado para traducción]