generated from coulomb/repo-seed
Add NET-WP-0017 T02 closure validator
This commit is contained in:
14
Makefile
14
Makefile
@@ -6,6 +6,9 @@ OPERATOR_AGE_PUBKEY := $(shell cat keys/age.pub 2>/dev/null | tr -d '[:space:]')
|
|||||||
SECURITY_BOOTSTRAP_METADATA ?= $(if $(METADATA),$(METADATA),.local/security-bootstrap.json)
|
SECURITY_BOOTSTRAP_METADATA ?= $(if $(METADATA),$(METADATA),.local/security-bootstrap.json)
|
||||||
SECURITY_BOOTSTRAP_HOST ?= $(if $(HOST),$(HOST),127.0.0.1)
|
SECURITY_BOOTSTRAP_HOST ?= $(if $(HOST),$(HOST),127.0.0.1)
|
||||||
SECURITY_BOOTSTRAP_PORT ?= $(if $(PORT),$(PORT),8876)
|
SECURITY_BOOTSTRAP_PORT ?= $(if $(PORT),$(PORT),8876)
|
||||||
|
OPENBAO_RESTORE_EVIDENCE ?= /tmp/netkingdom-openbao-restore-drill/evidence.json
|
||||||
|
OPENBAO_EMERGENCY_EVIDENCE ?= /tmp/netkingdom-openbao-emergency-drill/evidence.json
|
||||||
|
RAILIANCE_PLATFORM_PATH ?= ../railiance-platform
|
||||||
|
|
||||||
# ── Help ──────────────────────────────────────────────────────────────────────
|
# ── Help ──────────────────────────────────────────────────────────────────────
|
||||||
help: ## Show this help
|
help: ## Show this help
|
||||||
@@ -172,6 +175,14 @@ security-bootstrap-validate-kit: ## Validate non-secret king credential metadata
|
|||||||
--metadata "$(SECURITY_BOOTSTRAP_METADATA)" \
|
--metadata "$(SECURITY_BOOTSTRAP_METADATA)" \
|
||||||
validate-king-kit
|
validate-king-kit
|
||||||
|
|
||||||
|
security-bootstrap-validate-t02: ## Validate NET-WP-0017-T02 OpenBao audit/recovery gates
|
||||||
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py \
|
||||||
|
--metadata "$(SECURITY_BOOTSTRAP_METADATA)" \
|
||||||
|
validate-t02 \
|
||||||
|
--railiance-path "$(RAILIANCE_PLATFORM_PATH)" \
|
||||||
|
--restore-evidence "$(OPENBAO_RESTORE_EVIDENCE)" \
|
||||||
|
--emergency-evidence "$(OPENBAO_EMERGENCY_EVIDENCE)"
|
||||||
|
|
||||||
security-bootstrap-approve-custody: ## Approve custody mode metadata: make security-bootstrap-approve-custody ARGS="--mfa-enrolled-confirmed --mfa-enrollment-source identity-provider --recovery-confirmed --custody-packet-prepared --no-secret-capture-confirmed"
|
security-bootstrap-approve-custody: ## Approve custody mode metadata: make security-bootstrap-approve-custody ARGS="--mfa-enrolled-confirmed --mfa-enrollment-source identity-provider --recovery-confirmed --custody-packet-prepared --no-secret-capture-confirmed"
|
||||||
python3 tools/security-bootstrap-console/security_bootstrap_console.py \
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py \
|
||||||
--metadata "$(SECURITY_BOOTSTRAP_METADATA)" \
|
--metadata "$(SECURITY_BOOTSTRAP_METADATA)" \
|
||||||
@@ -212,6 +223,7 @@ security-bootstrap-ui: security-bootstrap-metadata-init ## Serve local custody a
|
|||||||
creds-agent-init creds-agent-status creds-emergency-reprint \
|
creds-agent-init creds-agent-status creds-emergency-reprint \
|
||||||
iam-profile-conformance-test playbook-contract-test \
|
iam-profile-conformance-test playbook-contract-test \
|
||||||
security-bootstrap-console security-bootstrap-king-kit \
|
security-bootstrap-console security-bootstrap-king-kit \
|
||||||
security-bootstrap-validate-kit security-bootstrap-approve-custody \
|
security-bootstrap-validate-kit security-bootstrap-validate-t02 \
|
||||||
|
security-bootstrap-approve-custody \
|
||||||
security-bootstrap-custody-packet security-bootstrap-openbao-preflight \
|
security-bootstrap-custody-packet security-bootstrap-openbao-preflight \
|
||||||
security-bootstrap-metadata-init security-bootstrap-ui
|
security-bootstrap-metadata-init security-bootstrap-ui
|
||||||
|
|||||||
@@ -216,6 +216,17 @@ python3 tools/security-bootstrap-console/security_bootstrap_console.py openbao-p
|
|||||||
|
|
||||||
This still does not run `bao operator init`.
|
This still does not run `bao operator init`.
|
||||||
|
|
||||||
|
Validate the current NET-WP-0017-T02 OpenBao audit/recovery gates:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make security-bootstrap-validate-t02
|
||||||
|
```
|
||||||
|
|
||||||
|
The validator checks local non-secret metadata, the next independent quorum
|
||||||
|
holder, the Audit Core retention/risk decision, and the Railiance restore and
|
||||||
|
emergency-drill evidence validators. It fails until real evidence files exist
|
||||||
|
and the remaining T02 metadata gates are recorded.
|
||||||
|
|
||||||
OpenBao itself is operated from the Railiance runbook. Public ingress is
|
OpenBao itself is operated from the Railiance runbook. Public ingress is
|
||||||
disabled, so the live ceremony uses Railiance `make` targets, `kubectl exec`,
|
disabled, so the live ceremony uses Railiance `make` targets, `kubectl exec`,
|
||||||
or an operator port-forward. The local UI can record non-secret milestones
|
or an operator port-forward. The local UI can record non-secret milestones
|
||||||
|
|||||||
@@ -647,9 +647,10 @@ def print_status(data: dict[str, Any]) -> None:
|
|||||||
print("2. custody-packet")
|
print("2. custody-packet")
|
||||||
print("3. openbao-preflight")
|
print("3. openbao-preflight")
|
||||||
print("4. handover-checklist")
|
print("4. handover-checklist")
|
||||||
print("5. metadata-template")
|
print("5. validate-t02")
|
||||||
print("6. approve-custody-mode")
|
print("6. metadata-template")
|
||||||
print("7. web-ui")
|
print("7. approve-custody-mode")
|
||||||
|
print("8. web-ui")
|
||||||
print("")
|
print("")
|
||||||
print("Refusal boundary")
|
print("Refusal boundary")
|
||||||
print("This console will not run bao operator init or collect secret values.")
|
print("This console will not run bao operator init or collect secret values.")
|
||||||
@@ -694,6 +695,168 @@ def print_validate_king_kit(data: dict[str, Any]) -> int:
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def valid_review_date(value: Any) -> bool:
|
||||||
|
try:
|
||||||
|
datetime.strptime(str(value).strip(), "%Y-%m-%d")
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def independent_quorum_holder_ready(data: dict[str, Any]) -> bool:
|
||||||
|
holder = str(data.get("role_future_quorum_email") or "").strip().lower()
|
||||||
|
if not holder:
|
||||||
|
return False
|
||||||
|
current_holders = {
|
||||||
|
str(data.get(key) or "").strip().lower()
|
||||||
|
for key in (
|
||||||
|
"role_setup_operator_email",
|
||||||
|
"role_platform_custodian_email",
|
||||||
|
"role_identity_admin_email",
|
||||||
|
"role_openbao_operator_email",
|
||||||
|
"role_recovery_custodian_email",
|
||||||
|
"notification_contact",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
current_holders.discard("")
|
||||||
|
return holder not in current_holders
|
||||||
|
|
||||||
|
|
||||||
|
def independent_quorum_holder_reason(data: dict[str, Any]) -> str:
|
||||||
|
holder = str(data.get("role_future_quorum_email") or "").strip()
|
||||||
|
if not holder:
|
||||||
|
return "Record the next independent escrow/quorum holder email before moving beyond temporary single-king custody."
|
||||||
|
if not independent_quorum_holder_ready(data):
|
||||||
|
return "Future quorum holder is recorded but is not independent from the current bootstrap/custody roles."
|
||||||
|
return "Future quorum holder is recorded as independent from the current bootstrap/custody roles."
|
||||||
|
|
||||||
|
|
||||||
|
def audit_core_posture_ready(data: dict[str, Any]) -> bool:
|
||||||
|
if yes(data, "audit_core_production_sink_ready"):
|
||||||
|
return True
|
||||||
|
return (
|
||||||
|
yes(data, "audit_core_bootstrap_risk_accepted")
|
||||||
|
and bool(str(data.get("audit_core_risk_owner") or "").strip())
|
||||||
|
and valid_review_date(data.get("audit_core_risk_review_date"))
|
||||||
|
and bool(str(data.get("audit_core_risk_note") or "").strip())
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def audit_core_posture_reason(data: dict[str, Any]) -> str:
|
||||||
|
if yes(data, "audit_core_production_sink_ready"):
|
||||||
|
return "Production Audit Core retention is recorded as ready."
|
||||||
|
missing: list[str] = []
|
||||||
|
if not yes(data, "audit_core_bootstrap_risk_accepted"):
|
||||||
|
missing.append("risk acceptance")
|
||||||
|
if not str(data.get("audit_core_risk_owner") or "").strip():
|
||||||
|
missing.append("owner")
|
||||||
|
if not valid_review_date(data.get("audit_core_risk_review_date")):
|
||||||
|
missing.append("review date")
|
||||||
|
if not str(data.get("audit_core_risk_note") or "").strip():
|
||||||
|
missing.append("risk note")
|
||||||
|
if missing:
|
||||||
|
return "Production Audit Core retention is deferred; record " + ", ".join(missing) + "."
|
||||||
|
return "Temporary bootstrap audit-retention risk exception is recorded with owner and review date."
|
||||||
|
|
||||||
|
|
||||||
|
def compact_command_output(text: str) -> str:
|
||||||
|
lines = [line.strip() for line in text.splitlines() if line.strip()]
|
||||||
|
return lines[-1] if lines else "No validator output captured."
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_cli_path(value: str | Path) -> Path:
|
||||||
|
path = Path(value).expanduser()
|
||||||
|
if not path.is_absolute():
|
||||||
|
path = (Path.cwd() / path).resolve()
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def evidence_validator_gate(
|
||||||
|
name: str,
|
||||||
|
railiance_path: Path,
|
||||||
|
target: str,
|
||||||
|
env_key: str,
|
||||||
|
evidence_path: Path,
|
||||||
|
) -> Gate:
|
||||||
|
if not railiance_path.is_dir():
|
||||||
|
return Gate(name, "blocked", f"Railiance repo not found: {railiance_path}")
|
||||||
|
if not evidence_path.exists():
|
||||||
|
return Gate(name, "blocked", f"Evidence file missing: {evidence_path}")
|
||||||
|
result = subprocess.run(
|
||||||
|
["make", target, f"{env_key}={evidence_path}"],
|
||||||
|
cwd=railiance_path,
|
||||||
|
text=True,
|
||||||
|
capture_output=True,
|
||||||
|
check=False,
|
||||||
|
)
|
||||||
|
output = compact_command_output(result.stdout + "\n" + result.stderr)
|
||||||
|
if result.returncode == 0:
|
||||||
|
return Gate(name, "done", output)
|
||||||
|
return Gate(name, "blocked", output)
|
||||||
|
|
||||||
|
|
||||||
|
def t02_metadata_gates(data: dict[str, Any]) -> list[Gate]:
|
||||||
|
return [
|
||||||
|
Gate(
|
||||||
|
"Restore drill metadata",
|
||||||
|
"done" if yes(data, "restore_drill_passed") else "blocked",
|
||||||
|
"Record the restore drill completion flag only after evidence exists and validates.",
|
||||||
|
),
|
||||||
|
Gate(
|
||||||
|
"Emergency seal/unseal metadata",
|
||||||
|
"done" if yes(data, "openbao_emergency_lockdown_drilled") else "blocked",
|
||||||
|
"Record the emergency drill completion flag only after an attended drill and validated evidence.",
|
||||||
|
),
|
||||||
|
Gate(
|
||||||
|
"Next independent escrow holder",
|
||||||
|
"done" if independent_quorum_holder_ready(data) else "blocked",
|
||||||
|
independent_quorum_holder_reason(data),
|
||||||
|
),
|
||||||
|
Gate(
|
||||||
|
"Audit Core retention posture",
|
||||||
|
"done" if audit_core_posture_ready(data) else "blocked",
|
||||||
|
audit_core_posture_reason(data),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def print_validate_t02(args: argparse.Namespace, data: dict[str, Any]) -> int:
|
||||||
|
merged = metadata_template()
|
||||||
|
merged.update(data)
|
||||||
|
railiance_path = resolve_cli_path(args.railiance_path)
|
||||||
|
restore_evidence = resolve_cli_path(args.restore_evidence)
|
||||||
|
emergency_evidence = resolve_cli_path(args.emergency_evidence)
|
||||||
|
gates = t02_metadata_gates(merged)
|
||||||
|
gates.extend(
|
||||||
|
[
|
||||||
|
evidence_validator_gate(
|
||||||
|
"Restore drill evidence file",
|
||||||
|
railiance_path,
|
||||||
|
"openbao-validate-restore-evidence",
|
||||||
|
"OPENBAO_RESTORE_EVIDENCE",
|
||||||
|
restore_evidence,
|
||||||
|
),
|
||||||
|
evidence_validator_gate(
|
||||||
|
"Emergency drill evidence file",
|
||||||
|
railiance_path,
|
||||||
|
"openbao-validate-emergency-evidence",
|
||||||
|
"OPENBAO_EMERGENCY_EVIDENCE",
|
||||||
|
emergency_evidence,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
print("NET-WP-0017-T02 VALIDATION")
|
||||||
|
print("")
|
||||||
|
for gate in gates:
|
||||||
|
print(f"- {gate.status}: {gate.name} - {gate.reason}")
|
||||||
|
print("")
|
||||||
|
if all(gate.status == "done" for gate in gates):
|
||||||
|
print("NET-WP-0017-T02 evidence and metadata gates are complete.")
|
||||||
|
return 0
|
||||||
|
print("NET-WP-0017-T02 is still open.")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def merged_approval_metadata(
|
def merged_approval_metadata(
|
||||||
existing: dict[str, Any],
|
existing: dict[str, Any],
|
||||||
payload: dict[str, Any],
|
payload: dict[str, Any],
|
||||||
@@ -720,6 +883,9 @@ def merged_approval_metadata(
|
|||||||
"mfa_enrollment_reference",
|
"mfa_enrollment_reference",
|
||||||
"custody_mode",
|
"custody_mode",
|
||||||
"root_token_disposition",
|
"root_token_disposition",
|
||||||
|
"audit_core_risk_owner",
|
||||||
|
"audit_core_risk_review_date",
|
||||||
|
"audit_core_risk_note",
|
||||||
"notes",
|
"notes",
|
||||||
)
|
)
|
||||||
for field in text_fields:
|
for field in text_fields:
|
||||||
@@ -754,6 +920,8 @@ def merged_approval_metadata(
|
|||||||
"openbao_oidc_auth_configured",
|
"openbao_oidc_auth_configured",
|
||||||
"openbao_oidc_admin_login_verified",
|
"openbao_oidc_admin_login_verified",
|
||||||
"restore_drill_passed",
|
"restore_drill_passed",
|
||||||
|
"audit_core_production_sink_ready",
|
||||||
|
"audit_core_bootstrap_risk_accepted",
|
||||||
"cleanup_complete",
|
"cleanup_complete",
|
||||||
"platform_reopened",
|
"platform_reopened",
|
||||||
):
|
):
|
||||||
@@ -978,6 +1146,11 @@ def metadata_template() -> dict[str, Any]:
|
|||||||
"openbao_oidc_admin_login_verified": False,
|
"openbao_oidc_admin_login_verified": False,
|
||||||
"root_token_disposition": "",
|
"root_token_disposition": "",
|
||||||
"restore_drill_passed": False,
|
"restore_drill_passed": False,
|
||||||
|
"audit_core_production_sink_ready": False,
|
||||||
|
"audit_core_bootstrap_risk_accepted": False,
|
||||||
|
"audit_core_risk_owner": "",
|
||||||
|
"audit_core_risk_review_date": "",
|
||||||
|
"audit_core_risk_note": "",
|
||||||
"cleanup_complete": False,
|
"cleanup_complete": False,
|
||||||
"platform_reopened": False,
|
"platform_reopened": False,
|
||||||
"review_date": "",
|
"review_date": "",
|
||||||
@@ -3106,6 +3279,24 @@ def ui_html() -> str:
|
|||||||
<li>Cleanup means bootstrap-era passwords, service tokens, temporary admin paths, trial OpenBao material, and plaintext secret exposure have been rotated, retired, reset, or explicitly accepted as residual risk.</li>
|
<li>Cleanup means bootstrap-era passwords, service tokens, temporary admin paths, trial OpenBao material, and plaintext secret exposure have been rotated, retired, reset, or explicitly accepted as residual risk.</li>
|
||||||
<li>Reopen means the platform is intentionally operated again under the selected custody strategy, with break-glass and restore paths known.</li>
|
<li>Reopen means the platform is intentionally operated again under the selected custody strategy, with break-glass and restore paths known.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<div class="choice-list">
|
||||||
|
<label class="choice"><input id="audit_core_production_sink_ready" type="checkbox"><span><strong>Production Audit Core sink ready</strong><span>Durable tenant-aware audit retention is available beyond the OpenBao audit PVC.</span></span></label>
|
||||||
|
<label class="choice"><input id="audit_core_bootstrap_risk_accepted" type="checkbox"><span><strong>Bootstrap audit-risk exception accepted</strong><span>Use only when ordinary onboarding proceeds before the production Audit Core sink exists.</span></span></label>
|
||||||
|
</div>
|
||||||
|
<div class="grid" style="margin-top: 14px;">
|
||||||
|
<label class="field">
|
||||||
|
<span class="label">Audit risk owner</span>
|
||||||
|
<input id="audit_core_risk_owner" type="text" autocomplete="off" title="Owner accountable for the temporary audit-retention risk exception.">
|
||||||
|
</label>
|
||||||
|
<label class="field">
|
||||||
|
<span class="label">Audit risk review date</span>
|
||||||
|
<input id="audit_core_risk_review_date" type="date" autocomplete="off" title="Date when the temporary audit-retention exception must be reviewed.">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<label class="field" style="margin-top: 14px;">
|
||||||
|
<span class="label">Audit risk note</span>
|
||||||
|
<input id="audit_core_risk_note" type="text" autocomplete="off" title="Non-secret note describing the accepted limitation and expected production Audit Core follow-up.">
|
||||||
|
</label>
|
||||||
<div class="choice-list">
|
<div class="choice-list">
|
||||||
<label class="choice"><input id="cleanup_complete" type="checkbox"><span><strong>Cleanup and hardening complete</strong><span>Bootstrap-era credentials, databases, access paths, and tainted materials have been reviewed and handled.</span></span></label>
|
<label class="choice"><input id="cleanup_complete" type="checkbox"><span><strong>Cleanup and hardening complete</strong><span>Bootstrap-era credentials, databases, access paths, and tainted materials have been reviewed and handled.</span></span></label>
|
||||||
<label class="choice"><input id="platform_reopened" type="checkbox"><span><strong>Platform reopened under custody</strong><span>The operator accepts that the platform is now running under the approved custody model.</span></span></label>
|
<label class="choice"><input id="platform_reopened" type="checkbox"><span><strong>Platform reopened under custody</strong><span>The operator accepts that the platform is now running under the approved custody model.</span></span></label>
|
||||||
@@ -3200,6 +3391,11 @@ def ui_html() -> str:
|
|||||||
"openbao_oidc_admin_login_verified",
|
"openbao_oidc_admin_login_verified",
|
||||||
"root_token_disposition",
|
"root_token_disposition",
|
||||||
"restore_drill_passed",
|
"restore_drill_passed",
|
||||||
|
"audit_core_production_sink_ready",
|
||||||
|
"audit_core_bootstrap_risk_accepted",
|
||||||
|
"audit_core_risk_owner",
|
||||||
|
"audit_core_risk_review_date",
|
||||||
|
"audit_core_risk_note",
|
||||||
"cleanup_complete",
|
"cleanup_complete",
|
||||||
"platform_reopened"
|
"platform_reopened"
|
||||||
];
|
];
|
||||||
@@ -3522,6 +3718,11 @@ def ui_html() -> str:
|
|||||||
openbao_oidc_admin_login_verified: document.getElementById("openbao_oidc_admin_login_verified").checked,
|
openbao_oidc_admin_login_verified: document.getElementById("openbao_oidc_admin_login_verified").checked,
|
||||||
root_token_disposition: document.getElementById("root_token_disposition").value,
|
root_token_disposition: document.getElementById("root_token_disposition").value,
|
||||||
restore_drill_passed: document.getElementById("restore_drill_passed").checked,
|
restore_drill_passed: document.getElementById("restore_drill_passed").checked,
|
||||||
|
audit_core_production_sink_ready: document.getElementById("audit_core_production_sink_ready").checked,
|
||||||
|
audit_core_bootstrap_risk_accepted: document.getElementById("audit_core_bootstrap_risk_accepted").checked,
|
||||||
|
audit_core_risk_owner: document.getElementById("audit_core_risk_owner").value.trim(),
|
||||||
|
audit_core_risk_review_date: document.getElementById("audit_core_risk_review_date").value.trim(),
|
||||||
|
audit_core_risk_note: document.getElementById("audit_core_risk_note").value.trim(),
|
||||||
cleanup_complete: document.getElementById("cleanup_complete").checked,
|
cleanup_complete: document.getElementById("cleanup_complete").checked,
|
||||||
platform_reopened: document.getElementById("platform_reopened").checked,
|
platform_reopened: document.getElementById("platform_reopened").checked,
|
||||||
approval_phrase: document.getElementById("approval_phrase").value,
|
approval_phrase: document.getElementById("approval_phrase").value,
|
||||||
@@ -3777,6 +3978,22 @@ def build_parser() -> argparse.ArgumentParser:
|
|||||||
sub.add_parser("status", help="Show trust stage, gates, and next safe action.")
|
sub.add_parser("status", help="Show trust stage, gates, and next safe action.")
|
||||||
sub.add_parser("king-kit", help="Print king credential kit checklist.")
|
sub.add_parser("king-kit", help="Print king credential kit checklist.")
|
||||||
sub.add_parser("validate-king-kit", help="Validate non-secret king credential metadata.")
|
sub.add_parser("validate-king-kit", help="Validate non-secret king credential metadata.")
|
||||||
|
validate_t02 = sub.add_parser("validate-t02", help="Validate NET-WP-0017-T02 evidence and metadata gates.")
|
||||||
|
validate_t02.add_argument(
|
||||||
|
"--railiance-path",
|
||||||
|
default="../railiance-platform",
|
||||||
|
help="Path to railiance-platform repo.",
|
||||||
|
)
|
||||||
|
validate_t02.add_argument(
|
||||||
|
"--restore-evidence",
|
||||||
|
default="/tmp/netkingdom-openbao-restore-drill/evidence.json",
|
||||||
|
help="Path to non-secret restore drill evidence JSON.",
|
||||||
|
)
|
||||||
|
validate_t02.add_argument(
|
||||||
|
"--emergency-evidence",
|
||||||
|
default="/tmp/netkingdom-openbao-emergency-drill/evidence.json",
|
||||||
|
help="Path to non-secret emergency seal/unseal drill evidence JSON.",
|
||||||
|
)
|
||||||
approve = sub.add_parser("approve-custody-mode", help="Approve a live-init-ready custody mode.")
|
approve = sub.add_parser("approve-custody-mode", help="Approve a live-init-ready custody mode.")
|
||||||
approve.add_argument(
|
approve.add_argument(
|
||||||
"--mode",
|
"--mode",
|
||||||
@@ -3831,7 +4048,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|||||||
def main(argv: list[str] | None = None) -> int:
|
def main(argv: list[str] | None = None) -> int:
|
||||||
parser = build_parser()
|
parser = build_parser()
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
metadata_commands = {"status", "validate-king-kit", "approve-custody-mode", "web-ui"}
|
metadata_commands = {"status", "validate-king-kit", "validate-t02", "approve-custody-mode", "web-ui"}
|
||||||
if args.command in metadata_commands and args.metadata is None:
|
if args.command in metadata_commands and args.metadata is None:
|
||||||
args.metadata = DEFAULT_METADATA_PATH
|
args.metadata = DEFAULT_METADATA_PATH
|
||||||
data = load_metadata(args.metadata)
|
data = load_metadata(args.metadata)
|
||||||
@@ -3844,6 +4061,8 @@ def main(argv: list[str] | None = None) -> int:
|
|||||||
return 0
|
return 0
|
||||||
if args.command == "validate-king-kit":
|
if args.command == "validate-king-kit":
|
||||||
return print_validate_king_kit(data)
|
return print_validate_king_kit(data)
|
||||||
|
if args.command == "validate-t02":
|
||||||
|
return print_validate_t02(args, data)
|
||||||
if args.command == "approve-custody-mode":
|
if args.command == "approve-custody-mode":
|
||||||
return print_approve_custody_mode(args, data)
|
return print_approve_custody_mode(args, data)
|
||||||
if args.command == "custody-packet":
|
if args.command == "custody-packet":
|
||||||
|
|||||||
@@ -229,6 +229,16 @@ deliberately not automated because it seals OpenBao and requires threshold
|
|||||||
unseal shares. T02 should count the emergency drill gate closed only after an
|
unseal shares. T02 should count the emergency drill gate closed only after an
|
||||||
attended drill records non-secret evidence and that evidence validates.
|
attended drill records non-secret evidence and that evidence validates.
|
||||||
|
|
||||||
|
**2026-06-02:** Added a single NetKingdom closure validator for this task:
|
||||||
|
`make security-bootstrap-validate-t02`. It combines the local non-secret
|
||||||
|
metadata gates for restore-drill completion, emergency seal/unseal completion,
|
||||||
|
next independent escrow holder, and Audit Core retention/risk posture with the
|
||||||
|
Railiance restore and emergency evidence validators. Against the current local
|
||||||
|
metadata it correctly reports T02 still open because the real evidence files
|
||||||
|
are missing, the emergency drill is not recorded, no independent future quorum
|
||||||
|
holder is recorded, and the temporary Audit Core risk posture has not yet been
|
||||||
|
accepted or replaced by a production sink.
|
||||||
|
|
||||||
### T03 - Close Trial Taint And Retire Bootstrap Admin Paths
|
### T03 - Close Trial Taint And Retire Bootstrap Admin Paths
|
||||||
|
|
||||||
```task
|
```task
|
||||||
|
|||||||
Reference in New Issue
Block a user