KB-702F

NVSZ migration/repoint rehearsal (temp_root_rehearsal.sh)

7 min read Revision 1
tool-kiem-thuv0.2-hardeningnvsznon-authorityreview-packetdryrun

#!/usr/bin/env bash

============================================================================

temp_root_rehearsal.sh -- NVSZ migration / repoint rehearsal (DISPOSABLE temp)

----------------------------------------------------------------------------

Object: TKT-OBJ-293 (PROPOSED). NON_AUTHORITY. decision_effect=NONE.

Rehearses, on a DISPOSABLE temp root only, how raw-evidence escrow records

would be migrated / repointed to a future no-vector root. It NEVER designates

an official root, never writes to the vector KB, never mutates production.

Exit 0 = rehearsal PASS; nonzero = a step failed (fail-closed).

============================================================================

set -u HERE="$(cd "$(dirname "$0")" && pwd)" VALIDATOR="$HERE/nvsz_root_validator.py" fail() { echo "REHEARSAL_FAIL: $1"; exit "${2:-1}"; } step() { echo; echo "== $1 =="; }

ROOT="$(mktemp -d -t nvsz-temproot-XXXXXX)" || fail "cannot mktemp root" 2 ROOT2="$(mktemp -d -t nvsz-temproot2-XXXXXX)" || fail "cannot mktemp root2" 2 PERMTEST="$(mktemp -d -t nvsz-dryrun-permtest-XXXXXX)" || fail "cannot mktemp permtest" 2 echo "DISPOSABLE temp root = $ROOT" echo "DISPOSABLE repoint root = $ROOT2" echo "DISPOSABLE permtest = $PERMTEST"

RUN_ID="rehearsal-run-0001" RUNDIR="$ROOT/tool-kiem-thu/runs/$RUN_ID"

--- the regeneration recipe (the KB-side artifact; tiny + deterministic) ---

RECIPE="$ROOT/commands.sh" cat > "$RECIPE" <<'EOF' #!/usr/bin/env bash

deterministic sample "run": fixed bytes -> byte-stable anchor

set -e OUT="$1" mkdir -p "$OUT" printf 'gate G1 OK\ngate G2 OK\n' > "$OUT/stdout.log" printf '{"G1":0,"G2":0,"OVERALL":"PASS"}\n' > "$OUT/exit_codes.json" EOF chmod +x "$RECIPE"

step "STEP 1: create root layout" mkdir -p "$RUNDIR" || fail "mkdir rundir" 3 echo " created $RUNDIR"

step "STEP 2: write/read/delete PERMISSION test (temp/dry-run path ONLY)" PT="$PERMTEST/probe.tmp" echo "w" > "$PT" || fail "perm write failed" 4 [ "$(cat "$PT")" = "w" ] || fail "perm read mismatch" 4 rm -f "$PT" || fail "perm delete failed" 4 [ ! -e "$PT" ] || fail "perm delete did not remove" 4 echo " write/read/delete OK in disposable $PERMTEST (NOT the real root, NOT prod)"

step "STEP 3: generate raw evidence into the temp root (regeneration recipe)" bash "$RECIPE" "$RUNDIR" || fail "recipe run failed" 5 STDOUT_HASH=$(shasum -a 256 "$RUNDIR/stdout.log" | awk '{print $1}') EXIT_HASH=$(shasum -a 256 "$RUNDIR/exit_codes.json" | awk '{print $1}') echo " stdout.log sha256=$STDOUT_HASH" echo " exit_codes.json sha256=$EXIT_HASH (byte-stable anchor)"

step "STEP 4: compute hash ledger + packet_tree" LEDGER="$RUNDIR/HASH_MANIFEST.sha256" ( cd "$RUNDIR" && shasum -a 256 stdout.log exit_codes.json ) > "$LEDGER" || fail "ledger compute" 6 LEDGER_HASH=$(shasum -a 256 "$LEDGER" | awk '{print $1}') echo "$LEDGER_HASH HASH_MANIFEST.sha256" > "$RUNDIR/packet_tree.sha256" echo " ledger_hash=$LEDGER_HASH"

step "STEP 5: build escrow descriptor pointing at the temp root + validate" DESC="$ROOT/candidate-root-descriptor.json" python3 - "$ROOT" "$RUNDIR" "$LEDGER_HASH" "$EXIT_HASH" "$PERMTEST" > "$DESC" <<'PY' import json, sys root, rundir, ledger_hash, exit_hash, permtest = sys.argv[1:6] desc = { "nvsz_root": { "designated": False, # rehearsal: NOT a real designation "designated_by": None, "root_path": root, # explicit disposable temp path "storage_kind": "nvsz_file_root", "outside_vector_kb": True }, "permissions": { "requires_production": False, "requires_real_run": False, "write_read_delete_tested_in": permtest }, "base_dir": rundir, "hash_ledger": { "path": "HASH_MANIFEST.sha256", "ledger_hash": "sha256:" + ledger_hash, "records": [ { "evidence_class": "rehearsal-exit-anchor", "pointer": {"target": "exit_codes.json", "local_path": "exit_codes.json", "hash": exit_hash, "size": 1, "produced_by": "bash commands.sh"}, "regeneration_command": "bash commands.sh runs/%s" % "rehearsal-run-0001", "determinism": "byte-exact" }, { "evidence_class": "rehearsal-gate-logs", "pointer": {"target": "stdout.log", "local_path": "stdout.log", "hash": "0"*64, "size": 0, "produced_by": "bash commands.sh"}, "regeneration_command": "bash commands.sh runs/rehearsal-run-0001", "determinism": "functional" } ] } } print(json.dumps(desc, indent=2)) PY python3 "$VALIDATOR" --descriptor "$DESC"; RC=$? [ "$RC" -eq 0 ] || fail "validator rejected the rehearsal descriptor (rc=$RC)" 7 echo " validator exit 0 -> descriptor VALID against temp root"

step "STEP 6: tamper-detect (mutate 1 byte -> ledger -c must FAIL)" cp "$RUNDIR/exit_codes.json" "$RUNDIR/exit_codes.json.bak" printf 'X' >> "$RUNDIR/exit_codes.json" if ( cd "$RUNDIR" && shasum -a 256 -c HASH_MANIFEST.sha256 ) >/dev/null 2>&1; then fail "tamper NOT detected (ledger -c passed on mutated file)" 8 fi echo " tamper detected: shasum -c failed on mutated byte (expected)" mv "$RUNDIR/exit_codes.json.bak" "$RUNDIR/exit_codes.json"

step "STEP 7: regeneration after loss (delete raw -> recipe rebuilds byte-stable)" rm -f "$RUNDIR/stdout.log" "$RUNDIR/exit_codes.json" bash "$RECIPE" "$RUNDIR" || fail "regeneration failed" 9 EXIT_HASH2=$(shasum -a 256 "$RUNDIR/exit_codes.json" | awk '{print $1}') [ "$EXIT_HASH2" = "$EXIT_HASH" ] || fail "byte-exact anchor not reproduced ($EXIT_HASH2 != $EXIT_HASH)" 9 echo " regenerated exit_codes.json sha256=$EXIT_HASH2 == original (byte-stable OK)"

step "STEP 8: REPOINT rehearsal (root -> root2; pointer/config change only)" mkdir -p "$ROOT2/tool-kiem-thu/runs/$RUN_ID" cp "$RUNDIR/stdout.log" "$RUNDIR/exit_codes.json" "$RUNDIR/HASH_MANIFEST.sha256"
"$RUNDIR/packet_tree.sha256" "$ROOT2/tool-kiem-thu/runs/$RUN_ID/" || fail "repoint copy" 10 DESC2="$ROOT2/candidate-root-descriptor.json" sed "s#"root_path": "$ROOT"#"root_path": "$ROOT2"#; s#"base_dir": "$RUNDIR"#"base_dir": "$ROOT2/tool-kiem-thu/runs/$RUN_ID"#" "$DESC" > "$DESC2" python3 "$VALIDATOR" --descriptor "$DESC2"; RC2=$? [ "$RC2" -eq 0 ] || fail "repointed descriptor rejected (rc=$RC2)" 10 echo " repointed descriptor VALID -> repoint is a pointer/config change (R5.4/R6)"

step "STEP 9: dispose temp roots (documented disposable; no retention needed)" rm -rf "$ROOT" "$ROOT2" "$PERMTEST" [ ! -e "$ROOT" ] && [ ! -e "$ROOT2" ] && [ ! -e "$PERMTEST" ] || fail "disposal incomplete" 11 echo " disposed all disposable temp roots"

echo echo "REHEARSAL_RESULT: PASS" echo " byte_stable_anchor=$EXIT_HASH ledger_hash=$LEDGER_HASH" exit 0

Back to Knowledge Hub knowledge/dev/laws/tool-kiem-thu/dev/v0.2-hardening/review/v02-nvsz-root-provisioning-dryrun-2026-06-11/temp_root_rehearsal.sh