mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-18 04:29:27 +00:00
feat(governance): Phase 1 — CWE policy store + project score (zero-dep)
First implementation slice of the approved harnessx-self-improving-rulesets spec (Foundation: governance + scoring planes). Additive and zero-dependency; findings stay byte-identical and the >=90% recall / <10% FP detection gate is unchanged. - PolicyStore (policy/verycode.py): vendors verycode-policies CWE_Score.tsv (167 CWEs, CRLF + trailing-space header parsed defensively); CwePolicy(severity 0-5, static/dynamic); load_policy, resolve_severity (severity is policy-governed, keyed on CWE — one CWE = one severity), assert_rules_resolve (fail-loud if an enabled rule's CWE is unmapped). Remap the C/C++ buffer rules CWE-120 -> CWE-121 (CWE-120 is absent from verycode; 121 = Stack-Based Buffer Overflow, severity 5). - ScoreModel (scoring/project_score.py): SEV_WEIGHT, REACH_MULT, finding_penalty, project_score (0-100 exponential decay; one sev-5 reachable -> ~43), two-condition gate (sev-5+reachable always fails; score<min_score fails only when blocking), build_score_artifact. - Wire into _run_scan: policy_load + fail-loud policy_check stages; score stage writes score.json and merges a score block into the manifest (advisory-first). - ScoreConfig (k/min_score/block_severity_reachable/blocking) in config.py. - pyproject uv_build ships the vendored TSV in the wheel (verified). - Tests: test_policy, test_scoring, test_score_pipeline (artifact + fail-loud). 85 passed; ruff + mypy clean. Spec phases 1.1-2.4 checked off; spec approved. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9b399fdc60
commit
ae365f6cb7
@@ -0,0 +1,41 @@
|
||||
"""Phase 1 in-pipeline wiring: project score artifact + fail-loud CWE invariant."""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
from openultrasast import cli
|
||||
from openultrasast.cli import main
|
||||
from openultrasast.policy import PolicyError
|
||||
|
||||
|
||||
def test_scan_writes_score_artifact_and_manifest_block(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
repo = tmp_path / "repo"
|
||||
repo.mkdir()
|
||||
(repo / "app.py").write_text("@app.route('/x')\ndef view():\n return eval(request.data)\n")
|
||||
monkeypatch.setenv("OPENULTRASAST_RUNS_DIR", ".runs")
|
||||
|
||||
assert main(["scan", str(repo), "--mode", "quick"]) == 0
|
||||
|
||||
run_dir = sorted((repo / ".runs").iterdir())[-1]
|
||||
score = json.loads((run_dir / "score.json").read_text())
|
||||
manifest = json.loads((run_dir / "manifest.json").read_text())
|
||||
|
||||
assert isinstance(score["project_score"], int) and 0 <= score["project_score"] <= 100
|
||||
assert set(score["gate"]) == {"min_score", "block_severity_reachable", "blocking", "passed"}
|
||||
assert manifest["score"] == score
|
||||
assert manifest["artifacts"]["score"] == "score.json"
|
||||
|
||||
|
||||
def test_scan_fails_loud_when_an_enabled_rule_cwe_is_unmapped(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
repo = tmp_path / "repo"
|
||||
repo.mkdir()
|
||||
(repo / "app.py").write_text("x = 1\n")
|
||||
monkeypatch.setenv("OPENULTRASAST_RUNS_DIR", ".runs")
|
||||
unmapped = SimpleNamespace(rule_id="bogus", cwe="CWE-99999", status="enabled")
|
||||
monkeypatch.setattr(cli, "PATTERN_RULES", (*cli.PATTERN_RULES, unmapped))
|
||||
|
||||
with pytest.raises(PolicyError):
|
||||
main(["scan", str(repo), "--mode", "quick"])
|
||||
Reference in New Issue
Block a user