mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-17 12:09:27 +00:00
ci: add quality gates and release workflows
This commit is contained in:
@@ -66,9 +66,19 @@ def test_ranking_metrics_track_false_positive_reasons_by_tier() -> None:
|
||||
metrics = compute_ranking_metrics(
|
||||
[
|
||||
{"tier": "A", "outcome": FindingOutcome.VERIFIED, "time_to_verification_seconds": 10},
|
||||
{"tier": "A", "outcome": FindingOutcome.REJECTED, "reason": FalsePositiveReason.UNREACHABLE_PATH, "time_to_verification_seconds": 20},
|
||||
{
|
||||
"tier": "A",
|
||||
"outcome": FindingOutcome.REJECTED,
|
||||
"reason": FalsePositiveReason.UNREACHABLE_PATH,
|
||||
"time_to_verification_seconds": 20,
|
||||
},
|
||||
{"tier": "B", "outcome": FindingOutcome.REJECTED, "reason": FalsePositiveReason.DUPLICATE},
|
||||
{"tier": "A", "outcome": FindingOutcome.UNVERIFIED, "reason": FalsePositiveReason.UNVERIFIED, "missed_fixture_vulnerabilities": 1},
|
||||
{
|
||||
"tier": "A",
|
||||
"outcome": FindingOutcome.UNVERIFIED,
|
||||
"reason": FalsePositiveReason.UNVERIFIED,
|
||||
"missed_fixture_vulnerabilities": 1,
|
||||
},
|
||||
],
|
||||
tier="A",
|
||||
)
|
||||
|
||||
@@ -74,6 +74,7 @@ def test_quick_hunter_prompt_is_bounded() -> None:
|
||||
repo = Path("/repo/example.py")
|
||||
target = next(iter(preprocess_repository(repo.parent)[1]), None) if repo.parent.exists() else None
|
||||
assert target is None
|
||||
|
||||
class Target:
|
||||
path = "example.py"
|
||||
language = "python"
|
||||
|
||||
@@ -34,9 +34,7 @@ class BadWriteProcessor:
|
||||
|
||||
def test_runtime_emits_stage_events_and_processor_state(tmp_path: Path) -> None:
|
||||
trace_path = tmp_path / "events.jsonl"
|
||||
processor = RecordingProcessor(
|
||||
ProcessorSpec(name="recorder", version="1", handles=("stage_start",), writes=("seen_stage",))
|
||||
)
|
||||
processor = RecordingProcessor(ProcessorSpec(name="recorder", version="1", handles=("stage_start",), writes=("seen_stage",)))
|
||||
runtime = HarnessRuntime(
|
||||
scan_id="scan-1",
|
||||
config=load_config(None),
|
||||
@@ -84,10 +82,8 @@ def test_warn_contract_mode_records_degradation(tmp_path: Path) -> None:
|
||||
|
||||
def test_harness_config_serializes_models_processors_and_prompt_hashes(tmp_path: Path) -> None:
|
||||
config_path = tmp_path / "openultrasast.toml"
|
||||
config_path.write_text("[models]\nranker = \"openrouter/ranker\"\n")
|
||||
processor = RecordingProcessor(
|
||||
ProcessorSpec(name="recorder", version="2026-01-01", handles=("stage_start",), writes=("seen_stage",))
|
||||
)
|
||||
config_path.write_text('[models]\nranker = "openrouter/ranker"\n')
|
||||
processor = RecordingProcessor(ProcessorSpec(name="recorder", version="2026-01-01", handles=("stage_start",), writes=("seen_stage",)))
|
||||
output = tmp_path / "harness.json"
|
||||
|
||||
write_harness_config(
|
||||
|
||||
+1
-1
@@ -3,8 +3,8 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from openultrasast.index import CodeChunk
|
||||
from openultrasast.index import (
|
||||
CodeChunk,
|
||||
build_code_chunks,
|
||||
build_retrieval_package,
|
||||
build_vector_index,
|
||||
|
||||
+19
-17
@@ -62,18 +62,24 @@ def test_mapping_task_records_cover_disciplines(tmp_path: Path) -> None:
|
||||
|
||||
assert semgrep_mapping_tasks(semgrep_hints)[0].task == "pattern_variant_review"
|
||||
assert codeql_mapping_tasks(codeql_hints)[0].task == "source_sink_sanitizer_path_review"
|
||||
assert differential_mapping_record(
|
||||
"parser.c",
|
||||
change_kind="modified_function",
|
||||
trust_boundary="network_input",
|
||||
rationale="Parser changed behind a socket boundary.",
|
||||
).trust_boundary == "network_input"
|
||||
assert sharp_edge_record(
|
||||
"config.py",
|
||||
category="insecure_default",
|
||||
surface="debug mode",
|
||||
rationale="Debug default changes production risk.",
|
||||
).category == "insecure_default"
|
||||
assert (
|
||||
differential_mapping_record(
|
||||
"parser.c",
|
||||
change_kind="modified_function",
|
||||
trust_boundary="network_input",
|
||||
rationale="Parser changed behind a socket boundary.",
|
||||
).trust_boundary
|
||||
== "network_input"
|
||||
)
|
||||
assert (
|
||||
sharp_edge_record(
|
||||
"config.py",
|
||||
category="insecure_default",
|
||||
surface="debug mode",
|
||||
rationale="Debug default changes production risk.",
|
||||
).category
|
||||
== "insecure_default"
|
||||
)
|
||||
|
||||
|
||||
def test_write_static_hints_artifact(tmp_path: Path) -> None:
|
||||
@@ -144,11 +150,7 @@ def test_entry_point_mapping_covers_solidity_state_changing_access(tmp_path: Pat
|
||||
def test_entry_point_mapping_records_solidity_feature_conditions(tmp_path: Path) -> None:
|
||||
repo = tmp_path / "repo"
|
||||
repo.mkdir()
|
||||
(repo / "Vault.sol").write_text(
|
||||
"contract Vault {\n"
|
||||
" function withdraw(uint256 amount) external onlyOwner whenNotPaused { }\n"
|
||||
"}\n"
|
||||
)
|
||||
(repo / "Vault.sol").write_text("contract Vault {\n function withdraw(uint256 amount) external onlyOwner whenNotPaused { }\n}\n")
|
||||
_, targets = preprocess_repository(repo)
|
||||
|
||||
entry_points = analyze_entry_points(repo, targets)
|
||||
|
||||
+15
-16
@@ -93,12 +93,7 @@ def test_cli_scan_writes_accepted_and_rejected_verifications(tmp_path: Path, mon
|
||||
repo = tmp_path / "repo"
|
||||
repo.mkdir()
|
||||
(repo / "app.py").write_text(
|
||||
"@app.route('/admin')\n"
|
||||
"def admin():\n"
|
||||
" return eval(request.data)\n"
|
||||
"\n"
|
||||
"def helper(value):\n"
|
||||
" return exec(value)\n"
|
||||
"@app.route('/admin')\ndef admin():\n return eval(request.data)\n\ndef helper(value):\n return exec(value)\n"
|
||||
)
|
||||
monkeypatch.setenv("OPENULTRASAST_RUNS_DIR", ".runs")
|
||||
|
||||
@@ -113,16 +108,20 @@ def test_cli_scan_writes_accepted_and_rejected_verifications(tmp_path: Path, mon
|
||||
|
||||
|
||||
def _finding(*, evidence_level: str, reachability_status: str) -> StaticFinding:
|
||||
evidence = [
|
||||
{
|
||||
"kind": "route",
|
||||
"access_level": "public",
|
||||
"line": 1,
|
||||
"end_line": 3,
|
||||
"function_name": "admin",
|
||||
"conditions": [],
|
||||
}
|
||||
] if reachability_status == "reachable" else []
|
||||
evidence = (
|
||||
[
|
||||
{
|
||||
"kind": "route",
|
||||
"access_level": "public",
|
||||
"line": 1,
|
||||
"end_line": 3,
|
||||
"function_name": "admin",
|
||||
"conditions": [],
|
||||
}
|
||||
]
|
||||
if reachability_status == "reachable"
|
||||
else []
|
||||
)
|
||||
return StaticFinding(
|
||||
finding_id="python-unsafe-eval:app.py:3",
|
||||
path="app.py",
|
||||
|
||||
Reference in New Issue
Block a user