fix(workflow): non-forgeable irrecoverable auth, merger consumer, exact-scope cleanup (#709)

Address formal review 434 REQUEST_CHANGES on PR #710:
- F1: replace caller operator_authorized with server-side HMAC auth artifacts
- F2: implement fail-closed merger consumption for prior-provenance only
- F3: enforce remote/org/repo/head on cross-profile load and clear

Co-Authored-By: Grok 4.5 (xAI) <[email protected]>
This commit is contained in:
2026-07-14 01:36:39 -04:00
co-authored by Grok 4.5
parent ec5cf67771
commit 9cb12ee0f4
6 changed files with 2730 additions and 336 deletions
+71 -18
View File
@@ -42,6 +42,8 @@ KIND_DECISION_LOCK_ARCHIVE = "review_decision_lock_archive"
KIND_POST_MERGE_DECISION_RECOVERY = "post_merge_decision_recovery"
# #709: truthful record when historical terminal evidence is irrecoverably gone.
KIND_IRRECOVERABLE_DECISION_PROVENANCE = "irrecoverable_decision_provenance"
# #709 F1: server-side non-forgeable authorization artifact for recovery.
KIND_IRRECOVERABLE_PROVENANCE_AUTH = "irrecoverable_provenance_authorization"
# Kinds that must survive the default session-state TTL (forensic / recovery).
RECOVERY_CRITICAL_KINDS = frozenset(
@@ -49,6 +51,7 @@ RECOVERY_CRITICAL_KINDS = frozenset(
KIND_DECISION_LOCK_ARCHIVE,
KIND_POST_MERGE_DECISION_RECOVERY,
KIND_IRRECOVERABLE_DECISION_PROVENANCE,
KIND_IRRECOVERABLE_PROVENANCE_AUTH,
}
)
@@ -504,6 +507,7 @@ def load_state_for_profile(
repo: str | None = None,
state_dir: str | None = None,
skip_identity_match: bool = False,
enforce_repo_scope: bool = True,
) -> dict[str, Any] | None:
"""Load durable state for an explicit profile identity (#709 cross-profile).
@@ -511,9 +515,46 @@ def load_state_for_profile(
profile_identity to equal the requested profile (anti-stomp), but does not
require the *active* session identity to match — needed so a merger can
inspect a reviewer lock after merge.
#709 F3: remote/org/repo filter reasons are **enforced** (not merely
computed). When *enforce_repo_scope* is True (default) and the caller
supplies remote/org/repo, mismatches fail closed with ``None``.
"""
# #709 F3: refuse traversal / malformed profile identities.
try:
from irrecoverable_provenance import assess_profile_path_identity
path_gate = assess_profile_path_identity(profile_identity)
if not path_gate.get("valid"):
return None
except Exception:
# Module may be mid-import in edge bootstraps; fall through to
# conservative checks below.
raw = str(profile_identity or "")
if ".." in raw or "/" in raw or "\\" in raw or "\x00" in raw:
return None
profile = current_profile_identity(profile_identity=profile_identity)
root = _ensure_state_dir(state_dir)
# Refuse symlink escape of the state root (#709 F3).
try:
real_root = os.path.realpath(root)
path = state_file_path(
kind=kind,
remote=remote,
org=org,
repo=repo,
profile_identity=profile,
state_dir=root,
)
real_path = os.path.realpath(path) if os.path.exists(path) else path
if os.path.exists(path) and not str(real_path).startswith(
str(real_root) + os.sep
) and str(real_path) != str(real_root):
return None
except OSError:
return None
path = state_file_path(
kind=kind,
remote=remote,
@@ -548,34 +589,46 @@ def load_state_for_profile(
if stored and stored != profile:
return None
if skip_identity_match:
# Still enforce TTL / future-dated so dead records do not authorize cleanup.
# Enforce remote/org/repo when caller provides them (#709 F3).
# Drop only *active session* profile-identity mismatches; keep
# expiry, spoof, and repository-scope reasons.
scope_remote = remote if enforce_repo_scope else None
scope_org = org if enforce_repo_scope else None
scope_repo = repo if enforce_repo_scope else None
reasons = identity_match_reasons(
merged,
remote=remote or merged.get("remote"),
org=org or merged.get("org"),
repo=repo or merged.get("repo"),
remote=scope_remote,
org=scope_org,
repo=scope_repo,
profile_identity=stored or profile,
)
# Drop active-session-only mismatches; keep expiry / spoof reasons.
filtered = [
r
for r in reasons
if "profile identity mismatch" not in r
or (stored and stored != profile)
]
# Re-run only expiry/future/missing checks via identity when profile matches
expiry_reasons = [
r
for r in identity_match_reasons(
merged,
remote=None,
org=None,
repo=None,
profile_identity=stored or profile,
)
if any(x in r for x in ("expired", "future", "missing recorded_at"))
]
if expiry_reasons:
# When caller requested a specific remote/org/repo, also fail if the
# stored record lacks those identity fields entirely (legacy incomplete).
if enforce_repo_scope:
for field, want in (
("remote", remote),
("org", org),
("repo", repo),
):
want_s = (want or "").strip()
if not want_s:
continue
have = (str(merged.get(field) or "")).strip()
if not have:
filtered.append(
f"session state {field} missing on durable record "
f"(expected={want_s!r}; fail closed, #709 F3)"
)
elif have != want_s:
# identity_match_reasons already adds mismatch; ensure kept
pass
if filtered:
return None
return merged
reasons = identity_match_reasons(