feat(prover): delivery B: handler-named operations, Symfony, Livewire, Remix and Tornado entries, enforcement witnesses, memoised path walk

Codex delivery under spec access-control-prover plus one fix of mine. Operation rows may now name a handler by
name pattern and framework (Jenkins form validation and list filling, Tornado request methods, Remix actions);
the mapper recognises Symfony, Livewire and Laravel controllers, Remix exports and Tornado handlers;
`obligations/enforcement.py` turns Laravel route middleware, Symfony attributes and security.yaml rules and
Tornado's authenticated decorator into router and decorator witnesses. The path walk looks each node's callers
up once per change and does not walk a tree with no recognised entry: one seatunnel change fell from 670 s to
35 s. One name Codex could not source (Tornado get_current_user) is left out and said so in the facts header.

Smoke on the 23 fix changes: 15 pushes caught (65 percent, Wilson 45 to 81), 55 of 93 locations, precision
15 of 15 flagged, no instrument failure, no change over 120 s. Delivery A caught 7.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
Marius Ciepluch
2026-10-14 17:31:07 +02:00
co-authored by Claude Fable 5.1
parent 7f1b820d5a
commit 17e07b36c4
18 changed files with 1179 additions and 66 deletions
+30
View File
@@ -111,3 +111,33 @@ def test_discharge_witness_covers_operation_only_when_kind_and_provenance_fit()
assert covering["constrained"] == ["identity_constraint"] and covering["constrained_too"] == ["identity_constraint"]
assert covering["leaky"] == [] # request-bound identity does not cover
assert covering["guarded"] == [] # a path guard does not cover a protected read (only privileged actions)
def test_handler_named_operations_are_framework_scoped():
from openultrasast.semantic.obligations import load_obligation_facts
from openultrasast.semantic.obligations.operations import find_operations
text = "class Handler:\n def open(self):\n pass\n def helper(self):\n pass\n"
ir = parse_file("app.py", text, "python")
facts = load_obligation_facts().for_language("python")
assert find_operations(ir, facts, text=text) == ()
assert find_operations(ir, facts, text=text, handlers_of={"open": "other"}) == ()
(op,) = find_operations(ir, facts, text=text, handlers_of={"open": "tornado", "helper": "tornado"})
assert (op.function, op.line, op.requires) == ("open", 2, ("path_guard",))
def test_handler_rows_in_java_and_typescript():
from openultrasast.semantic.obligations import load_obligation_facts
from openultrasast.semantic.obligations.operations import find_operations
facts = load_obligation_facts()
cases = [
("java", "stapler", "class Editor { public void doFillNamesItems() {} }", "doFillNamesItems", ("path_guard",)),
("typescript", "remix", "export function action() { return 1; }", "action", ("path_guard", "ownership_check")),
]
for language, framework, text, name, requires in cases:
ir = parse_file(f"app.{language}", text, language)
assert ir.parse_ok
assert find_operations(ir, facts.for_language(language), text=text) == ()
(operation,) = find_operations(ir, facts.for_language(language), text=text, handlers_of={name: framework})
assert operation.line == 1 and operation.requires == requires and operation.function == name