feat: pin constitution hash and manifest evidence

This commit is contained in:
Vault Sovereign
2025-12-27 01:06:04 +00:00
parent d1980ec714
commit c62ff092b7
6 changed files with 117 additions and 42 deletions

View File

@@ -5,9 +5,17 @@ OUT_DIR="${1:?usage: collect_ledger_verify.sh <out_dir>}"
mkdir -p "$OUT_DIR"
if command -v ledger >/dev/null 2>&1; then
ledger verify --format json > "$OUT_DIR/ledger_verify.json"
if ! ledger verify --format json > "$OUT_DIR/ledger_verify.json"; then
cat > "$OUT_DIR/ledger_verify.json" <<'JSON'
{"collected": false, "reason": "ledger verify failed"}
JSON
fi
elif command -v ledger-cli >/dev/null 2>&1; then
ledger-cli verify --format json > "$OUT_DIR/ledger_verify.json"
if ! ledger-cli verify --format json > "$OUT_DIR/ledger_verify.json"; then
cat > "$OUT_DIR/ledger_verify.json" <<'JSON'
{"collected": false, "reason": "ledger-cli verify failed"}
JSON
fi
else
cat > "$OUT_DIR/ledger_verify.json" <<'JSON'
{"collected": false, "reason": "ledger CLI not found"}

View File

@@ -7,8 +7,14 @@ EVID_DIR="${1:?usage: governance_constitution_pinned.sh <evidence_dir>}"
TS="$(iso_utc_now)"
FILE="$EVID_DIR/constitution_hash.json"
ROOT="$(vmcc_root)"
PIN_FILE="${VMCC_PINS_FILE:-$ROOT/config/pins.yaml}"
PINNED_SHA256="${VMCC_PINNED_CONSTITUTION_SHA256:-}"
if [[ -z "$PINNED_SHA256" && -f "$PIN_FILE" ]]; then
PINNED_SHA256="$(awk -F': *' '/^constitution_sha256:/ {print $2}' "$PIN_FILE" | tr -d '"' | tr -d "'" | head -n 1)"
fi
if [[ ! -f "$FILE" ]]; then
json_emit "$(jq -n --arg ts "$TS" '{
version:"1.0.0",

View File

@@ -9,7 +9,7 @@ vm-cc is the continuous compliance and evidence orchestration layer. It ingests
## Layout
- config/: source/rule/redaction/schedule configs
- schemas/: JSON/YAML schemas for evidence, rules, reports
- 00-frameworks/: frameworks and mappings (e.g., CISrules)
- 00-frameworks/: frameworks and mappings (e.g., CIS->rules)
- 10-controls/: control definitions
- 20-collectors/: collectors to pull evidence from vm-skills, ops, ledger, mcp
- 30-evidence/: raw evidence drops (per-run folders)
@@ -19,7 +19,7 @@ vm-cc is the continuous compliance and evidence orchestration layer. It ingests
- 70-violations/: findings and escalations
- 80-remediation/: playbooks/automation for fixes
- 90-automation/: pipelines/glue for end-to-end runs
- scripts/: thin CLI wrappers to orchestrate collect evaluate report sign
- scripts/: thin CLI wrappers to orchestrate collect -> evaluate -> report -> sign
## Run directories
Each execution writes to a per-run folder set:
@@ -45,6 +45,7 @@ RUN_ID format: `YYYYMMDDThhmmssZ_<shorthash>`.
"sha256": "..."
}
],
"details": { "entries_checked": 18231 }
"details": { "entries_checked": 18231 },
"remediation": null
}
```

2
config/pins.yaml Normal file
View File

@@ -0,0 +1,2 @@
version: "1.0.0"
constitution_sha256: ""

View File

@@ -20,14 +20,13 @@ vm_ledger:
path: "../vm-ledger"
evidence:
- "log/entries.cborseq"
- "ledger-cli verify --format json" # command invocation placeholder
vm_mcp:
path: "../vm-mcp"
evidence:
- "governance/constitution.lock"
vm_contracts:
contracts:
path: "../vm-contracts"
evidence:
- "receipt_v1.schema.json"

View File

@@ -14,51 +14,110 @@ REP_DIR="$ROOT/50-reports/$DAY/$RUN_ID"
mkdir -p "$EVID_DIR" "$RULE_DIR" "$REP_DIR"
hash_file() {
local file="$1"
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$file" | awk '{print $1}'
else
shasum -a 256 "$file" | awk '{print $1}'
fi
}
write_manifest() {
local manifest="$EVID_DIR/manifest.json"
local ts
ts="$(iso_utc_now)"
{
echo "{"
echo " \"version\": \"1.0.0\","
echo " \"collected_at\": \"${ts}\","
echo " \"run_id\": \"${RUN_ID}\","
echo " \"files\": ["
local first=1
while IFS= read -r file; do
local rel
rel="${file#$ROOT/}"
local sha
sha="$(hash_file "$file")"
if [[ $first -eq 0 ]]; then
echo " ,"
fi
first=0
echo " {\"path\": \"${rel}\", \"sha256\": \"${sha}\"}"
done < <(find "$EVID_DIR" -type f ! -name "manifest.json" | sort)
echo " ]"
echo "}"
} > "$manifest"
}
run_collect() {
echo "[vmcc] run_id=$RUN_ID"
echo "[vmcc] collecting evidence -> $EVID_DIR"
"$ROOT/20-collectors/collect_ledger_verify.sh" "$EVID_DIR"
"$ROOT/20-collectors/collect_constitution_hash.sh" "$EVID_DIR"
"$ROOT/20-collectors/collect_backup_restore_drill.sh" "$EVID_DIR"
write_manifest
}
run_evaluate() {
echo "[vmcc] evaluating rules -> $RULE_DIR"
"$ROOT/40-rules/ledger_hash_chain_intact.sh" "$EVID_DIR" > "$RULE_DIR/ledger.hash_chain_intact.json"
"$ROOT/40-rules/governance_constitution_pinned.sh" "$EVID_DIR" > "$RULE_DIR/governance.constitution_pinned.json"
"$ROOT/40-rules/backup_restore_drill_recent.sh" "$EVID_DIR" > "$RULE_DIR/backup.restore_drill_recent.json"
}
run_report() {
require_cmd jq
echo "[vmcc] assembling report -> $REP_DIR/report.json"
TS="$(iso_utc_now)"
PASSED_COUNT="$(jq -s '[.[] | select(.passed==true)] | length' "$RULE_DIR"/*.json)"
FAILED_COUNT="$(jq -s '[.[] | select(.passed==false)] | length' "$RULE_DIR"/*.json)"
jq -n \
--arg version "1.0.0" \
--arg timestamp "$TS" \
--arg run_id "$RUN_ID" \
--arg day "$DAY" \
--slurpfile rules <(cat "$RULE_DIR"/*.json) \
--argjson passed "$PASSED_COUNT" \
--argjson failed "$FAILED_COUNT" \
'{
version: $version,
timestamp: $timestamp,
period: "run",
run_id: $run_id,
day: $day,
summary: {
rules_passed: $passed,
rules_failed: $failed,
status: (if $failed == 0 then "COMPLIANT" else "NONCOMPLIANT" end)
},
rules: $rules
}' > "$REP_DIR/report.json"
}
case "$CMD" in
collect)
echo "[vmcc] run_id=$RUN_ID"
echo "[vmcc] collecting evidence -> $EVID_DIR"
"$ROOT/20-collectors/collect_ledger_verify.sh" "$EVID_DIR"
"$ROOT/20-collectors/collect_constitution_hash.sh" "$EVID_DIR"
"$ROOT/20-collectors/collect_backup_restore_drill.sh" "$EVID_DIR"
run_collect
;;
evaluate)
echo "[vmcc] evaluating rules -> $RULE_DIR"
"$ROOT/40-rules/ledger_hash_chain_intact.sh" "$EVID_DIR" > "$RULE_DIR/ledger.hash_chain_intact.json"
"$ROOT/40-rules/governance_constitution_pinned.sh" "$EVID_DIR" > "$RULE_DIR/governance.constitution_pinned.json"
"$ROOT/40-rules/backup_restore_drill_recent.sh" "$EVID_DIR" > "$RULE_DIR/backup.restore_drill_recent.json"
run_evaluate
;;
report)
run_report
;;
all)
run_collect
run_evaluate
run_report
require_cmd jq
echo "[vmcc] assembling report -> $REP_DIR/report.json"
TS="$(iso_utc_now)"
PASSED_COUNT="$(jq -s '[.[] | select(.passed==true)] | length' "$RULE_DIR"/*.json)"
FAILED_COUNT="$(jq -s '[.[] | select(.passed==false)] | length' "$RULE_DIR"/*.json)"
jq -n \
--arg version "1.0.0" \
--arg timestamp "$TS" \
--arg run_id "$RUN_ID" \
--arg day "$DAY" \
--slurpfile rules <(cat "$RULE_DIR"/*.json) \
--argjson passed "$PASSED_COUNT" \
--argjson failed "$FAILED_COUNT" \
'{
version: $version,
timestamp: $timestamp,
period: "run",
run_id: $run_id,
day: $day,
summary: {
rules_passed: $passed,
rules_failed: $failed,
status: (if $failed == 0 then "COMPLIANT" else "NONCOMPLIANT" end)
},
rules: $rules
}' > "$REP_DIR/report.json"
if [[ "$FAILED_COUNT" -ne 0 ]]; then
exit 3
fi
;;
*)
echo "Usage: $0 {collect|evaluate|report}" >&2
echo "Usage: $0 {collect|evaluate|report|all}" >&2
exit 1
;;
esac