mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 19:59:26 +00:00
fix(pre-push-safety-net): take the operation symbol from the call (M1b 12.1)
Admission extracted everything before the first parenthesis, so the operation for `const preTax = eval(req.body.preTax)` was `const preTax = eval`. No real declaration can enumerate every assignment a codebase might write, so admission would have rejected genuine findings on operation_semantics_mismatch. The M1b demonstration only passed because its declaration listed the assignment spellings. The symbol is now the trailing qualified callee. Receiver spelling stays part of it, so `$wpdb->prepare` and `prepare` remain different operations and a declaration cannot widen from one to the other. A spelling that is not a qualified name, such as a dynamic `handlers[name](x)`, yields the statement text, matches no declaration and stays ineligible exactly as before. Controls cover the assigned call, the receiver distinction, the dynamic spelling, and that a declaration for a different operation still does not cover it. The recorded-veto report reads the same helper instead of repeating the extraction. 1,403 tests passed, nine skipped. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
This commit is contained in:
co-authored by
Claude Opus 5
parent
6653b6aca8
commit
4ee31142ab
@@ -231,3 +231,35 @@ def test_an_operation_the_change_introduced_is_a_supported_change_basis():
|
||||
invented = replace(candidate, delta=replace(candidate.delta, reason="operation_moved_within_change"))
|
||||
disposition = admit_candidates((invented,), capabilities=(capability,)).dispositions[0]
|
||||
assert not disposition.admitted and "change_unsupported" in disposition.reasons
|
||||
|
||||
|
||||
def test_the_operation_symbol_comes_from_the_call_not_the_statement():
|
||||
"""M1b 12.1: a declaration cannot enumerate every assignment a codebase might write."""
|
||||
from openultrasast.push.policy import operation_symbol
|
||||
|
||||
assert operation_symbol("eval(req.body.preTax)") == "eval"
|
||||
assert operation_symbol("const preTax = eval(req.body.preTax)") == "eval"
|
||||
assert operation_symbol("return os.system(full)") == "os.system"
|
||||
# Receiver spelling is part of the symbol: these are different operations.
|
||||
assert operation_symbol("$result = $wpdb->query($sql)") == "$wpdb->query"
|
||||
assert operation_symbol("$wpdb->prepare($sql)") != operation_symbol("prepare($sql)")
|
||||
# A spelling that is not a qualified name matches no declaration and stays ineligible.
|
||||
assert operation_symbol("handlers[name](x)") == "handlers[name]"
|
||||
|
||||
|
||||
def test_a_declaration_naming_the_call_now_covers_an_assigned_call():
|
||||
candidate, capability, _ = control()
|
||||
assigned = replace(
|
||||
candidate,
|
||||
delta=replace(
|
||||
candidate.delta,
|
||||
head_operation=replace(candidate.delta.head_operation, operation="const out = exec(command)"),
|
||||
site="handler.src:4:handler",
|
||||
),
|
||||
)
|
||||
covered = replace(capability, operation_symbols=("exec",))
|
||||
disposition = admit_candidates((assigned,), capabilities=(covered,)).dispositions[0]
|
||||
assert "operation_semantics_mismatch" not in disposition.reasons
|
||||
# A declaration for a different operation still does not cover it.
|
||||
other = replace(capability, operation_symbols=("query",))
|
||||
assert "operation_semantics_mismatch" in admit_candidates((assigned,), capabilities=(other,)).dispositions[0].reasons
|
||||
|
||||
Reference in New Issue
Block a user