Add blocked Stage 5 target admission record

This commit is contained in:
Svrnty
2026-05-31 23:48:56 -04:00
parent f8a6d6873d
commit 3f8a2eeeab
5 changed files with 132 additions and 1 deletions
+64
View File
@@ -35,6 +35,7 @@ REQUIRED_FILES = [
".sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-PRD.md",
".sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md",
".sot/03-PROTOCOLS/CTO-CASE-STAGE5-TARGET-REPOSITORY-ADMISSION-TEMPLATE.md",
".sot/03-PROTOCOLS/CTO-CASE-STAGE5-TARGET-REPOSITORY-ADMISSION.json",
".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-ADMISSION-PRD.md",
".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-ADMISSION-ISSUES.md",
".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-BUILD-PRD.md",
@@ -334,6 +335,7 @@ REQUIRED_STAGE5_ISSUE_IDS = [
"CTO-WORK-037",
"CTO-WORK-038",
"CTO-WORK-039",
"CTO-WORK-040",
]
REQUIRED_STAGE5_TARGET_ADMISSION_TEMPLATE_PHRASES = [
@@ -355,6 +357,31 @@ REQUIRED_STAGE5_TARGET_ADMISSION_TEMPLATE_PHRASES = [
"This template does not authorize owned repository mutation.",
]
REQUIRED_STAGE5_TARGET_ADMISSION_JSON = {
"admission_status": "not_admitted",
"target_repository_path": "",
"repository_owner": "",
"ownership_evidence": "",
"risk_classification": "",
"noncritical_rationale": "",
"approval_source": "",
"approval_timestamp": "",
"operator_outcome_required": True,
}
REQUIRED_STAGE5_TARGET_FORBIDDEN_ACTIONS = [
"push",
"merge",
"deploy",
"close",
"pr_open",
"issue_close",
"public_publication",
"credential_change",
"vendor_source_mutation",
"cortex_core_mutation",
]
REQUIRED_PROVIDER_ADMISSION_PRD_PHRASES = [
"Local planning SOT only. Not a Core Protocol. Not active Core authority.",
"https://github.com/workos/case.git",
@@ -1027,6 +1054,40 @@ def main() -> int:
if phrase not in text:
errors.append(f"missing_stage5_target_admission_template_phrase:{phrase}")
stage5_target_admission = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-STAGE5-TARGET-REPOSITORY-ADMISSION.json"
if stage5_target_admission.is_file():
checked.append("stage5_target_admission_json:parse")
try:
payload = json.loads(stage5_target_admission.read_text(encoding="utf-8"))
except json.JSONDecodeError as exc:
errors.append(f"stage5_target_admission_invalid_json:{exc}")
payload = {}
if not isinstance(payload, dict):
errors.append("stage5_target_admission_must_be_object")
payload = {}
for key, expected in REQUIRED_STAGE5_TARGET_ADMISSION_JSON.items():
checked.append(f"stage5_target_admission_json:{key}")
if payload.get(key) != expected:
errors.append(f"stage5_target_admission_mismatch:{key}:expected_{expected}:actual_{payload.get(key)}")
for key in ["allowed_paths", "forbidden_paths", "forbidden_actions"]:
checked.append(f"stage5_target_admission_json_list:{key}")
if not isinstance(payload.get(key), list):
errors.append(f"stage5_target_admission_missing_list:{key}")
forbidden_actions = payload.get("forbidden_actions", [])
if isinstance(forbidden_actions, list):
for action in REQUIRED_STAGE5_TARGET_FORBIDDEN_ACTIONS:
checked.append(f"stage5_target_admission_forbidden_action:{action}")
if action not in forbidden_actions:
errors.append(f"stage5_target_admission_missing_forbidden_action:{action}")
if payload.get("allowed_paths") != []:
errors.append("stage5_target_admission_allowed_paths_must_be_empty_while_not_admitted")
if not isinstance(payload.get("review_trigger"), str) or not payload.get("review_trigger"):
errors.append("stage5_target_admission_missing_review_trigger")
for key in payload:
checked.append(f"stage5_target_admission_json_secret_key:{key}")
if key.lower() in {"api_key", "apikey", "access_token", "token", "secret", "password", "credential_value"}:
errors.append(f"stage5_target_admission_forbidden_secret_key:{key}")
provider_admission_prd = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-ADMISSION-PRD.md"
if provider_admission_prd.is_file():
text = provider_admission_prd.read_text(encoding="utf-8")
@@ -1286,6 +1347,7 @@ def main() -> int:
"CTO-WORK-037": "validated",
"CTO-WORK-038": "blocked",
"CTO-WORK-039": "validated",
"CTO-WORK-040": "blocked",
}
for issue_id, expected in expected_statuses.items():
checked.append(f"workboard_status:{issue_id}:{expected}")
@@ -1326,6 +1388,8 @@ def main() -> int:
errors.append("workboard_missing_stage5_issues_source")
if "CTO-CASE-STAGE5-TARGET-REPOSITORY-ADMISSION-TEMPLATE.md" not in text:
errors.append("workboard_missing_stage5_target_admission_template_source")
if "CTO-CASE-STAGE5-TARGET-REPOSITORY-ADMISSION.json" not in text:
errors.append("workboard_missing_stage5_target_admission_json_source")
if "CTO-CASE-PROVIDER-ADMISSION-PRD.md" not in text:
errors.append("workboard_missing_provider_admission_prd_source")
if "CTO-CASE-PROVIDER-ADMISSION-ISSUES.md" not in text: