Explorar la documentación

assurance

Construir un caso de aseguramiento de seguridad: afirmaciones respaldadas solo por comprobaciones realmente ejecutadas, registradas en un diario encadenado y verificadas en un commit.

En esta página
  1. Sinopsis
  2. El archivo de caso
  3. Qué lee y qué escribe
  4. El diario y su clave
  5. Cómo se construye el veredicto
  6. Códigos de salida
  7. Cómo se ve la salida
  8. Errores y qué hacer
  9. Ejemplos

assurance es el comando detrás del caso de aseguramiento de seguridad del pack Shield. Un caso enumera afirmaciones sobre tu sistema (por ejemplo «ninguna dependencia de producción tiene un aviso conocido de gravedad alta»), da un argumento para cada una y la respalda con evidencias. La única evidencia que BMAD+ acepta es una comprobación que ejecutó él mismo: un comando, su código de salida, la huella de su salida y las de los archivos que escribió, añadidos a un diario encadenado por huellas. Una declaración, un documento o un enlace se rechaza. Se usa cuando alguien, un auditor, un cliente o tú mismo más adelante, pide demostrar que unos controles se cumplen en un commit concreto y «creemos que sí» no basta.

Advertencia Lo que un veredicto no es

Un caso «supported» demuestra que las comprobaciones nombradas pasaron en un commit. No certifica el sistema ni es una opinión de auditoría; un auditor cualificado decide cuánto valen las evidencias. Además, assurance run ejecuta los comandos escritos en el caso con la misma confianza que tus propios scripts: lee un caso ajeno antes de ejecutarlo.

Sinopsis

En la terminal de tu proyecto
npx bmad-plus assurance init <case-file>
npx bmad-plus assurance run <case-file> [--check <id>]... [--dir <path>] [--json]
npx bmad-plus assurance verify <case-file> [--ledger-head <sha256>] [--emit-check <file.json>] [--dir <path>] [--json]

Acciones
AcciónQué hace
initCopia la plantilla de Shield al archivo de caso que indiques. El archivo debe llamarse <id>.yaml; el id sale del nombre. Nunca sobrescribe un archivo existente.
runEjecuta las comprobaciones del caso (todas, o las indicadas con --check) y añade un registro por comprobación al diario.
verifyJuzga cada comprobación por su última ejecución y cada afirmación por sus evidencias, y muestra el veredicto. No ejecuta nada.
Opciones de assurance
OpciónArgumentoPor defectoQué hace
-d, --directory<path>carpeta actualCarpeta del proyecto.
--dir<path>_bmad-output/assuranceCarpeta de evidencias dentro del proyecto; el diario está en <dir>/<case id>/runs.jsonl. Ruta relativa escrita con /.
--check<id>todas las comprobacionesSolo run: ejecutar solo esta comprobación. Repite la opción para varias.
--ledger-head<sha256>ningunoSolo verify: fallar si el diario ya no contiene el registro con esta huella (64 caracteres hexadecimales en minúscula).
--emit-check<file>ningunoSolo verify: escribir además el veredicto como resultado de comprobación JSON para CI. El nombre debe acabar en .json y no puede ser el caso ni su diario.
--json-desactivadaImprimir el resultado en JSON (schemaVersion: 1) en lugar de texto. Los errores pasan a ser { "status": "error", "message": ... }.

El archivo de caso

Por convención un caso vive en _bmad/assurance/<id>.yaml, pero sirve cualquier ruta relativa al proyecto sin .. ni enlaces simbólicos. init escribe la plantilla de Shield, que es un ejemplo completo y funcional (cuatro comprobaciones, una afirmación principal y cuatro subafirmaciones). Sustituye cada ejemplo por el tuyo, haz commit del archivo y luego ejecútalo. Esta es la forma; las claves desconocidas se rechazan.

Forma de un caso (abreviada de la plantilla)
schema: bmad-plus/assurance-case/1
id: release-security
title: Release security case
scope: >-
  The service at the commit being released.
freshness:
  maxAgeDays: 30
  sameCommit: true
checks:
  - id: unit-tests
    run: [npm, test]
    timeoutSeconds: 900
  - id: secret-scan
    run: [gitleaks, detect, --no-banner, --redact, --report-path, reports/gitleaks.json]
    artifacts: [reports/gitleaks.json]
claims:
  - id: C1
    claim: The release ships no committed credential and no failing control test.
    argument: >-
      Holds when both sub-claims hold.
  - id: C1.1
    parent: C1
    claim: No credential is committed in the repository history.
    argument: >-
      The scanner reads every reachable commit and exits non-zero on a finding.
    controls: [ISO27001:A.5.17, SOC2:CC6.1]
    evidence:
      - check: secret-scan
        shows: gitleaks finds no secret and writes its report.
  - id: C1.2
    parent: C1
    claim: The behaviour the controls rely on is covered by passing tests.
    argument: >-
      The suite exercises access checks and input validation.
    controls: [ISO27001:A.8.29]
    evidence:
      - check: unit-tests
        shows: The test suite passes at this commit.

Claves de un caso
ClaveRegla
schemaDebe ser bmad-plus/assurance-case/1.
idMinúsculas, dígitos, puntos y guiones, hasta 64 caracteres.
title, scopeTexto libre, de 1 a 4000 caracteres cada uno.
freshness.maxAgeDaysNúmero entero de días de 1 a 366. Por defecto 30. Una ejecución más antigua es stale.
freshness.sameCommittrue (por defecto) liga las evidencias al commit activo y a un árbol de trabajo limpio. Pon false solo en un proyecto fuera de git.
checks[].idId único de la comprobación.
checks[].runEl comando como lista de argumentos separados. No interviene ningún shell. En Windows, programas como npm son archivos .cmd y necesitan [cmd, /c, npm, ...].
checks[].cwdCarpeta relativa al proyecto donde ejecutar. Por defecto ..
checks[].envNombres de variables de entorno adicionales que la comprobación puede ver. Por defecto solo hereda PATH, HOME, las carpetas temporales y algunas variables de sistema de Windows. BMAD_PLUS_ASSURANCE_KEY nunca puede figurar.
checks[].timeoutSecondsNúmero entero de 1 a 21600. Por defecto 600.
checks[].expect.exitCodeCódigo de salida que cuenta como éxito, de 0 a 255. Por defecto 0.
checks[].artifactsArchivos relativos al proyecto que el comando debe escribir; cada uno se resume con la ejecución. Un archivo que la ejecución dejó igual no cuenta como producido.
claims[].id, claim, argumentObligatorios. El argumento dice por qué una comprobación superada demuestra la afirmación.
claims[].parentUna afirmación declarada antes. Una afirmación sin evidencia debe tener al menos una subafirmación; si no, está «solo afirmada» y el caso no carga.
claims[].controlsLista opcional de referencias FRAMEWORK:ID. Marcos aceptados: ISO27001, SOC2, GDPR, EU-AI-Act, NIS2, NIST-800-53. Un control mal escrito o inventado se rechaza.
claims[].evidenceLista de { check, shows }. check debe nombrar una comprobación declarada.

Qué lee y qué escribe

  • init escribe un solo archivo: el caso, en la ruta que indiques (se crean las carpetas padre).
  • run lee el caso, ejecuta cada comprobación elegida como proceso hijo sin shell y añade una línea por comprobación a <dir>/<case id>/runs.jsonl. Mientras trabaja mantiene runs.jsonl.lock. Consulta git (rev-parse, status, ls-files) para anotar el commit y si el árbol estaba limpio.
  • verify lee el caso, el diario, git y los artefactos declarados. No escribe nada salvo el archivo opcional de --emit-check.
  • No abre por sí mismo ninguna conexión de red. Los comandos que declares hacen lo que hagan; por eso el inventario de tratamiento de datos lista assurance-checks como un flujo que solo existe cuando invocas run.
  • Rechazado en todas partes: rutas fuera del proyecto y cualquier ruta que pase por un enlace simbólico.

El diario y su clave

Cada registro de runs.jsonl es una línea JSON: el id de la comprobación, un número de secuencia, la huella del comando, el commit (revision) y dirty (si había cambios rastreados o archivos sin rastrear no ignorados), las horas de inicio y fin, el código de salida, si superó el tiempo, el tamaño y la huella de la salida con un extracto censurado de sus últimos 2048 bytes, la huella de cada artefacto declarado (o null si la ejecución no lo escribió), la huella del registro anterior y su propio sha256. Editar, reordenar o quitar un registro antes del último rompe la cadena, y verify juzga entonces todo el caso como no respaldado.

La cadena sola solo delata ediciones descuidadas: quien pueda escribir el archivo puede añadir un registro que se verifica o cortar los últimos. Dos elementos guardados fuera del diario cierran esa brecha.

  • La clave. Define BMAD_PLUS_ASSURANCE_KEY (al menos 32 caracteres) desde un secreto de CI. run añade entonces un HMAC-SHA256 a cada registro y verify rechaza cualquier registro que la clave no autentique. La clave nunca se entrega a una comprobación. Usa la misma clave en run y verify: un diario escrito sin clave se rechaza en cuanto la clave está definida.
  • La cabeza. run imprime la huella de su último registro. Guárdala donde quienes escriben el diario no puedan cambiarla (el log del job de CI, el archivo de auditoría) y pásala a verify --ledger-head. Un diario que ya no contiene ese registro se rechaza, así que las ejecuciones retiradas se notan.

Cómo se construye el veredicto

Estado de una comprobación (según su última ejecución)
EstadoSignificado
passedSe ejecutó, hizo lo que espera la comprobación y es reciente.
failedNo arrancó, superó el tiempo, salió con otro código distinto del esperado, o un artefacto no lo produjo la ejecución.
stalePasó, pero en otro commit, con cambios sin confirmar o archivos sin rastrear, con un comando que cambió después, con un artefacto que cambió después, más antiguo que maxAgeDays o con una hora de fin en el futuro.
missingNunca se ejecutó.

Una afirmación es supported solo cuando todas sus comprobaciones de evidencia son passed y todas sus subafirmaciones son supported; si no, es unsupported, con los motivos. El caso es supported solo cuando lo es cada afirmación, el diario está intacto, cualquier --ledger-head sigue en él y, con sameCommit: true, hay un commit y el árbol de trabajo no tiene cambios sin confirmar ni archivos sin rastrear (la carpeta del diario y los artefactos del caso no cuentan). El veredicto también lista controls.supported y controls.unsupported: los controles etiquetados en afirmaciones que tienen, o no, evidencia ejecutada.

Códigos de salida

Códigos de salida por acción
AcciónCódigoSignificado
init0Archivo de caso escrito.
run0Cada comprobación elegida terminó como espera.
run1Al menos una comprobación elegida falló (no arrancó, superó el tiempo, código de salida incorrecto o artefacto declarado no producido). Los registros se escriben igualmente.
verify0El caso es supported.
verify1El caso es unsupported.
cualquiera3El comando no pudo hacer su trabajo: acción desconocida, caso ausente o inválido, clave o cabeza incorrecta, diario no intacto en run, bloqueo retenido, comprobación no declarada, --emit-check rechazado. Se imprime assurance: <message> en el flujo de error.

Cómo se ve la salida

Las tres transcripciones siguientes se componen a partir de las plantillas de mensajes del código fuente, con valores ilustrativos (rutas, tiempos y huellas son inventados). Por eso están marcadas como simuladas.

Iniciar un caso y ejecutarloSimulado
npx bmad-plus assurance init _bmad/assurance/release-security.yaml
_bmad/assurance/release-security.yaml: case release-security started from the Shield template.
Replace every example claim and check with those of the project, commit it, then run it.
npx bmad-plus assurance run _bmad/assurance/release-security.yaml
/home/me/app/_bmad-output/assurance/release-security/runs.jsonl
  passed unit-tests               exit 0 in 41.3 s
  passed dependency-audit         exit 0 in 6.8 s
  passed secret-scan              exit 0 in 3.1 s
  passed review-gate              exit 0 in 1.2 s
Recorded 4 run(s); ledger head 3f9c1b7e5a2d4c6e8b0a1d3f5c7e9b2a4d6f8a0c1e3b5d7f9a2c4e6b8d0f1a3c.
Keep the head outside the ledger and verify with bmad-plus assurance verify _bmad/assurance/release-security.yaml --ledger-head 3f9c1b7e5a2d4c6e8b0a1d3f5c7e9b2a4d6f8a0c1e3b5d7f9a2c4e6b8d0f1a3c.

Transcripción ilustrativa, no capturada de una ejecución real. Fuente: tools/cli/commands/assurance.js (plantillas de mensajes de initAction y runAction)

Verificar en el mismo commitSimulado
npx bmad-plus assurance verify _bmad/assurance/release-security.yaml --ledger-head 3f9c1b7e5a2d4c6e8b0a1d3f5c7e9b2a4d6f8a0c1e3b5d7f9a2c4e6b8d0f1a3c --emit-check ci/assurance.json
release-security: supported — 5/5 claim(s) supported, 4 recorded run(s)
  controls with executed evidence: ISO27001:A.8.8, NIST-800-53:RA-5, ISO27001:A.5.17, SOC2:CC6.1, ISO27001:A.8.32, SOC2:CC8.1, ISO27001:A.8.29
  check: /home/me/app/ci/assurance.json

Transcripción ilustrativa, no capturada de una ejecución real. Fuente: tools/cli/commands/assurance.js (plantilla de mensaje de verifyAction)

Verificar tras un cambio de códigoSimulado
npx bmad-plus assurance verify _bmad/assurance/release-security.yaml
release-security: unsupported — 3/5 claim(s) supported, 4 recorded run(s)
  stale   unit-tests: it ran at 1a2b3c4d5e6f, not at 9f8e7d6c5b4a
  unsupported claim C1: sub-claim C1.4 is unsupported
  unsupported claim C1.4: evidence unit-tests is stale
  controls with executed evidence: ISO27001:A.8.8, NIST-800-53:RA-5, ISO27001:A.5.17, SOC2:CC6.1, ISO27001:A.8.32, SOC2:CC8.1
Código de salida 1. Ejecuta de nuevo la comprobación obsoleta en el nuevo commit y verifica.

Transcripción ilustrativa, no capturada de una ejecución real. Fuente: tools/cli/commands/assurance.js (verifyAction), tools/cli/lib/assurance.js (motivos de judgeCheck)

Con --emit-check, el archivo escrito es un objeto JSON con el esquema bmad-plus/assurance-check/1: el estado, la revisión, las afirmaciones con sus motivos, los controles y una entrada github (name, conclusion con valor success o failure, un título como 3/5 claims supported y una tabla resumen en Markdown) que un paso de CI puede publicar como ejecución de comprobación. No lleva marca de tiempo, así que el mismo veredicto produce el mismo archivo.

Errores y qué hacer

Mensajes impresos tras assurance: (código de salida 3)
MensajeCausaQué hacer
unknown action "x" (init, run, verify)El primer argumento no es una de las tres acciones.Usa init, run o verify.
no assurance case at <path>El archivo de caso no existe.Revisa la ruta o créalo con init.
<path> already existsinit nunca sobrescribe.Elige otro nombre o edita el caso existente.
case file: name it <id>.yaml ...El nombre del archivo no es <id>.yaml con un id válido.Usa minúsculas, dígitos, puntos y guiones en el id.
<case>: claim X is only asserted; support it with evidence from a check or with sub-claimsUna afirmación no tiene evidencia ni subafirmaciones.Añade evidence que nombre una comprobación, o subafirmaciones con parent.
evidence must name a check that runs (check: <id>); a statement, document or link is only assertedUn elemento de evidencia no tiene la forma { check, shows }.Escribe una comprobación cuyo comando demuestre la afirmación y señálala.
BMAD_PLUS_ASSURANCE_KEY must hold at least 32 charactersLa clave está definida pero es demasiado corta.Genera un secreto más largo o quita la variable.
the ledger <file> is not intact (record N ...)run encontró un registro editado, reordenado o no autenticado (por ejemplo escrito antes de definir la clave).Conserva el archivo para inspección y registra en otro --dir.
another run holds <file>.lock; delete it only if no run is in progressHay una ejecución activa o se interrumpió una.Espera; si no hay ninguna, borra el archivo de bloqueo.
check X is not declared in <case>--check nombra una comprobación desconocida.Usa un id de la lista checks.
the ledger head must be a record digest of 64 lowercase hexadecimal characters--ledger-head está mal formado.Copia la cabeza exactamente como la imprimió run.
--emit-check writes a .json file / --emit-check must not overwrite the case or its ledgerNombre de salida incorrecto.Elige una ruta .json que no sea el caso ni el diario.
<path> passes through a symbolic link / must be a relative path inside the project, written with /La ruta sale del proyecto o cruza un enlace.Usa una ruta relativa normal con separadores /.

Motivos por los que verify sale con 1

  • the ledger is not intact: ... o ... is not authenticated by BMAD_PLUS_ASSURANCE_KEY: se alteró un registro o la clave no coincide. Reconstruye el diario ejecutando de nuevo las comprobaciones en un --dir nuevo.
  • the ledger no longer holds the head ... it was anchored to: se quitaron registros o se sustituyó el diario.
  • the working tree has uncommitted changes or untracked files: haz commit y vuelve a ejecutar y verificar. Las evidencias describen el commit, no tu árbol de trabajo.
  • there is no commit to bind the evidence to: la carpeta no es un repositorio git con un commit. Pon freshness.sameCommit: false solo en un proyecto fuera de git.
  • Una comprobación está missing, failed o stale: la línea <status> <check>: <reasons> dice por qué. Ejecútala de nuevo en el commit actual.

Ejemplos

Que Shield construya y ejecute un caso para una versión

Vas a publicar una versión y un cliente pidió la prueba de que los controles de seguridad se cumplen en ese commit exacto. El árbol de trabajo está confirmado.

En tu asistente de IA
Shield, inicia un caso de aseguramiento para esta versión. Mantén cada afirmación lo bastante pequeña para que un comando la demuestre, etiquétalas con los controles que respaldan, luego ejecuta las comprobaciones en este commit y verifica el caso. Dime qué afirmaciones no están respaldadas y por qué.

Lo que deberías obtener Shield ejecuta bmad-plus assurance init _bmad/assurance/<id>.yaml, sustituye las afirmaciones y comprobaciones de ejemplo de la plantilla por las de tu proyecto (una afirmación principal, subafirmaciones cada una respaldada por un comando que sale con error cuando la afirmación falla) y te pide que hagas commit del archivo. Después ejecuta assurance run, guarda la cabeza del diario impresa y ejecuta assurance verify --ledger-head <head> --emit-check .... Informa de cada afirmación no respaldada con el motivo que imprime verify y lista los controles con evidencia ejecutada. Indica si se usaron una clave y una cabeza; sin ellas, aclara que las evidencias están registradas pero no a prueba de manipulación. Nunca da por cumplida una afirmación no respaldada.

Explicar un veredicto no respaldado

Un job de CI falló en assurance verify, y el caso estaba en verde la semana pasada.

En tu asistente de IA
Shield, verifica el caso release-security y explica cada afirmación no respaldada. No vuelvas a ejecutar nada hasta decirme qué está obsoleto y por qué.

Lo que deberías obtener Shield ejecuta bmad-plus assurance verify _bmad/assurance/release-security.yaml (solo lectura) y lee la salida: la línea de estado, cada comprobación no superada con sus motivos (otro commit, cambios sin confirmar, comando o artefacto modificado, más antiguo que maxAgeDays) y cada afirmación no respaldada. Los explica con palabras sencillas, te dice qué comprobaciones repetir con assurance run --check <id> y espera tu visto bueno antes de ejecutar nada, porque run ejecuta los comandos escritos en el caso.

Véase también