mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
feat(learning-harness): declared twins and a fixture-difficulty check
The five byte-identical vibe-py twins now say so in the catalog instead of only hashing to it, and a declared limit that names one of the unscorable vocabulary's own reasons keeps that spelling, so `identical_twin` stays one fact. Leave-one-out over vibe-py consequently runs on 30 rows, not 35. The difficulty check measures three axes the corpus varies on: binding hops from the identity source to the constrained use, registration distance, and guard distance. Measured first, and it failed: the shared obligations fixture reached (1, 0, 2) where the vibe-py absence rows reach (5, 2, 2). Every fixture handler carried its own route decorator, so nothing in the suite exercised a handler registered from another document and no binding chain was longer than one hop -- the checker was passing on a simpler world than the one it meets. `from_spec` closes that with the connexion shape those rows really have. The verdict is committed beside the numbers. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
This commit is contained in:
co-authored by
Claude Opus 5
parent
1843ef9a02
commit
d1faa04771
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"axes": [
|
||||
"binding_hops",
|
||||
"registration_distance",
|
||||
"guard_distance"
|
||||
],
|
||||
"command": "uv run pytest tests/test_fixture_difficulty.py",
|
||||
"corpus": [
|
||||
{
|
||||
"binding_hops": 5,
|
||||
"function": "get_by_title",
|
||||
"guard_distance": 1,
|
||||
"registration_distance": 2
|
||||
},
|
||||
{
|
||||
"binding_hops": 2,
|
||||
"function": "update_password",
|
||||
"guard_distance": 1,
|
||||
"registration_distance": 2
|
||||
},
|
||||
{
|
||||
"binding_hops": 0,
|
||||
"function": "get",
|
||||
"guard_distance": 2,
|
||||
"registration_distance": 0
|
||||
},
|
||||
{
|
||||
"binding_hops": 0,
|
||||
"function": "delete",
|
||||
"guard_distance": 2,
|
||||
"registration_distance": 0
|
||||
}
|
||||
],
|
||||
"corpus_reach": [
|
||||
5,
|
||||
2,
|
||||
2
|
||||
],
|
||||
"corpus_rows": [
|
||||
"vampi-books-get-by-title",
|
||||
"vampi-users-update-password",
|
||||
"threatbyte-api-v1-get",
|
||||
"threatbyte-api-v1-delete"
|
||||
],
|
||||
"fixture": [
|
||||
{
|
||||
"binding_hops": 0,
|
||||
"function": "guarded",
|
||||
"guard_distance": 0,
|
||||
"registration_distance": 0
|
||||
},
|
||||
{
|
||||
"binding_hops": 1,
|
||||
"function": "constrained",
|
||||
"guard_distance": 0,
|
||||
"registration_distance": 0
|
||||
},
|
||||
{
|
||||
"binding_hops": 1,
|
||||
"function": "constrained_too",
|
||||
"guard_distance": 1,
|
||||
"registration_distance": 0
|
||||
},
|
||||
{
|
||||
"binding_hops": 0,
|
||||
"function": "leaky",
|
||||
"guard_distance": 2,
|
||||
"registration_distance": 0
|
||||
},
|
||||
{
|
||||
"binding_hops": 5,
|
||||
"function": "from_spec",
|
||||
"guard_distance": 1,
|
||||
"registration_distance": 2
|
||||
}
|
||||
],
|
||||
"fixture_reach": [
|
||||
5,
|
||||
2,
|
||||
2
|
||||
],
|
||||
"fixture_source": "tests/test_obligation_operations.py::APP",
|
||||
"generated": "2026-09-06",
|
||||
"history": "First measured with the fixture reaching (1, 0, 2) against a corpus reaching (5, 2, 2): every shared obligations handler carried its route decorator, so nothing in the suite exercised a handler registered from another document, and no chain was longer than one binding. `from_spec` was added to the fixture to close that, and it is the connexion shape the vibe-py rows really have.",
|
||||
"note": "learning-harness Req 10.4. Higher is harder on every axis. `binding_hops` counts the assignments between the identity source and the constrained use; `registration_distance` is 0 for a route decorator on the handler, 1 for a statement elsewhere in the same file, 2 for another document entirely; `guard_distance` is 0 for a decorator guard, 1 for a call in the body, 2 for no visible guard. The comparison is per axis over the whole set: a suite covers a bug shape with several handlers between them, but its hardest case on an axis must not fall short of the corpus rows its tests claim to cover.",
|
||||
"strictly_easier": false,
|
||||
"verdict": "fixture_matches_corpus"
|
||||
}
|
||||
@@ -2324,6 +2324,7 @@ fix_policy = "silent"
|
||||
provenance = "human"
|
||||
split = "holdout"
|
||||
review_tier = "seeded"
|
||||
known_limit = "identical_twin"
|
||||
|
||||
[[pair.expected]]
|
||||
cwe = "CWE-89"
|
||||
@@ -3207,6 +3208,7 @@ fix_policy = "silent"
|
||||
provenance = "human"
|
||||
split = "train"
|
||||
review_tier = "seeded"
|
||||
known_limit = "identical_twin"
|
||||
|
||||
[[pair.expected]]
|
||||
cwe = "CWE-1336"
|
||||
@@ -3236,6 +3238,7 @@ fix_policy = "silent"
|
||||
provenance = "human"
|
||||
split = "holdout"
|
||||
review_tier = "seeded"
|
||||
known_limit = "identical_twin"
|
||||
|
||||
[[pair.expected]]
|
||||
cwe = "CWE-79"
|
||||
@@ -3354,6 +3357,7 @@ fix_policy = "silent"
|
||||
provenance = "human"
|
||||
split = "holdout"
|
||||
review_tier = "seeded"
|
||||
known_limit = "identical_twin"
|
||||
|
||||
[[pair.context]]
|
||||
relpath = "openapi_specs/openapi3.yml"
|
||||
@@ -3656,6 +3660,7 @@ fix_policy = "silent"
|
||||
provenance = "human"
|
||||
split = "train"
|
||||
review_tier = "seeded"
|
||||
known_limit = "identical_twin"
|
||||
|
||||
[[pair.expected]]
|
||||
cwe = "CWE-502"
|
||||
|
||||
@@ -2290,6 +2290,7 @@ trap_id = "dsvw-fp-001"
|
||||
acceptable_cwes = ["CWE-89", "CWE-564", "CWE-943"]
|
||||
evidence = "SQL injection via id parameter directly concatenated into SELECT query without sanitization"
|
||||
commit_url = "https://github.com/stamparm/DSVW/blob/7d40f4b7939c901610ed9b85724552d60e7d63fa/dsvw.py#L30"
|
||||
known_limit = "identical_twin"
|
||||
split = "holdout"
|
||||
|
||||
[[recipe]]
|
||||
@@ -3167,6 +3168,7 @@ trap_id = "python-insecure-app-fp-001"
|
||||
acceptable_cwes = ["CWE-1336", "CWE-94", "CWE-95"]
|
||||
evidence = "Server-Side Template Injection via Jinja2. User-controlled 'name' query parameter is interpolated into an f-string on line 38 to build 'content', which is then passed to Template(content).render() on line 41. An attacker can inject Jinja2 t"
|
||||
commit_url = "https://github.com/kolega-ai/realvuln-python-insecure-app/blob/80b894a2f754590747a31c92b2088be086421953/app/main.py#L41"
|
||||
known_limit = "identical_twin"
|
||||
split = "train"
|
||||
|
||||
[[recipe]]
|
||||
@@ -3198,6 +3200,7 @@ trap_id = "python-ssti-fp-001"
|
||||
acceptable_cwes = ["CWE-79", "CWE-80"]
|
||||
evidence = "The Jinja2 Environment is created with default settings (autoescape=False). User input from the 'username' query parameter is concatenated into the template string and the rendered output is returned as HTMLResponse. An attacker can inject "
|
||||
commit_url = "https://github.com/TheWation/PythonSSTI/blob/76339c27d5a870c0a81bad6aee5f9bd516592145/main.py#L14"
|
||||
known_limit = "identical_twin"
|
||||
split = "holdout"
|
||||
|
||||
[[recipe]]
|
||||
@@ -3328,6 +3331,7 @@ evidence = "Broken Object Level Authorization (BOLA). When vuln=1, get_by_title
|
||||
commit_url = "https://github.com/erev0s/VAmPI/blob/1713b54b601ad29582581eeda4b31fceb1319874/api_views/books.py#L51"
|
||||
family = "access_control"
|
||||
context = ["openapi_specs/openapi3.yml"]
|
||||
known_limit = "identical_twin"
|
||||
split = "holdout"
|
||||
|
||||
[[recipe]]
|
||||
@@ -3672,6 +3676,7 @@ trap_id = "vulnpy-fp-011"
|
||||
acceptable_cwes = ["CWE-502", "CWE-94"]
|
||||
evidence = "User input encoded to bytes and passed to pickle.load(), which can execute arbitrary code via crafted pickle payloads"
|
||||
commit_url = "https://github.com/Contrast-Security-OSS/vulnpy/blob/d1d0f64c06f038fe59a049e0e6001bfaf9839697/src/vulnpy/trigger/deserialization.py#L8"
|
||||
known_limit = "identical_twin"
|
||||
split = "train"
|
||||
|
||||
[[recipe]]
|
||||
|
||||
Reference in New Issue
Block a user