Skip to content

v1.12.0 — Tres campos del contrato que se declaraban y no se verificaban

Latest

Choose a tag to compare

@MauricioPerera MauricioPerera released this 26 Jul 22:45
· 46 commits to main since this release
f880a09

Esta release sale de instanciar la plantilla en un proyecto Rust real y encontrar, tirando del mismo hilo tres veces, que tres campos del contrato declaraban una cobertura que no tenían. Los tres fallaban del mismo modo: verde silencioso, no error visible. Ninguno era detectable sin leer el código del gate.

Qué se declaraba Qué pasaba de verdad
budget: max_cyclomatic_complexity: N El gate de Nivel 2 lee cyclomatic_max. El nombre que documentaba la plantilla nunca se leyó — 33/33 contratos del repo afectados. Un contrato con max_params: 1 y una firma de 5 parámetros pasaba sin un solo error.
forbids: ['unsafe'] Nadie verificaba el contenido de forbids, solo que la lista no estuviera vacía. Se podía declarar sobre un proyecto Rust que permite unsafe sin que ningún gate lo notara.
scan_secrets corriendo en CI, en verde Escaneaba solo ('.py','.js','.ts','.md','.json'): en un proyecto Rust/Go/Java miraba cero archivos y salía 0. La misma clave AWS daba ERROR en un .py y pasaba limpia en un .rs.

El patrón, que es la lección

Un gate que no puede reportar su propia ausencia de cobertura no es un gate, es una sensación de cobertura. Por eso los tres arreglos no se limitan al fix: cada uno agrega un mecanismo para que la falta de cobertura se veaFM_BUDGET_KEY, FORBID_UNVERIFIED, SECRETS_NO_FILES_SCANNED.

Nota metodológica: el agujero de scan_secrets estaba congelado por su propio oráculo — un test aseveraba literalmente que un .rs con una credencial devolvía []. tests_sha256 garantiza que el oráculo no cambió, no que sea correcto, y audit_seals detecta oráculos débiles, no equivocados.

Novedades

  • scripts/audit_forbids.py (nuevo, advisory opt-in): verifica forbids declarado vs realmente impedido. Un verificador hoy — unsafe en Rust, el único donde la prohibición es comprobable de verdad porque rustc la impone sobre el crate entero. network/subprocess/llm se reportan como FORBID_UNVERIFIED: siguen siendo declarativos y el auditor lo dice en vez de callar.
  • scripts/scan_lint_suppressions.py (nuevo): detecta #[allow(clippy::…)] agregado en el diff para esquivar un lint en vez de arreglarlo.
  • Documentado el punto ciego de macros: la misma lógica mide cyclomatic=5, nesting=4 en código normal y cyclomatic=1, nesting=0 dentro de un view! { }. Una función cuya lógica entera vive en un macro mide como si estuviera vacía. No es arreglable en un gate estático; se documenta el límite de la garantía.
  • Dónde van los tests de un proyecto no-Python, con el mecanismo concreto ([[test]] path en Rust) y sus dos consecuencias: hay que actualizar la clave tests: del contrato, y el tests_sha256 no cambia (sella contenido, no ubicación).

Breaking para proyectos ya instanciados

  • Los contratos con max_cyclomatic_complexity / max_nesting_depth pasan a ERROR; el mensaje nombra el reemplazo canónico. Mismo patrón que fijó tests_sha256.
  • scan_secrets ahora encuentra credenciales en archivos que antes ignoraba: un repo "en verde" puede pasar a rojo — y en ese caso el rojo es el correcto.

Verificación

validate_contracts 33 archivos, validate_okf 60 nodos, validate_changelog 33 contratos, lint_ascii 26 scripts — 0 errores. Suite completa 696 tests, 0 fallos. preflight.py 12/12.