Files
railiance-platform/scripts/openbao-validate-emergency-drill-evidence.sh

118 lines
3.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
EVIDENCE="${OPENBAO_EMERGENCY_EVIDENCE:-${1:-/tmp/netkingdom-openbao-emergency-drill/evidence.json}}"
usage() {
cat <<'USAGE'
Usage: scripts/openbao-validate-emergency-drill-evidence.sh [evidence.json]
Validates non-secret OpenBao emergency seal/unseal drill evidence. The evidence
file should record timing, status checks, verification flags, and operator
notes, but must not contain OpenBao tokens, unseal shares, root tokens, private
keys, passwords, OTP seeds, or recovery codes.
Environment:
OPENBAO_EMERGENCY_EVIDENCE Evidence JSON path. Default:
/tmp/netkingdom-openbao-emergency-drill/evidence.json
USAGE
}
if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then
usage
exit 0
fi
python3 - "$EVIDENCE" <<'PY'
from __future__ import annotations
import json
import sys
from pathlib import Path
path = Path(sys.argv[1])
if not path.exists():
print(f"[FAIL] emergency drill evidence file is missing: {path}", file=sys.stderr)
sys.exit(1)
try:
data = json.loads(path.read_text(encoding="utf-8"))
except json.JSONDecodeError as exc:
print(f"[FAIL] emergency drill evidence is not valid JSON: {exc}", file=sys.stderr)
sys.exit(1)
if not isinstance(data, dict):
print("[FAIL] emergency drill evidence root must be a JSON object", file=sys.stderr)
sys.exit(1)
required_strings = [
"drill_date",
"operator",
"source_cluster",
"source_namespace",
"source_pod",
"seal_started_at",
"sealed_status_observed_at",
"unseal_started_at",
"unseal_completed_at",
"post_unseal_verification",
]
required_true = [
"seal_command_issued",
"sealed_status_confirmed",
"unseal_quorum_available",
"unseal_completed",
"post_unseal_status_verified",
"post_unseal_readiness_verified",
"no_secret_material_recorded",
]
errors: list[str] = []
for key in required_strings:
value = data.get(key)
if not isinstance(value, str) or not value.strip():
errors.append(f"missing non-empty string: {key}")
for key in required_true:
if data.get(key) is not True:
errors.append(f"must be true: {key}")
window = data.get("availability_window_minutes")
if not isinstance(window, int) or window < 0:
errors.append("availability_window_minutes must be a non-negative integer")
encoded = json.dumps(data, sort_keys=True)
secret_markers = [
"OPENBAO_ROOT_TOKEN",
"VAULT_TOKEN",
"BEGIN PRIVATE KEY",
"BEGIN OPENSSH PRIVATE KEY",
"AGE-SECRET-KEY-1",
"-----BEGIN",
"hvs.",
]
for marker in secret_markers:
if marker in encoded:
errors.append(f"secret-looking marker present: {marker}")
placeholder_markers = [
"YYYY-MM-DD",
"example",
"Do not record",
"<",
]
for marker in placeholder_markers:
if marker in encoded:
errors.append(f"template placeholder present: {marker}")
if errors:
for error in errors:
print(f"[FAIL] {error}", file=sys.stderr)
sys.exit(1)
print(f"[OK] emergency drill evidence is structurally valid: {path}")
print(f"[OK] drill_date: {data['drill_date']}")
print(f"[OK] source: {data['source_cluster']}/{data['source_namespace']}/{data['source_pod']}")
print(f"[OK] availability_window_minutes: {data['availability_window_minutes']}")
PY