Bind C-25 JSON to the scanned source commit (STATE-WP-0094-T03)
The checker JSON reports per repository repo_slug, source_revision (full 40-hex HEAD SHA) and source_revision_reason; C-25 findings repeat them so a findings-only consumer can bind. A dirty workplans/ tree, a non-git path, a missing HEAD or a tree changing mid-scan yields null plus a reason, never HEAD or a branch name. plan_owner_returns validates and passes the revision into every candidate and refuses findings bound elsewhere. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 692292@bnt-lap001 Assistant-Session: 89c7d8e8-e1b3-47eb-9411-a0ab227fca2f
This commit is contained in:
parent
a0083ab78c
commit
150cb0b201
6 changed files with 284 additions and 1 deletions
|
|
@ -15,6 +15,7 @@ from datetime import date
|
|||
_REPO = re.compile(r"^[a-z0-9][a-z0-9-]*$")
|
||||
_TASK = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]*$")
|
||||
_STATES = {"open", "claimed", "succeeded", "failed", "expired"}
|
||||
_SHA = re.compile(r"^[0-9a-f]{40}$")
|
||||
|
||||
|
||||
def _uuid(value: object) -> str:
|
||||
|
|
@ -91,6 +92,12 @@ def plan_owner_returns(
|
|||
raise ValueError("invalid repository identity")
|
||||
if report.get("result") == "error":
|
||||
raise ValueError("cannot plan from failed checker collection")
|
||||
# Passed through unchanged so candidates stay bound to the scanned commit;
|
||||
# None (unknown/dirty scan) travels as None and the eligibility builder
|
||||
# refuses it. Never substituted or guessed here.
|
||||
revision = report.get("source_revision")
|
||||
if revision is not None and (not isinstance(revision, str) or not _SHA.fullmatch(revision)):
|
||||
raise ValueError("source_revision must be a full 40-hex commit SHA or null")
|
||||
issues = report.get("issues")
|
||||
if not isinstance(issues, list):
|
||||
raise ValueError("checker issues must be a list")
|
||||
|
|
@ -100,6 +107,8 @@ def plan_owner_returns(
|
|||
raise ValueError("invalid checker issue")
|
||||
if issue.get("check_id") != "C-25" or "owner_return" not in issue:
|
||||
continue
|
||||
if issue.get("repo_slug", repo) != repo or issue.get("source_revision", revision) != revision:
|
||||
raise ValueError("C-25 finding is bound to a different repository or revision")
|
||||
context = issue["owner_return"]
|
||||
if not isinstance(context, Mapping):
|
||||
raise ValueError("invalid owner-return context")
|
||||
|
|
@ -118,7 +127,8 @@ def plan_owner_returns(
|
|||
encoded = json.dumps([repo, task, message], separators=(",", ":")).encode()
|
||||
event = "owner-return:" + hashlib.sha256(encoded).hexdigest()
|
||||
candidates[event] = {
|
||||
"target_repo": repo, "task_record_id": task, "message_id": message,
|
||||
"target_repo": repo, "source_revision": revision,
|
||||
"task_record_id": task, "message_id": message,
|
||||
"activity_definition_id": definition, "triggering_event_id": event,
|
||||
"disposition": "stopped" if stop else "reviewable",
|
||||
"stop_reason": stop, "ops_run_id": None,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue