fix(#664): remediate break-glass restart workflow blockers B1, B6/B11, B9, B10, B8, and B12
This commit is contained in:
+304
-66
@@ -236,16 +236,15 @@ def _effective_workspace_role() -> str:
|
||||
def _profile_role_kind(profile: dict) -> str:
|
||||
"""Resolve a profile's declared role before inferring from permissions.
|
||||
|
||||
Declared ``role`` / ``role_kind`` always wins so a controller profile is
|
||||
never reclassified as reconciler from permission inference (#840).
|
||||
Declared ``role`` / ``role_kind`` or profile_name containing 'controller'
|
||||
always resolves to 'controller' (#840/#664).
|
||||
"""
|
||||
role = (profile.get("role") or profile.get("role_kind") or "").strip().lower()
|
||||
if role:
|
||||
# Normalize aliases / case.
|
||||
if "control" in role:
|
||||
return "controller"
|
||||
return role
|
||||
profile_name = (profile.get("profile_name") or "").strip().lower()
|
||||
role = (profile.get("role") or profile.get("role_kind") or "").strip().lower()
|
||||
if "controller" in profile_name or "control" in role or role == "controller":
|
||||
return "controller"
|
||||
if role:
|
||||
return role
|
||||
for candidate in (
|
||||
"controller",
|
||||
"reconciler",
|
||||
@@ -23923,7 +23922,7 @@ def gitea_request_mcp_restart(
|
||||
|
||||
|
||||
BREAK_GLASS_CONFIRMATION_PHRASE = "I_ACKNOWLEDGE_BREAK_GLASS_MCP_RESTART_DISRUPTION"
|
||||
PRIVILEGED_BREAK_GLASS_ROLES = frozenset({"controller", "operator", "admin", "sysadmin"})
|
||||
PRIVILEGED_BREAK_GLASS_ROLES = frozenset({"controller"})
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
@@ -23944,25 +23943,25 @@ def gitea_break_glass_restart(
|
||||
|
||||
Break-glass restart permits emergency recovery when graceful drain cannot
|
||||
complete. It requires:
|
||||
1. Privileged caller authorization (explicit allowlist: controller, operator,
|
||||
admin, sysadmin; ordinary roles and unknown/malformed roles fail closed).
|
||||
1. Privileged caller authorization (explicit allowlist: controller;
|
||||
ordinary roles and unknown/malformed roles fail closed).
|
||||
2. Explicit non-empty reason (minimum 10 characters).
|
||||
3. Exact confirmation string matching 'I_ACKNOWLEDGE_BREAK_GLASS_MCP_RESTART_DISRUPTION'.
|
||||
4. Mandatory impact acknowledgement (impact_ack=True).
|
||||
5. Immutable append-only audit entry recorded prior to execution.
|
||||
5. Immutable append-only audit entry recorded prior to execution and after terminal completion.
|
||||
6. Automatic incident record created on Gitea prior to execution.
|
||||
7. Truthful execution reporting and mandatory post-restart reconciliation (#662).
|
||||
"""
|
||||
read_block = _profile_operation_gate("gitea.read")
|
||||
read_block = _profile_operation_gate("runtime.break_glass_restart")
|
||||
if read_block:
|
||||
return {
|
||||
return gitea_audit.redact({
|
||||
"success": False,
|
||||
"performed": False,
|
||||
"break_glass_executed": False,
|
||||
"reasons": read_block,
|
||||
"permission_report": _permission_block_report("gitea.read"),
|
||||
"permission_report": _permission_block_report("runtime.break_glass_restart"),
|
||||
"blocker_kind": "permission_denied",
|
||||
}
|
||||
})
|
||||
|
||||
h, o, r = _resolve(remote, host, org, repo)
|
||||
profile = get_profile()
|
||||
@@ -23971,25 +23970,25 @@ def gitea_break_glass_restart(
|
||||
(os.environ.get("GITEA_BREAKGLASS_RESTART_AUTHORIZATION") or "").strip()
|
||||
)
|
||||
|
||||
# 1. Privileged role authorization (explicit allowlist - Finding 1 & 5)
|
||||
# 1. Privileged role authorization (explicit allowlist: controller only - B1)
|
||||
if active_role not in PRIVILEGED_BREAK_GLASS_ROLES:
|
||||
return {
|
||||
return gitea_audit.redact({
|
||||
"success": False,
|
||||
"performed": False,
|
||||
"break_glass_executed": False,
|
||||
"active_role": active_role,
|
||||
"reasons": [
|
||||
f"role '{active_role}' is not in privileged break-glass allowlist "
|
||||
f"({sorted(PRIVILEGED_BREAK_GLASS_ROLES)}); break-glass restart requires a privileged role (#664 AC1)"
|
||||
f"({sorted(PRIVILEGED_BREAK_GLASS_ROLES)}); break-glass restart requires a privileged controller role (#664 AC1)"
|
||||
],
|
||||
"blocker_kind": "role_authorization",
|
||||
}
|
||||
})
|
||||
|
||||
# 2. Required fields and redaction (Finding 3)
|
||||
# 2. Required fields and redaction (B8)
|
||||
raw_reason = (reason or "").strip()
|
||||
clean_reason = _redact(raw_reason)
|
||||
if not raw_reason or len(raw_reason) < 10:
|
||||
return {
|
||||
return gitea_audit.redact({
|
||||
"success": False,
|
||||
"performed": False,
|
||||
"break_glass_executed": False,
|
||||
@@ -23997,11 +23996,11 @@ def gitea_break_glass_restart(
|
||||
"reason is required and must be at least 10 characters long (#664 AC2)"
|
||||
],
|
||||
"blocker_kind": "missing_required_fields",
|
||||
}
|
||||
})
|
||||
|
||||
clean_confirmation = (confirmation or "").strip()
|
||||
if clean_confirmation != BREAK_GLASS_CONFIRMATION_PHRASE:
|
||||
return {
|
||||
return gitea_audit.redact({
|
||||
"success": False,
|
||||
"performed": False,
|
||||
"break_glass_executed": False,
|
||||
@@ -24009,10 +24008,10 @@ def gitea_break_glass_restart(
|
||||
f"confirmation string mismatch; must equal exactly '{BREAK_GLASS_CONFIRMATION_PHRASE}' (#664 AC2)"
|
||||
],
|
||||
"blocker_kind": "confirmation_mismatch",
|
||||
}
|
||||
})
|
||||
|
||||
if not impact_ack:
|
||||
return {
|
||||
return gitea_audit.redact({
|
||||
"success": False,
|
||||
"performed": False,
|
||||
"break_glass_executed": False,
|
||||
@@ -24020,20 +24019,20 @@ def gitea_break_glass_restart(
|
||||
"impact_ack must be True to acknowledge disruption of in-flight sessions (#664 AC2)"
|
||||
],
|
||||
"blocker_kind": "impact_ack_required",
|
||||
}
|
||||
})
|
||||
|
||||
# Gate incident issue creation on gitea.issue.create permission (Finding 3, B3)
|
||||
# Gate incident issue creation on gitea.issue.create permission (B3)
|
||||
if create_incident_issue:
|
||||
create_block = _profile_operation_gate("gitea.issue.create")
|
||||
if create_block:
|
||||
return {
|
||||
return gitea_audit.redact({
|
||||
"success": False,
|
||||
"performed": False,
|
||||
"break_glass_executed": False,
|
||||
"reasons": create_block,
|
||||
"permission_report": _permission_block_report("gitea.issue.create"),
|
||||
"blocker_kind": "permission_denied",
|
||||
}
|
||||
})
|
||||
|
||||
# Evaluate impact / disrupted sessions
|
||||
impact_result = gitea_request_mcp_restart(
|
||||
@@ -24050,11 +24049,16 @@ def gitea_break_glass_restart(
|
||||
|
||||
identity = _authenticated_username(h) or profile.get("username") or "unknown"
|
||||
now_iso = datetime.now(timezone.utc).isoformat()
|
||||
ns_ctx = _resolve_namespace_mutation_context(worktree_path)
|
||||
mcp_namespace = ns_ctx.get("mcp_namespace") or profile.get("profile_name") or "gitea-controller"
|
||||
correlation_id = f"bg-{uuid.uuid4().hex[:12]}"
|
||||
|
||||
audit_payload = {
|
||||
audit_payload = gitea_audit.redact({
|
||||
"event": "break_glass_mcp_restart",
|
||||
"correlation_id": correlation_id,
|
||||
"actor": identity,
|
||||
"role": active_role,
|
||||
"mcp_namespace": mcp_namespace,
|
||||
"timestamp": now_iso,
|
||||
"reason": clean_reason,
|
||||
"confirmation": clean_confirmation,
|
||||
@@ -24069,18 +24073,20 @@ def gitea_break_glass_restart(
|
||||
"org": o,
|
||||
"repo": r,
|
||||
"env_auth_present": break_glass_env_auth,
|
||||
}
|
||||
})
|
||||
|
||||
# 4. Dry-run handling (Finding 4, B7)
|
||||
# Dry-run handling (B7: no durable mutation)
|
||||
if dry_run:
|
||||
return {
|
||||
return gitea_audit.redact({
|
||||
"success": True,
|
||||
"performed": False,
|
||||
"dry_run": True,
|
||||
"break_glass_executed": False,
|
||||
"would_execute": True,
|
||||
"correlation_id": correlation_id,
|
||||
"actor": identity,
|
||||
"role": active_role,
|
||||
"mcp_namespace": mcp_namespace,
|
||||
"restart_class": restart_class,
|
||||
"reason": clean_reason,
|
||||
"confirmation": clean_confirmation,
|
||||
@@ -24094,11 +24100,11 @@ def gitea_break_glass_restart(
|
||||
"follow_up_issue_required": True,
|
||||
"cross_references": ["#652", "#653", "#655", "#630", "#658", "#662", "#664"],
|
||||
"reasons": ["break-glass restart dry-run evaluated successfully"],
|
||||
}
|
||||
})
|
||||
|
||||
# Fail closed if create_incident_issue is False on real execution (Finding 2, B5)
|
||||
# Fail closed if create_incident_issue is False on real execution (B5)
|
||||
if not create_incident_issue:
|
||||
return {
|
||||
return gitea_audit.redact({
|
||||
"success": False,
|
||||
"performed": False,
|
||||
"break_glass_executed": False,
|
||||
@@ -24107,12 +24113,24 @@ def gitea_break_glass_restart(
|
||||
"pre-execution incident creation is mandatory (#664 AC3)"
|
||||
],
|
||||
"blocker_kind": "incident_creation_required",
|
||||
}
|
||||
})
|
||||
|
||||
# Pre-execution recording: Audit record (Finding 2, B4)
|
||||
audit_event = gitea_audit.build_event(
|
||||
action="break_glass_mcp_restart",
|
||||
result=gitea_audit.SUCCEEDED,
|
||||
# B9: Fail closed if audit backend is disabled
|
||||
if not gitea_audit.audit_enabled():
|
||||
return gitea_audit.redact({
|
||||
"success": False,
|
||||
"performed": False,
|
||||
"break_glass_executed": False,
|
||||
"reasons": [
|
||||
"audit recording is disabled or unavailable; break-glass restart requires an enabled audit backend (#664 AC3)"
|
||||
],
|
||||
"blocker_kind": "audit_recording_failed",
|
||||
})
|
||||
|
||||
# Pre-execution recording: Audit record in REQUESTED state (B4, B10)
|
||||
pre_audit_event = gitea_audit.build_event(
|
||||
action="break_glass_mcp_restart_requested",
|
||||
result=gitea_audit.REQUESTED,
|
||||
remote=remote,
|
||||
server=(gitea_url(h, "").rstrip("/") if h else None),
|
||||
repository=r,
|
||||
@@ -24120,11 +24138,12 @@ def gitea_break_glass_restart(
|
||||
audit_label=profile.get("audit_label", "unknown"),
|
||||
authenticated_username=identity,
|
||||
reason=clean_reason,
|
||||
mcp_namespace="gitea-author",
|
||||
mcp_namespace=mcp_namespace,
|
||||
task_role=active_role,
|
||||
operation="break_glass_mcp_restart",
|
||||
now=now_iso,
|
||||
request_metadata={
|
||||
"correlation_id": correlation_id,
|
||||
"confirmation": clean_confirmation,
|
||||
"restart_class": restart_class,
|
||||
"disrupted_sessions_count": disrupted_count,
|
||||
@@ -24134,12 +24153,10 @@ def gitea_break_glass_restart(
|
||||
],
|
||||
},
|
||||
)
|
||||
audit_write_success = True
|
||||
if gitea_audit.audit_enabled():
|
||||
audit_write_success = gitea_audit.write_event(audit_event)
|
||||
audit_write_success = gitea_audit.write_event(pre_audit_event)
|
||||
|
||||
if not audit_write_success:
|
||||
return {
|
||||
return gitea_audit.redact({
|
||||
"success": False,
|
||||
"performed": False,
|
||||
"break_glass_executed": False,
|
||||
@@ -24147,13 +24164,14 @@ def gitea_break_glass_restart(
|
||||
"failed to persist required pre-execution audit event (#664 AC3)"
|
||||
],
|
||||
"blocker_kind": "audit_recording_failed",
|
||||
}
|
||||
})
|
||||
|
||||
# Pre-execution recording: Gitea Incident Issue (Finding 2 & 3, B5)
|
||||
issue_title = f"[INCIDENT] Break-glass MCP restart invoked by {identity}"
|
||||
issue_body = (
|
||||
# Pre-execution recording: Gitea Incident Issue (B5, B8)
|
||||
issue_title = _redact(f"[INCIDENT] [REQUESTED] Break-glass MCP restart invoked by {identity} ({correlation_id})")
|
||||
issue_body = _redact(
|
||||
f"## Break-glass MCP restart incident report (#664)\n\n"
|
||||
f"- **Invoked by**: `{identity}` (role: `{active_role}`)\n"
|
||||
f"- **Correlation ID**: `{correlation_id}`\n"
|
||||
f"- **Invoked by**: `{identity}` (role: `{active_role}`, namespace: `{mcp_namespace}`)\n"
|
||||
f"- **Timestamp**: `{now_iso}`\n"
|
||||
f"- **Reason**: {clean_reason}\n"
|
||||
f"- **Confirmation**: `{clean_confirmation}`\n"
|
||||
@@ -24177,18 +24195,18 @@ def gitea_break_glass_restart(
|
||||
},
|
||||
)
|
||||
if not isinstance(incident_issue_result, dict) or "number" not in incident_issue_result:
|
||||
return {
|
||||
return gitea_audit.redact({
|
||||
"success": False,
|
||||
"performed": False,
|
||||
"break_glass_executed": False,
|
||||
"reasons": [
|
||||
f"incident issue creation failed (#664 AC3): {incident_issue_result}"
|
||||
f"incident issue creation failed (#664 AC3): {_redact(str(incident_issue_result))}"
|
||||
],
|
||||
"blocker_kind": "incident_creation_failed",
|
||||
"incident_issue": incident_issue_result,
|
||||
}
|
||||
})
|
||||
except Exception as exc:
|
||||
return {
|
||||
return gitea_audit.redact({
|
||||
"success": False,
|
||||
"performed": False,
|
||||
"break_glass_executed": False,
|
||||
@@ -24197,9 +24215,11 @@ def gitea_break_glass_restart(
|
||||
],
|
||||
"blocker_kind": "incident_creation_failed",
|
||||
"incident_issue": {"error": _redact(str(exc))},
|
||||
}
|
||||
})
|
||||
|
||||
# Execute or delegate canonical non-dry-run restart (Finding 4)
|
||||
incident_number = incident_issue_result.get("number")
|
||||
|
||||
# Execute or delegate canonical non-dry-run restart (B6/B11)
|
||||
restart_exec_result = gitea_request_mcp_restart(
|
||||
remote=remote,
|
||||
host=host,
|
||||
@@ -24210,13 +24230,107 @@ def gitea_break_glass_restart(
|
||||
request_break_glass=True,
|
||||
)
|
||||
|
||||
if not restart_exec_result.get("apply_authorized") or not restart_exec_result.get("success"):
|
||||
return {
|
||||
apply_supported = bool(restart_exec_result.get("apply_supported", False))
|
||||
apply_authorized = bool(restart_exec_result.get("apply_authorized", False))
|
||||
exec_success = bool(restart_exec_result.get("success", False))
|
||||
restart_performed = bool(
|
||||
restart_exec_result.get("restart_performed", False)
|
||||
or restart_exec_result.get("break_glass_executed", False)
|
||||
)
|
||||
|
||||
if not apply_supported:
|
||||
term_audit = gitea_audit.build_event(
|
||||
action="break_glass_mcp_restart_terminal",
|
||||
result=gitea_audit.FAILED,
|
||||
remote=remote,
|
||||
server=(gitea_url(h, "").rstrip("/") if h else None),
|
||||
repository=r,
|
||||
profile_name=profile.get("profile_name", "unknown"),
|
||||
audit_label=profile.get("audit_label", "unknown"),
|
||||
authenticated_username=identity,
|
||||
reason="apply_unsupported",
|
||||
mcp_namespace=mcp_namespace,
|
||||
task_role=active_role,
|
||||
operation="break_glass_mcp_restart",
|
||||
now=datetime.now(timezone.utc).isoformat(),
|
||||
request_metadata={
|
||||
"correlation_id": correlation_id,
|
||||
"incident_number": incident_number,
|
||||
"break_glass_executed": False,
|
||||
"blocker_kind": "apply_unsupported",
|
||||
},
|
||||
)
|
||||
gitea_audit.write_event(term_audit)
|
||||
if incident_number:
|
||||
try:
|
||||
api_request(
|
||||
"POST",
|
||||
f"{repo_api_url(h, o, r)}/issues/{incident_number}/comments",
|
||||
_auth(h),
|
||||
{"body": _redact(f"**Terminal Status**: `apply_unsupported` - Restart coordinator does not support apply execution. No restart was performed. ({correlation_id})")},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return gitea_audit.redact({
|
||||
"success": False,
|
||||
"performed": False,
|
||||
"break_glass_executed": False,
|
||||
"actor": identity,
|
||||
"role": active_role,
|
||||
"mcp_namespace": mcp_namespace,
|
||||
"restart_class": restart_class,
|
||||
"reasons": [
|
||||
"break-glass apply is unsupported by restart coordinator (apply_supported=False) (#664)",
|
||||
*(restart_exec_result.get("reasons") or []),
|
||||
],
|
||||
"blocker_kind": "apply_unsupported",
|
||||
"restart_result": restart_exec_result,
|
||||
"incident_issue": incident_issue_result,
|
||||
"audit_record": pre_audit_event,
|
||||
})
|
||||
|
||||
if not apply_authorized or not exec_success or not restart_performed:
|
||||
term_audit = gitea_audit.build_event(
|
||||
action="break_glass_mcp_restart_terminal",
|
||||
result=gitea_audit.FAILED,
|
||||
remote=remote,
|
||||
server=(gitea_url(h, "").rstrip("/") if h else None),
|
||||
repository=r,
|
||||
profile_name=profile.get("profile_name", "unknown"),
|
||||
audit_label=profile.get("audit_label", "unknown"),
|
||||
authenticated_username=identity,
|
||||
reason="restart_delegation_failed",
|
||||
mcp_namespace=mcp_namespace,
|
||||
task_role=active_role,
|
||||
operation="break_glass_mcp_restart",
|
||||
now=datetime.now(timezone.utc).isoformat(),
|
||||
request_metadata={
|
||||
"correlation_id": correlation_id,
|
||||
"incident_number": incident_number,
|
||||
"break_glass_executed": False,
|
||||
"blocker_kind": "restart_delegation_failed",
|
||||
},
|
||||
)
|
||||
gitea_audit.write_event(term_audit)
|
||||
if incident_number:
|
||||
try:
|
||||
api_request(
|
||||
"POST",
|
||||
f"{repo_api_url(h, o, r)}/issues/{incident_number}/comments",
|
||||
_auth(h),
|
||||
{"body": _redact(f"**Terminal Status**: `restart_delegation_failed` - Restart execution failed or was denied. No restart was performed. ({correlation_id})")},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return gitea_audit.redact({
|
||||
"success": False,
|
||||
"performed": False,
|
||||
"break_glass_executed": False,
|
||||
"actor": identity,
|
||||
"role": active_role,
|
||||
"mcp_namespace": mcp_namespace,
|
||||
"restart_class": restart_class,
|
||||
"reasons": [
|
||||
"delegated restart execution failed or was denied by coordinator (#664)",
|
||||
@@ -24225,25 +24339,149 @@ def gitea_break_glass_restart(
|
||||
"blocker_kind": "restart_delegation_failed",
|
||||
"restart_result": restart_exec_result,
|
||||
"incident_issue": incident_issue_result,
|
||||
"audit_record": audit_event,
|
||||
}
|
||||
"audit_record": pre_audit_event,
|
||||
})
|
||||
|
||||
return {
|
||||
# Restart occurred! Perform mandatory post-restart reconciliation (B10)
|
||||
recon_result = None
|
||||
try:
|
||||
recon_result = gitea_reconcile_after_restart(
|
||||
remote=remote,
|
||||
host=host,
|
||||
org=org,
|
||||
repo=repo,
|
||||
)
|
||||
except Exception as exc:
|
||||
recon_result = {"success": False, "error": _redact(str(exc))}
|
||||
|
||||
recon_success = bool(recon_result and isinstance(recon_result, dict) and recon_result.get("success", False))
|
||||
|
||||
if not recon_success:
|
||||
term_audit = gitea_audit.build_event(
|
||||
action="break_glass_mcp_restart_terminal",
|
||||
result=gitea_audit.FAILED,
|
||||
remote=remote,
|
||||
server=(gitea_url(h, "").rstrip("/") if h else None),
|
||||
repository=r,
|
||||
profile_name=profile.get("profile_name", "unknown"),
|
||||
audit_label=profile.get("audit_label", "unknown"),
|
||||
authenticated_username=identity,
|
||||
reason="reconciliation_failed",
|
||||
mcp_namespace=mcp_namespace,
|
||||
task_role=active_role,
|
||||
operation="break_glass_mcp_restart",
|
||||
now=datetime.now(timezone.utc).isoformat(),
|
||||
request_metadata={
|
||||
"correlation_id": correlation_id,
|
||||
"incident_number": incident_number,
|
||||
"break_glass_executed": True,
|
||||
"reconciliation_success": False,
|
||||
"blocker_kind": "reconciliation_failed",
|
||||
},
|
||||
)
|
||||
gitea_audit.write_event(term_audit)
|
||||
if incident_number:
|
||||
try:
|
||||
api_request(
|
||||
"POST",
|
||||
f"{repo_api_url(h, o, r)}/issues/{incident_number}/comments",
|
||||
_auth(h),
|
||||
{"body": _redact(f"**Terminal Status**: `reconciliation_failed` - Restart was executed but post-restart reconciliation failed. ({correlation_id})")},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return gitea_audit.redact({
|
||||
"success": False,
|
||||
"performed": True,
|
||||
"break_glass_executed": True,
|
||||
"actor": identity,
|
||||
"role": active_role,
|
||||
"mcp_namespace": mcp_namespace,
|
||||
"restart_class": restart_class,
|
||||
"reasons": [
|
||||
"break-glass restart executed but post-restart reconciliation failed (#664/#662)"
|
||||
],
|
||||
"blocker_kind": "reconciliation_failed",
|
||||
"restart_result": restart_exec_result,
|
||||
"reconciliation_result": recon_result,
|
||||
"incident_issue": incident_issue_result,
|
||||
"audit_record": pre_audit_event,
|
||||
})
|
||||
|
||||
# Terminal audit append for successful execution + reconciliation
|
||||
term_audit = gitea_audit.build_event(
|
||||
action="break_glass_mcp_restart_terminal",
|
||||
result=gitea_audit.SUCCEEDED,
|
||||
remote=remote,
|
||||
server=(gitea_url(h, "").rstrip("/") if h else None),
|
||||
repository=r,
|
||||
profile_name=profile.get("profile_name", "unknown"),
|
||||
audit_label=profile.get("audit_label", "unknown"),
|
||||
authenticated_username=identity,
|
||||
reason=clean_reason,
|
||||
mcp_namespace=mcp_namespace,
|
||||
task_role=active_role,
|
||||
operation="break_glass_mcp_restart",
|
||||
now=datetime.now(timezone.utc).isoformat(),
|
||||
request_metadata={
|
||||
"correlation_id": correlation_id,
|
||||
"incident_number": incident_number,
|
||||
"break_glass_executed": True,
|
||||
"reconciliation_success": True,
|
||||
},
|
||||
)
|
||||
term_write_success = gitea_audit.write_event(term_audit)
|
||||
|
||||
if incident_number:
|
||||
try:
|
||||
api_request(
|
||||
"POST",
|
||||
f"{repo_api_url(h, o, r)}/issues/{incident_number}/comments",
|
||||
_auth(h),
|
||||
{"body": _redact(f"**Terminal Status**: `succeeded` - Break-glass restart executed and reconciled successfully ({correlation_id}).")},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if not term_write_success:
|
||||
return gitea_audit.redact({
|
||||
"success": False,
|
||||
"performed": True,
|
||||
"break_glass_executed": True,
|
||||
"actor": identity,
|
||||
"role": active_role,
|
||||
"mcp_namespace": mcp_namespace,
|
||||
"restart_class": restart_class,
|
||||
"reasons": [
|
||||
"break-glass restart executed and reconciled but terminal audit recording failed (#664)"
|
||||
],
|
||||
"blocker_kind": "terminal_audit_failed",
|
||||
"restart_result": restart_exec_result,
|
||||
"reconciliation_result": recon_result,
|
||||
"incident_issue": incident_issue_result,
|
||||
"audit_record": pre_audit_event,
|
||||
})
|
||||
|
||||
return gitea_audit.redact({
|
||||
"success": True,
|
||||
"performed": True,
|
||||
"dry_run": False,
|
||||
"break_glass_executed": True,
|
||||
"would_execute": True,
|
||||
"correlation_id": correlation_id,
|
||||
"actor": identity,
|
||||
"role": active_role,
|
||||
"mcp_namespace": mcp_namespace,
|
||||
"restart_class": restart_class,
|
||||
"reason": clean_reason,
|
||||
"confirmation": clean_confirmation,
|
||||
"disrupted_sessions_count": disrupted_count,
|
||||
"disrupted_sessions": disrupted_sessions,
|
||||
"audit_record": audit_event,
|
||||
"saved_audit": audit_event,
|
||||
"audit_record": term_audit,
|
||||
"saved_audit": term_audit,
|
||||
"incident_issue": incident_issue_result,
|
||||
"reconciliation_result": recon_result,
|
||||
"reconciliation_required": True,
|
||||
"reconciliation_tool": "gitea_reconcile_after_restart",
|
||||
"follow_up_issue_required": True,
|
||||
@@ -24251,7 +24489,7 @@ def gitea_break_glass_restart(
|
||||
"reasons": [
|
||||
"break-glass restart executed with incident creation and mandatory reconciliation"
|
||||
],
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user