mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 11:49:28 +00:00
feat(pre-push-safety-net): exclude vendor inputs and partition frontend coverage
This commit is contained in:
+16
-5
@@ -181,8 +181,19 @@ unsupported Go partition is reported explicitly. One ranker decision and one reg
|
||||
limit cover both supported frontends. The shared 900-second budget is a lab allowance;
|
||||
this check establishes neither production hook latency nor framework admission.
|
||||
|
||||
Current status (2026-09-13): this is a failing regression on Joern 4.0.625. The
|
||||
projected JavaScript test file is readable but absent from the resulting graph.
|
||||
See `benchmarks/measurements/2026-09-13-partition-retention-blocker.json` and the
|
||||
proposed contributor-scan frontend-retention prerequisite. An exit 1 is expected
|
||||
until that engine contract is repaired; do not treat it as a passing partition smoke.
|
||||
Stock Joern 4.0.625 fails the retention check: the projected test file is readable
|
||||
but absent from the graph. The approved source adaptation fixes both test filters;
|
||||
see `frontend-retention/README.md` for build pins and inclusion policy, and
|
||||
`benchmarks/measurements/2026-09-13-frontend-retention-smoke.json` for passing
|
||||
foundation verification. The earlier failing evidence remains in
|
||||
`benchmarks/measurements/2026-09-13-partition-retention-blocker.json`.
|
||||
|
||||
Setting `OUSAST_SMOKE_INCLUDE_TESTS=0` in the container explicitly disables the
|
||||
backend inclusion policy; that negative control must fail the retention assertion.
|
||||
The expanded task 3.4 smoke also verifies first-party browser-path retention and
|
||||
unshipped test-path records. Runtime origin remains unspecified without declarations.
|
||||
|
||||
`ops/smoke_partition_census.py`, using the same container invocation, builds a small
|
||||
readable Python graph and exercises the production taint, dominance and configuration
|
||||
batch queries. Each must return the actual source filename in its census. This
|
||||
checks query compilation and census transport, not security-property coverage.
|
||||
|
||||
@@ -95,6 +95,10 @@ def main() -> None:
|
||||
enriched = result.change_context
|
||||
assert enriched is not None and enriched.relationships, "changed context did not reach any question"
|
||||
assert result.scope is not None and result.scope.selected
|
||||
invalid_census = {"cpg_empty", "files_unparsed", "partition_file_census_unavailable", "partition_file_census_incomplete"}
|
||||
assert not invalid_census.intersection(result.scope.unresolved_boundaries), result.scope
|
||||
assert not any(d.get("reason") in invalid_census for d in result.degradations), result.degradations
|
||||
assert result.question_outcomes and all(outcome.status == "completed" for outcome in result.question_outcomes), result
|
||||
selected = {question.identity for question in result.scope.selected}
|
||||
assert any(relation.target in selected for relation in enriched.relationships)
|
||||
assert result.findings, "controlled unchanged sink has no witness"
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
"""Compile all production batch censuses on a readable real Python graph."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import tempfile
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from openultrasast.cpg.backend import JoernBackend
|
||||
from openultrasast.model.contracts import ExecutionBudget
|
||||
|
||||
|
||||
def main() -> None:
|
||||
budget = ExecutionBudget(time.monotonic() + 600, 2.0)
|
||||
results = {}
|
||||
with tempfile.TemporaryDirectory(prefix="ousast-census-smoke-") as temporary:
|
||||
root = Path(temporary)
|
||||
source = root / "probe.py"
|
||||
source.write_text("def handler(value):\n return value\n")
|
||||
data = source.read_bytes()
|
||||
assert data, "source input unreadable"
|
||||
backend = JoernBackend(heap_mb=1024, execution_budget=budget)
|
||||
graph = backend.build(root, language="python")
|
||||
assert graph is not None and graph.run_batch is not None, "real Python graph unavailable"
|
||||
try:
|
||||
for kind in ("taint", "dominance", "config"):
|
||||
answer = graph.run_batch(kind, {"probe": {"file": "probe.py", "function": "handler"}})
|
||||
assert isinstance(answer, dict) and "probe" in answer, f"{kind} batch unanswered"
|
||||
census = answer.get("__census__")
|
||||
assert isinstance(census, list) and census, f"{kind} census missing"
|
||||
names = census[0].get("file_names")
|
||||
assert isinstance(names, list) and any(str(p).endswith("probe.py") for p in names), census
|
||||
assert int(census[0]["methods"]) > 0, census
|
||||
results[kind] = census
|
||||
finally:
|
||||
graph.cleanup()
|
||||
print(
|
||||
json.dumps(
|
||||
{
|
||||
"purpose": "Real Python batch schema and query compilation; no security property admission claim",
|
||||
"source_bytes": len(data),
|
||||
"source_sha256": hashlib.sha256(data).hexdigest(),
|
||||
"shared_budget_seconds": 600,
|
||||
"censuses": results,
|
||||
},
|
||||
indent=2,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -39,6 +39,7 @@ def main() -> None:
|
||||
sources = {
|
||||
"src/api.php": "<?php\nfunction php_handler($req) { eval($req); }\n",
|
||||
"server/api.js": "function js_handler(req) { eval(req.query.code); }\n",
|
||||
"browser/client.js": "function browser_marker() { return 42; }\n",
|
||||
"tests/probe.php": "<?php\nfunction php_test_marker() { return 42; }\n",
|
||||
"tests/probe.js": "function js_test_marker() { return 42; }\n",
|
||||
"vendor/library.php": "<?php\nfunction vendor_php_marker($req) { eval($req); }\n",
|
||||
@@ -91,6 +92,8 @@ def main() -> None:
|
||||
assert any(str(filename).endswith(path) for filename in files), witness
|
||||
assert method in methods, witness
|
||||
assert "php_handler" not in methods, witness
|
||||
assert any(str(path).endswith("browser/client.js") for path in files), witness
|
||||
assert "browser_marker" in methods, witness
|
||||
else:
|
||||
raise AssertionError(f"unexpected frontend: {language}")
|
||||
records.append({"frontend": language, "input_root": str(root), "graph_witness": witness})
|
||||
@@ -116,12 +119,20 @@ def main() -> None:
|
||||
)
|
||||
assert {record["frontend"] for record in records} == {"php", "javascript"}, records
|
||||
assert result.scope is not None
|
||||
invalid_census = {"cpg_empty", "files_unparsed", "partition_file_census_unavailable", "partition_file_census_incomplete"}
|
||||
assert not invalid_census.intersection(result.scope.unresolved_boundaries), result.scope
|
||||
assert not any(d.get("reason") in invalid_census for d in result.degradations), result.degradations
|
||||
assert [q.identity.function for q in result.scope.selected] == ["php_handler"], result.scope
|
||||
assert {q.identity.function for q in result.scope.deferred} == {"js_handler", "php_test_marker", "js_test_marker"}, result.scope
|
||||
assert len(result.question_outcomes) == 1, result.question_outcomes
|
||||
assert result.question_outcomes[0].identity == result.scope.selected[0].identity
|
||||
assert all("vendor" not in q.identity.path and "node_modules" not in q.identity.path for q in result.scope.selected), result.scope
|
||||
assert any(p.language == "go" and p.status == "unsupported" for p in result.partitions), result.partitions
|
||||
javascript = next(p for p in result.partitions if p.language == "javascript")
|
||||
assert set(javascript.unshipped_paths) == {"tests/probe.js", *suffix_tests}, javascript
|
||||
assert javascript.runtime == "unspecified", "runtime role needs declared evidence"
|
||||
php = next(p for p in result.partitions if p.language == "php")
|
||||
assert php.unshipped_paths == ("tests/probe.php",), php
|
||||
assert all(not Path(record["input_root"]).exists() for record in records), "partition scratch leaked"
|
||||
report = {
|
||||
"purpose": "Real mixed PHP/JavaScript graph census and one global ranker budget; no admission or latency claim",
|
||||
|
||||
Reference in New Issue
Block a user