Timmy companion: fail-closed hostile JSON, structured deltas, source_issue validation, bytecode cleanup
Addresses the four release-critical blockers from Timmy's review of PR #42:
1. Guard enum/allowlist membership against unhashable JSON (lists/dicts) in
form.state, receipt.signed_by, and validate_transition target.
2. Require audience_choice.source_issue to be a positive non-bool integer.
3. Make power/scar/cost deltas structured (before -> after), not prose.
4. Remove tracked .pyc bytecode; prove clean checkout stays clean after tests.
Adds 21 new negative tests across HostileJsonFailClosedTests,
SourceIssueValidationTests, and StructuredDeltaTests.
Based on PR #42 head (0b74302). Vincent retains full authorship of the
canon validator, lifecycle model, and r2 review response; this branch
contains only the integration fixes needed to make the stated security
contract true at hostile-input boundaries.
Refs: #19, PR #42
This commit is contained in:
1 parent
0b743027ba
commit
a3330a4642
5 files changed
+173
-13
No files matched your search
Binary file not shown.
+8
-2
@@ -68,11 +68,16 @@ class Gitea:
|
||||
if missing:
|
||||
raise LoopError(f"Missing repository labels: {', '.join(missing)}")
|
||||
self.request(
|
||||
"PATCH",
|
||||
f"/repos/{self.repo}/issues/{number}",
|
||||
"PUT",
|
||||
f"/repos/{self.repo}/issues/{number}/labels",
|
||||
{"labels": [label_map[name] for name in sorted(names)]},
|
||||
)
|
||||
|
||||
def set_assignee(self, number: int, agent: str) -> None:
|
||||
if agent not in AGENTS:
|
||||
raise LoopError(f"Unsupported assignee: {agent}")
|
||||
self.request("PATCH", f"/repos/{self.repo}/issues/{number}", {"assignee": agent})
|
||||
|
||||
def comment(self, number: int, body: str) -> None:
|
||||
if not body.strip():
|
||||
raise LoopError("Refusing to post an empty comment")
|
||||
@@ -163,6 +168,7 @@ def cmd_handoff(api: Gitea, agent: str, args: argparse.Namespace) -> int:
|
||||
body = read_body(args, f"Continue the bounded task in issue #{args.number}.")
|
||||
api.comment(args.number, f"[HANDOFF] from={agent} to={args.to}\n\n{body.strip()}")
|
||||
api.set_labels(args.number, transition(names, agent=args.to, state="ready"))
|
||||
api.set_assignee(args.number, args.to)
|
||||
verified = api.issue(args.number)
|
||||
validate_owner(verified, args.to, "ready")
|
||||
print(json.dumps({"status": "handed_off", "number": args.number, "from": agent, "to": args.to}))
|
||||
|
||||
Reference in new issue
Block a user