Dokumentation durchsuchen

assurance

Einen Security-Assurance-Case aufbauen: Aussagen, die nur durch wirklich gelaufene Prüfungen gestützt sind, in einem Hash-Ledger festgehalten und an einem Commit verifiziert.

Auf dieser Seite
  1. Syntax
  2. Die Case-Datei
  3. Was es liest und schreibt
  4. Das Ledger und sein Schlüssel
  5. Wie das Urteil entsteht
  6. Exit-Codes
  7. So sieht die Ausgabe aus
  8. Fehler und was zu tun ist
  9. Beispiele

assurance ist der Befehl hinter dem Security-Assurance-Case des Shield-Packs. Ein Case listet Aussagen über dein System auf (zum Beispiel „keine Produktionsabhängigkeit hat eine bekannte Schwachstelle hoher Schwere“), liefert zu jeder ein Argument und stützt sie mit Nachweisen. Als Nachweis akzeptiert BMAD+ nur eine Prüfung, die es selbst ausgeführt hat: ein Befehl, sein Exit-Code, ein Digest seiner Ausgabe und die Digests der geschriebenen Dateien, angehängt an ein per Hash verkettetes Ledger. Eine Behauptung, ein Dokument oder ein Link wird abgelehnt. Du brauchst es, wenn jemand, eine Prüferin, ein Kunde oder du selbst später, zeigen will, dass Kontrollen an einem bestimmten Commit greifen, und „wir glauben es“ nicht reicht.

Warnung Was ein Urteil nicht ist

Ein „supported“-Case zeigt, dass die genannten Prüfungen an einem Commit bestanden haben. Er zertifiziert das System nicht und ist kein Prüfurteil; was die Nachweise wert sind, entscheidet eine qualifizierte Prüferin. Außerdem führt assurance run die im Case stehenden Befehle mit demselben Vertrauen aus wie deine eigenen Skripte: Lies einen fremden Case, bevor du ihn startest.

Syntax

Im Terminal deines Projekts
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]

Aktionen
AktionWas sie tut
initKopiert die Shield-Vorlage in die genannte Case-Datei. Die Datei muss <id>.yaml heißen; die ID stammt aus dem Namen. Eine vorhandene Datei wird nie überschrieben.
runFührt die Prüfungen des Case aus (alle oder die mit --check genannten) und hängt pro Prüfung einen Eintrag ans Ledger an.
verifyBewertet jede Prüfung nach ihrem letzten Lauf und jede Aussage nach ihren Nachweisen und gibt das Urteil aus. Führt nichts aus.
Optionen von assurance
OptionArgumentStandardWas sie tut
-d, --directory<path>aktueller OrdnerProjektordner.
--dir<path>_bmad-output/assuranceNachweisordner im Projekt; das Ledger liegt in <dir>/<case id>/runs.jsonl. Relativer Pfad, mit / geschrieben.
--check<id>alle PrüfungenNur run: nur diese Prüfung ausführen. Die Option für mehrere wiederholen.
--ledger-head<sha256>keinerNur verify: fehlschlagen, wenn das Ledger den Eintrag mit diesem Digest nicht mehr enthält (64 hexadezimale Kleinbuchstaben).
--emit-check<file>keinerNur verify: das Urteil zusätzlich als JSON-Prüfergebnis für CI schreiben. Der Name muss auf .json enden und darf weder der Case noch sein Ledger sein.
--json-ausDas Ergebnis als JSON (schemaVersion: 1) statt als Text ausgeben. Fehler werden zu { "status": "error", "message": ... }.

Die Case-Datei

Üblicherweise liegt ein Case unter _bmad/assurance/<id>.yaml, aber jeder projektrelative Pfad ohne .. und ohne symbolischen Link funktioniert. init schreibt die Shield-Vorlage, ein vollständiges lauffähiges Beispiel (vier Prüfungen, eine Hauptaussage und vier Unteraussagen). Ersetze jedes Beispiel durch dein eigenes, committe die Datei und starte sie dann. So sieht die Form aus; unbekannte Schlüssel werden abgelehnt.

Form eines Case (aus der Vorlage gekürzt)
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.

Schlüssel eines Case
SchlüsselRegel
schemaMuss bmad-plus/assurance-case/1 sein.
idKleinbuchstaben, Ziffern, Punkte und Bindestriche, bis zu 64 Zeichen.
title, scopeFreitext, je 1 bis 4000 Zeichen.
freshness.maxAgeDaysGanze Tage von 1 bis 366. Standard 30. Ein älterer Lauf ist stale.
freshness.sameCommittrue (Standard) bindet die Nachweise an den ausgecheckten Commit und einen sauberen Arbeitsbaum. Nur für ein Projekt außerhalb von git auf false setzen.
checks[].idEindeutige ID der Prüfung.
checks[].runDer Befehl als Liste einzelner Argumente. Keine Shell beteiligt. Unter Windows sind Programme wie npm .cmd-Dateien und brauchen [cmd, /c, npm, ...].
checks[].cwdProjektrelativer Ordner für die Ausführung. Standard ..
checks[].envNamen zusätzlicher Umgebungsvariablen, die die Prüfung sehen darf. Standardmäßig erbt sie nur PATH, HOME, die temporären Ordner und einige Windows-Systemvariablen. BMAD_PLUS_ASSURANCE_KEY darf nie aufgeführt werden.
checks[].timeoutSecondsGanze Zahl von 1 bis 21600. Standard 600.
checks[].expect.exitCodeExit-Code, der als Erfolg gilt, 0 bis 255. Standard 0.
checks[].artifactsProjektrelative Dateien, die der Befehl schreiben muss; jede wird mit dem Lauf gehasht. Eine vom Lauf unverändert gelassene Datei gilt nicht als erzeugt.
claims[].id, claim, argumentPflicht. Das Argument sagt, warum eine bestandene Prüfung die Aussage zeigt.
claims[].parentEine früher deklarierte Aussage. Eine Aussage ohne Nachweis braucht mindestens eine Unteraussage, sonst ist sie „nur behauptet“ und der Case lädt nicht.
claims[].controlsOptionale Liste von FRAMEWORK:ID-Verweisen. Akzeptierte Rahmenwerke: ISO27001, SOC2, GDPR, EU-AI-Act, NIS2, NIST-800-53. Eine falsch geschriebene oder erfundene Kontrolle wird abgelehnt.
claims[].evidenceListe von { check, shows }. check muss eine deklarierte Prüfung nennen.

Was es liest und schreibt

  • init schreibt genau eine Datei: den Case, unter dem angegebenen Pfad (übergeordnete Ordner werden angelegt).
  • run liest den Case, führt jede gewählte Prüfung als Kindprozess ohne Shell aus und hängt pro Prüfung eine Zeile an <dir>/<case id>/runs.jsonl an. Währenddessen hält es runs.jsonl.lock. Es fragt git (rev-parse, status, ls-files), um den Commit und den Zustand des Arbeitsbaums festzuhalten.
  • verify liest Case, Ledger, git und die deklarierten Artefakte. Es schreibt nichts außer der optionalen --emit-check-Datei.
  • Es öffnet selbst keine Netzwerkverbindung. Die Befehle, die du deklarierst, tun, was sie tun; deshalb führt das Inventar der Datenflüsse assurance-checks als Fluss auf, der nur existiert, wenn du run aufrufst.
  • Überall abgelehnt: Pfade außerhalb des Projekts und jeder Pfad, der durch einen symbolischen Link führt.

Das Ledger und sein Schlüssel

Jeder Eintrag in runs.jsonl ist eine JSON-Zeile: Prüf-ID, Sequenznummer, Digest des Befehls, der Commit (revision) und dirty (ob verfolgte Änderungen oder nicht ignorierte, unverfolgte Dateien vorlagen), Start- und Endzeit, Exit-Code, ob eine Zeitüberschreitung vorlag, Größe und Digest der Ausgabe mit geschwärztem Auszug der letzten 2048 Bytes, der Digest jedes deklarierten Artefakts (oder null, wenn der Lauf es nicht schrieb), der Digest des Vorgängereintrags und der eigene sha256. Wer einen Eintrag vor dem letzten ändert, umsortiert oder entfernt, bricht die Kette, und verify bewertet dann den ganzen Case als nicht gestützt.

Die Kette allein verrät nur nachlässige Änderungen: Wer die Datei schreiben kann, kann einen gültigen Eintrag anhängen oder die letzten abschneiden. Zwei Dinge außerhalb des Ledgers schließen diese Lücke.

  • Der Schlüssel. Setze BMAD_PLUS_ASSURANCE_KEY (mindestens 32 Zeichen) aus einem CI-Secret. run hängt dann an jeden Eintrag einen HMAC-SHA256, und verify lehnt jeden Eintrag ab, den der Schlüssel nicht authentifiziert. Der Schlüssel wird nie an eine Prüfung weitergegeben. Nimm für run und verify denselben Schlüssel: Ein ohne Schlüssel geschriebenes Ledger wird abgelehnt, sobald der Schlüssel gesetzt ist.
  • Der Kopf. run gibt den Digest seines letzten Eintrags aus. Bewahre ihn dort auf, wo die Schreibenden des Ledgers ihn nicht ändern können (CI-Job-Log, Audit-Datei), und übergib ihn an verify --ledger-head. Ein Ledger, das diesen Eintrag nicht mehr enthält, wird abgelehnt, entfernte Läufe fallen also auf.

Wie das Urteil entsteht

Status einer Prüfung (nach ihrem letzten Lauf)
StatusBedeutung
passedLief, tat, was die Prüfung erwartet, und ist aktuell.
failedStartete nicht, überschritt die Zeit, endete mit einem anderen als dem erwarteten Code, oder ein Artefakt wurde vom Lauf nicht erzeugt.
staleBestand, aber an einem anderen Commit, auf uncommitteten Änderungen oder unverfolgten Dateien, mit inzwischen geändertem Befehl, mit inzwischen geändertem Artefakt, älter als maxAgeDays oder mit Endzeit in der Zukunft.
missingLief nie.

Eine Aussage ist nur supported, wenn alle ihre Nachweisprüfungen passed und alle Unteraussagen supported sind; sonst ist sie unsupported, mit Begründung. Der Case ist nur supported, wenn jede Aussage es ist, das Ledger intakt ist, ein angegebener --ledger-head noch darin steht und bei sameCommit: true ein Commit existiert und der Arbeitsbaum weder uncommittete Änderungen noch unverfolgte Dateien hat (Ledger-Ordner und Artefakte des Case zählen nicht). Das Urteil listet außerdem controls.supported und controls.unsupported: die an Aussagen markierten Kontrollen, die ausgeführte Nachweise haben oder nicht.

Exit-Codes

Exit-Codes je Aktion
AktionCodeBedeutung
init0Case-Datei geschrieben.
run0Jede gewählte Prüfung endete so, wie sie es erwartet.
run1Mindestens eine gewählte Prüfung ist gescheitert (Start unmöglich, Zeitüberschreitung, falscher Exit-Code oder ein deklariertes Artefakt nicht erzeugt). Die Einträge werden trotzdem geschrieben.
verify0Der Case ist supported.
verify1Der Case ist unsupported.
alle3Der Befehl konnte seine Arbeit nicht tun: unbekannte Aktion, Case fehlt oder ist ungültig, falscher Schlüssel oder Kopf, Ledger bei run nicht intakt, Sperre gehalten, Prüfung nicht deklariert, --emit-check abgelehnt. Ausgabe als assurance: <message> auf dem Fehlerstrom.

So sieht die Ausgabe aus

Die drei Mitschnitte unten sind aus den Meldungsvorlagen im Quellcode zusammengesetzt, mit Beispielwerten (Pfade, Zeiten und Digests sind erfunden). Deshalb sind sie als simuliert markiert.

Einen Case starten und ausführenSimuliert
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.

Beispielhafter Ablauf, nicht bei einem echten Lauf aufgezeichnet. Quelle: tools/cli/commands/assurance.js (Meldungsvorlagen von initAction und runAction)

Am selben Commit verifizierenSimuliert
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

Beispielhafter Ablauf, nicht bei einem echten Lauf aufgezeichnet. Quelle: tools/cli/commands/assurance.js (Meldungsvorlage von verifyAction)

Verifizieren, nachdem sich der Code geändert hatSimuliert
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
Exit-Code 1. Die veraltete Prüfung am neuen Commit erneut ausführen, dann verifizieren.

Beispielhafter Ablauf, nicht bei einem echten Lauf aufgezeichnet. Quelle: tools/cli/commands/assurance.js (verifyAction), tools/cli/lib/assurance.js (Begründungen von judgeCheck)

Mit --emit-check ist die geschriebene Datei ein JSON-Objekt mit dem Schema bmad-plus/assurance-check/1: Status, Revision, die Aussagen mit Begründungen, die Kontrollen und ein github-Eintrag (name, conclusion als success oder failure, ein Titel wie 3/5 claims supported und eine Markdown-Übersichtstabelle), den ein CI-Schritt als Check-Run veröffentlichen kann. Er enthält keinen Zeitstempel, dasselbe Urteil ergibt also dieselbe Datei.

Fehler und was zu tun ist

Meldungen nach assurance: (Exit-Code 3)
MeldungUrsacheWas tun
unknown action "x" (init, run, verify)Das erste Argument ist keine der drei Aktionen.init, run oder verify verwenden.
no assurance case at <path>Die Case-Datei existiert nicht.Pfad prüfen oder mit init anlegen.
<path> already existsinit überschreibt nie.Anderen Namen wählen oder den vorhandenen Case bearbeiten.
case file: name it <id>.yaml ...Der Dateiname ist nicht <id>.yaml mit gültiger ID.In der ID Kleinbuchstaben, Ziffern, Punkte und Bindestriche verwenden.
<case>: claim X is only asserted; support it with evidence from a check or with sub-claimsEine Aussage hat weder Nachweis noch Unteraussagen.evidence mit einer Prüfung ergänzen oder Unteraussagen mit parent.
evidence must name a check that runs (check: <id>); a statement, document or link is only assertedEin Nachweis hat nicht die Form { check, shows }.Eine Prüfung schreiben, deren Befehl die Aussage zeigt, und darauf verweisen.
BMAD_PLUS_ASSURANCE_KEY must hold at least 32 charactersDer Schlüssel ist gesetzt, aber zu kurz.Ein längeres Secret erzeugen oder die Variable entfernen.
the ledger <file> is not intact (record N ...)run fand einen geänderten, umsortierten oder nicht authentifizierten Eintrag (zum Beispiel vor dem Setzen des Schlüssels geschrieben).Die Datei zur Untersuchung aufbewahren und in ein anderes --dir schreiben.
another run holds <file>.lock; delete it only if no run is in progressEin Lauf ist aktiv oder wurde unterbrochen.Warten; läuft keiner, die Sperrdatei löschen.
check X is not declared in <case>--check nennt eine unbekannte Prüfung.Eine ID aus der Liste checks verwenden.
the ledger head must be a record digest of 64 lowercase hexadecimal characters--ledger-head ist fehlerhaft.Den Kopf genau so kopieren, wie run ihn ausgab.
--emit-check writes a .json file / --emit-check must not overwrite the case or its ledgerFalscher Ausgabename.Einen .json-Pfad wählen, der weder Case noch Ledger ist.
<path> passes through a symbolic link / must be a relative path inside the project, written with /Der Pfad verlässt das Projekt oder kreuzt einen Link.Einen normalen relativen Pfad mit / verwenden.

Gründe, warum verify mit 1 endet

  • the ledger is not intact: ... oder ... is not authenticated by BMAD_PLUS_ASSURANCE_KEY: Ein Eintrag wurde verändert oder der Schlüssel passt nicht. Das Ledger neu aufbauen, indem du die Prüfungen in ein frisches --dir erneut ausführst.
  • the ledger no longer holds the head ... it was anchored to: Einträge wurden entfernt oder das Ledger ausgetauscht.
  • the working tree has uncommitted changes or untracked files: committen, dann erneut ausführen und verifizieren. Die Nachweise beschreiben den Commit, nicht deinen Arbeitsbaum.
  • there is no commit to bind the evidence to: Der Ordner ist kein git-Repository mit einem Commit. freshness.sameCommit: false nur für ein Projekt außerhalb von git setzen.
  • Eine Prüfung ist missing, failed oder stale: Die Zeile <status> <check>: <reasons> nennt den Grund. Diese Prüfung am aktuellen Commit erneut ausführen.

Beispiele

Shield einen Case für ein Release bauen und ausführen lassen

Du stehst vor einem Release, und ein Kunde hat einen Nachweis verlangt, dass die Sicherheitskontrollen an genau diesem Commit greifen. Der Arbeitsbaum ist committet.

In deinem KI-Assistenten
Shield, starte einen Assurance-Case für dieses Release. Halte jede Aussage so klein, dass ein Befehl sie zeigt, markiere sie mit den Kontrollen, die sie stützen, führe dann die Prüfungen an diesem Commit aus und verifiziere den Case. Sag mir, welche Aussagen nicht gestützt sind und warum.

Das solltest du erhalten Shield führt bmad-plus assurance init _bmad/assurance/<id>.yaml aus, ersetzt die Beispielaussagen und -prüfungen der Vorlage durch die deines Projekts (eine Hauptaussage, Unteraussagen, jede gestützt durch einen Befehl, der bei Verletzung der Aussage fehlschlägt) und bittet dich, die Datei zu committen. Danach startet es assurance run, merkt sich den ausgegebenen Ledger-Kopf und führt assurance verify --ledger-head <head> --emit-check ... aus. Es meldet jede nicht gestützte Aussage mit dem von verify genannten Grund und listet die Kontrollen mit ausgeführtem Nachweis. Es sagt, ob Schlüssel und Kopf genutzt wurden; ohne sie vermerkt es, dass die Nachweise festgehalten, aber nicht manipulationssicher sind. Eine nicht gestützte Aussage nennt es nie erfüllt.

Ein nicht gestütztes Urteil erklären lassen

Ein CI-Job ist an assurance verify gescheitert, obwohl der Case letzte Woche grün war.

In deinem KI-Assistenten
Shield, verifiziere den Case release-security und erkläre jede nicht gestützte Aussage. Führe nichts erneut aus, bevor du mir gesagt hast, was veraltet ist und warum.

Das solltest du erhalten Shield führt bmad-plus assurance verify _bmad/assurance/release-security.yaml aus (nur lesend) und liest die Ausgabe: die Statuszeile, jede nicht bestandene Prüfung mit Gründen (anderer Commit, uncommittete Änderungen, geänderter Befehl oder geändertes Artefakt, älter als maxAgeDays) und jede nicht gestützte Aussage. Es erklärt sie in einfachen Worten, nennt die Prüfungen, die mit assurance run --check <id> zu wiederholen sind, und wartet auf dein Okay, bevor es etwas ausführt, denn run führt die im Case stehenden Befehle aus.

Siehe auch