MACGUARD · DOCUMENTACIÓN
English

Registro y checkpoints

Qué se registra, cómo se firman los checkpoints y cómo se detectan retrocesos.

El registro

logs/log.jsonl es un registro de solo añadir con una línea JSON por evento (time, level, event, message y detalles). Su vista legible está en la página de transparencia. Los eventos llevan solo cifras: nunca nombres ni hallazgos de reglas en cuarentena.

Checkpoints

Un checkpoint es un texto de tres líneas: el origen macguard-rules-log v1, el número de entradas y la raíz en base64. publish.yml lo firma con Sigstore (checkpoint.sigstore.json) y lo adjunta a la release (checkpoint.txt).

Diagrama: Publicación y firma del checkpoint

Dibujando el diagrama…

Descripción del diagrama

publish.yml añade el evento de aprobación, escribe un checkpoint sin firmar con tlog.py, lo firma con cosign usando la identidad del workflow, verifica de nuevo todo el registro, sella el manifiesto que incluye la cabeza del registro, lo firma y escribe la prueba de inclusión que une la entrada de la release con ese checkpoint.

Código Mermaid
sequenceDiagram
  autonumber
  participant W as publish.yml
  participant T as tlog.py
  participant CO as cosign
  participant SE as seal.py
  W->>T: event release.approved
  W->>T: checkpoint (origin, size, root)
  W->>CO: sign-blob checkpoint
  CO-->>W: checkpoint.sigstore.json
  W->>T: verify (every checkpoint, consistency, signatures)
  W->>SE: write manifest.json (rules_root and log head)
  W->>CO: sign-blob manifest.json
  CO-->>W: manifest.sigstore.json
  W->>T: release-proof (inclusion proof for the candidate.accepted entry)
  T-->>W: inclusion-proof.json
Diagrama: Evolución de los checkpoints

Dibujando el diagrama…

Descripción del diagrama

Cada checkpoint firmado compromete un tamaño y una raíz del registro. Los posteriores extienden a los anteriores. Una prueba de consistencia demuestra que el árbol del tamaño anterior es prefijo del posterior, es decir, solo se añadieron entradas. Un cliente que recuerda el checkpoint anterior puede rechazar un árbol menor (rollback) o una raíz distinta con el mismo tamaño (bifurcación).

Código Mermaid
flowchart LR
  C20["checkpoint<br/>size 20<br/>00000020.txt"]:::sec
  C75["checkpoint<br/>size 75<br/>00000075.txt"]:::sec
  CN["next checkpoint<br/>size N"]:::sec
  C20 -->|consistency.json<br/>proof 20 to 75| C75
  C75 -->|consistency proof| CN
  RB["client sees size smaller<br/>than the one it trusts"]:::qua -.->|rollback refused| C75
  FK["client sees another root<br/>at the same size"]:::qua -.->|fork refused| C75
  classDef src fill:#cfe3ff,stroke:#2f6df0,color:#0b1b33
  classDef val fill:#ffe9b8,stroke:#b8860b,color:#2b1d00
  classDef sec fill:#cdeedd,stroke:#1b6e3c,color:#08210f
  classDef pub fill:#e4d7ff,stroke:#6a3fd1,color:#1b0b3b
  classDef qua fill:#ffd4cc,stroke:#c0392b,color:#33100b
  classDef gate fill:#ffffff,stroke:#111111,stroke-width:3px,color:#111111

El manifiesto firmado incluye la cabeza del registro (log.origin, log.size, log.root) y debe coincidir con el checkpoint adjunto. En la última release el tamaño es 75 y la raíz del registro 1bab9bb9364b3a42f76835ae138bffad33eaa3694d0021afd208f5fd54e63d96.

Eventos

Estos son los códigos de evento que emiten los workflows y scripts. Una prueba de la documentación comprueba que cada uno aparece en el fichero indicado.

CódigoNivelCuándo se registraOrigen
sources.fetchedINFOSe descargaron las fuentes upstream en commits fijados.scripts/tlog.py
candidate.classifiedINFOResumen de la clasificación: examinados, aceptados, en cuarentena, rechazados y obsoletos (solo cifras).scripts/tlog.py
candidate.acceptedINFOEl conjunto aprobado superó todos los controles obligatorios; incluye su rules_root candidato.scripts/tlog.py
candidate.not_publishableWARNINGEsta ejecución no produce release; se indican los bloqueos.scripts/tlog.py
rules.withheldWARNINGFicheros ya publicados que ya no pasan los controles y se retienen hasta resolverse.scripts/tlog.py
file.skippedWARNINGUn fichero de la fuente se omitió al preparar el candidato (tamaño, binario, ruta no permitida).scripts/tlog.py
rule.rejectedERROREvento heredado del flujo anterior: un fichero falló la validación del compilador.scripts/tlog.py
gate.rule_errorERROREvento heredado: un fichero falló al cargarse en la app.scripts/tlog.py
candidate.rejectedERROREvento heredado: candidato bloqueado completo por ficheros que fallaban.scripts/tlog.py
candidate.changesINFOHay cambio efectivo respecto a la última release; se solicita la publicación..github/workflows/daily.yml
candidate.unchangedINFOSin cambio efectivo: no hay release ni solicitud de aprobación..github/workflows/daily.yml
run.failedERRORLa ejecución diaria falló antes de poder decidir; no se publicó nada..github/workflows/daily.yml
release.approvedINFOEl candidato se aprobó para firma (automáticamente o por un humano según el entorno) y se firma la cabeza del registro..github/workflows/publish.yml
release.publishedINFOLa release firmada se publicó en GitHub y se solicitó el despliegue del sitio..github/workflows/publish.yml
release.failedERRORFallo al firmar o publicar; no se publicó nada nuevo..github/workflows/publish.yml
site.github_pages_deployedINFOSitio desplegado en GitHub Pages..github/workflows/site.yml
site.github_pages_failedERRORFalló el despliegue en GitHub Pages..github/workflows/site.yml
site.live_verifiedINFOLa URL pública se verificó con los bytes que sirve (paquete, ficheros, firmas, pruebas, enlaces)..github/workflows/site.yml
site.live_failedERRORLa verificación de la URL pública falló..github/workflows/site.yml
site.build_failedERRORNo se pudo construir o verificar el sitio..github/workflows/site.yml
site.cloudflare_deployedINFOSitio desplegado automáticamente en Cloudflare Pages desde el workflow..github/workflows/site.yml
site.cloudflare_skippedWARNINGNo hay credenciales de Cloudflare configuradas en el repositorio; no se intentó desplegar..github/workflows/site.yml
site.cloudflare_blockedERRORLa comprobación previa de la credencial de Cloudflare falló; no se intentó desplegar..github/workflows/site.yml
site.cloudflare_failedERROREl despliegue en Cloudflare Pages falló; sigue el sitio anterior..github/workflows/site.yml