mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
bench(learn): harvest signals for the decision engine (decision-engine task 5)
`ousast plane harvest` (plane/harvest.py) writes two Runs over a label snapshot:
verify a/b + agree on the verify-family units (both sides of each labelled pair as
an opaque files-only Workspace, candidates outside the hunt's root, no declared
sites; v1 and dev-php pins with repo-facts first) and model roles on the candidate
files (pair excerpts grouped, one Task per population pin). Budgets sum under the
ceiling by construction. New roles task template; the generator re-pins it.
Spent by attribution: verify $2.54 (1961 calls, 150 units, 182 hunts per pass),
roles $1.40 (1034 calls, 799 files, 0 unclassified chunks); DeepSeek balance
19.63 -> 18.23. Engine on the pair corpus (benchmarks/learn/engine_pairs.py,
frozen e6ed785, one 3g container) is PARTIAL: 384 of 686 sides at commit, still
running; unfinished sides stay missing. benchmarks/learn/build_features.py built
1712 static+plane records into the memory store; counts-only record under
benchmarks/measurements/2026-10-01-decision-engine-harvest/.
source/roles parts are `none`, not `failed`, for a language without a declaration
pattern (C). ops/ax/README: Substrate golden-actor disk leak and the inline
Workspace limit (~20 KB).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
e6ed7854bb
commit
34da916030
@@ -28,10 +28,14 @@ the maintainer confirms its budget.
|
|||||||
commits (separate, never merged); a first label snapshot committed as counts only.
|
commits (separate, never merged); a first label snapshot committed as counts only.
|
||||||
- _Requirements: 2.1, 2.2, 2.3, 7.1_
|
- _Requirements: 2.1, 2.2, 2.3, 7.1_
|
||||||
|
|
||||||
- [ ] 5. Harvest (needs budget go-ahead)
|
- [x] 5. Harvest (needs budget go-ahead)
|
||||||
- A plane Run of verify a/b on the verify-family pairs and development cases (~$6, ceiling $10), model roles on
|
- A plane Run of verify a/b on the verify-family pairs and development cases (~$6, ceiling $10), model roles on
|
||||||
the candidate files (ceiling $10), engine features for the pair corpus on the host (frozen source, one
|
the candidate files (ceiling $10), engine features for the pair corpus on the host (frozen source, one
|
||||||
container at a time, background).
|
container at a time, background).
|
||||||
|
- Done 2026-10-01 (`benchmarks/measurements/2026-10-01-decision-engine-harvest/record.json`): verify $2.54 and roles
|
||||||
|
$1.40 by attribution. The engine part was PARTIAL at commit (384 of 686 pair sides recorded, the job still
|
||||||
|
running): unfinished sides are `missing` in the feature records; rebuild them with
|
||||||
|
`benchmarks/learn/build_features.py` once `benchmarks/learn/engine_pairs.py` has finished.
|
||||||
- _Requirements: 1.1_
|
- _Requirements: 1.1_
|
||||||
|
|
||||||
- [ ] 6. Train, calibrate, evaluate
|
- [ ] 6. Train, calibrate, evaluate
|
||||||
|
|||||||
@@ -0,0 +1,363 @@
|
|||||||
|
"""Feature records for every labelled pin unit, from the harvested signals (learned-decision-engine task 5, step 3).
|
||||||
|
|
||||||
|
Host only. For each labelled pin unit of a label snapshot (``ousast learn labels --out``; conditional rows excluded),
|
||||||
|
one ``static`` and one ``plane`` record per labelled (candidate, family), built with :mod:`openultrasast.learn.features`
|
||||||
|
from:
|
||||||
|
|
||||||
|
- quick rules and deterministic roles, run here on the unit's tree: a pair side materialised from its excerpt, a
|
||||||
|
population or recipe pin exported from its clone or checkout (one at a time, deleted after, disk-guarded);
|
||||||
|
- the engine: ``benchmarks/learn/engine_pairs.py`` records for pairs, the recorded protocol scans
|
||||||
|
(``~/ousast-results/independent-v{1,2}/scans/<case>--<pin role>.json``) for populations;
|
||||||
|
- verify passes a/b and ``agree`` from the harvest Run (``harvest-verify``) and, for population v2, the recorded
|
||||||
|
``validation-46`` Run; model roles from ``harvest-roles``;
|
||||||
|
- callers and entry-point distance on a repository (``not_applicable`` on a pair excerpt: no repository exists).
|
||||||
|
|
||||||
|
An instrument that has not run for a unit yet (the engine job still running, a Run task not done) is recorded as
|
||||||
|
``failed`` with version ``missing:not-run`` -- null features, never zeros -- and counted as *missing*. Rows go to the
|
||||||
|
memory store (``OUSAST_MEMORY``, default ``~/ousast-results/plane/memory``) as kind ``features``; a rerun replaces
|
||||||
|
them by id. ``--counts`` writes the counts-only coverage record (no candidate, path or repository name).
|
||||||
|
|
||||||
|
Usage::
|
||||||
|
|
||||||
|
python benchmarks/learn/build_features.py --labels labels-<sha>.jsonl --units <harvest plane>/units.json --counts counts.json
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
from collections import Counter, defaultdict
|
||||||
|
from collections.abc import Mapping
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from openultrasast.findings import quick_scan_findings
|
||||||
|
from openultrasast.learn.features import (
|
||||||
|
NONE,
|
||||||
|
NOT_APPLICABLE,
|
||||||
|
Part,
|
||||||
|
SourceIndex,
|
||||||
|
Vocabulary,
|
||||||
|
_callers_of,
|
||||||
|
_signals,
|
||||||
|
agree_part,
|
||||||
|
engine_part,
|
||||||
|
entry_distance,
|
||||||
|
entry_names,
|
||||||
|
facts_part,
|
||||||
|
function_of,
|
||||||
|
model_sinks_part,
|
||||||
|
quick_part,
|
||||||
|
record,
|
||||||
|
roles_part,
|
||||||
|
ruleset_digest,
|
||||||
|
source_part,
|
||||||
|
verify_part,
|
||||||
|
)
|
||||||
|
from openultrasast.learn.roles import RoleSet, from_model_roles, infer_for_checkout
|
||||||
|
from openultrasast.pairs import DEFAULT_CATALOG, _materialize_side, _targets, load_pair_catalog
|
||||||
|
from openultrasast.plane import memory
|
||||||
|
from openultrasast.plane.tasks.alerts import covers
|
||||||
|
from openultrasast.plane.tasks.alerts import engine_languages as _engine_languages
|
||||||
|
from openultrasast.plane.tasks.alerts import quick_languages as _quick_languages
|
||||||
|
from openultrasast.plane.tasks.repo_facts import GLOBAL
|
||||||
|
from openultrasast.preprocess import detect_language
|
||||||
|
from openultrasast.rank import rank_targets
|
||||||
|
from openultrasast.ruleset import DEFAULT_RULESET_DIR, load_ruleset
|
||||||
|
|
||||||
|
RESULTS = Path.home() / "ousast-results"
|
||||||
|
MISSING = Part("failed", version="missing:not-run")
|
||||||
|
CONDITIONAL_SOURCES = ("benign_control", "assumed_benign")
|
||||||
|
PASSES = ("a", "b", "c")
|
||||||
|
QUICK_LANGUAGES = _quick_languages()
|
||||||
|
ENGINE_LANGUAGES = _engine_languages()
|
||||||
|
|
||||||
|
|
||||||
|
def jsonl(path: Path) -> list[dict[str, Any]]:
|
||||||
|
return [json.loads(x) for x in path.read_text(encoding="utf-8").splitlines() if x.strip()] if path.is_file() else []
|
||||||
|
|
||||||
|
|
||||||
|
def read_json(path: Path) -> Any:
|
||||||
|
return json.loads(path.read_text(encoding="utf-8")) if path.is_file() else None
|
||||||
|
|
||||||
|
|
||||||
|
def done(run: Path, entry: str) -> bool:
|
||||||
|
state = (read_json(run / "state.json") or {}).get("tasks", {})
|
||||||
|
return state.get(entry, {}).get("status") == "done"
|
||||||
|
|
||||||
|
|
||||||
|
class Signals:
|
||||||
|
"""The harvested model signals: verify/agree per unit name, model roles per unit name."""
|
||||||
|
|
||||||
|
def __init__(self, verify_run: Path, roles_run: Path, v46: Path) -> None:
|
||||||
|
self.verify_run, self.roles_run, self.v46 = verify_run, roles_run, v46
|
||||||
|
self.roles: dict[str, tuple[dict[str, Any], set[str]]] = {}
|
||||||
|
state = (read_json(roles_run / "state.json") or {}).get("tasks", {})
|
||||||
|
for entry, info in state.items():
|
||||||
|
if info.get("status") != "done":
|
||||||
|
continue
|
||||||
|
payload = read_json(roles_run / entry / "roles.json") or {}
|
||||||
|
classified = {str(r["path"]) for r in jsonl(roles_run / entry / "units.jsonl") if "error" not in r}
|
||||||
|
self._index_roles(entry.removesuffix("-roles"), payload, classified)
|
||||||
|
|
||||||
|
def _index_roles(self, owner: str, payload: Mapping[str, Any], classified: set[str]) -> None:
|
||||||
|
grouped = any("/" in p and p.split("/", 1)[0].startswith("h-") for p in classified)
|
||||||
|
if not grouped: # a pin's Task: the paths are the repository's
|
||||||
|
self.roles[owner] = (dict(payload), classified)
|
||||||
|
return
|
||||||
|
for unit in {p.split("/", 1)[0] for p in classified}:
|
||||||
|
prefix = unit + "/"
|
||||||
|
|
||||||
|
def strip(paths: Any, prefix: str = prefix) -> list[str]:
|
||||||
|
return [p.removeprefix(prefix) for p in paths if str(p).startswith(prefix)]
|
||||||
|
|
||||||
|
rows = [
|
||||||
|
r | {"path": r["path"].removeprefix(prefix)}
|
||||||
|
for r in payload.get("roles") or ()
|
||||||
|
if str(r.get("path", "")).startswith(prefix)
|
||||||
|
]
|
||||||
|
unit_payload = {
|
||||||
|
"model": payload.get("model"),
|
||||||
|
"roles": rows,
|
||||||
|
"unclassified_paths": strip(payload.get("unclassified_paths") or ()),
|
||||||
|
}
|
||||||
|
self.roles[unit] = (unit_payload, set(strip(classified)))
|
||||||
|
|
||||||
|
def passes(self, base: Path, entry_stem: str) -> tuple[dict[str, list], dict[str, str | None], Any] | None:
|
||||||
|
if not (done(base, f"{entry_stem}-va") and done(base, f"{entry_stem}-vb")):
|
||||||
|
return None
|
||||||
|
passes = {p: jsonl(base / f"{entry_stem}-v{p}" / "units.jsonl") for p in PASSES}
|
||||||
|
models = {p: (read_json(base / f"{entry_stem}-v{p}" / "summary.json") or {}).get("model") for p in PASSES}
|
||||||
|
final = base / f"{entry_stem}-final" / "agreed.json"
|
||||||
|
agreed = read_json(final if final.is_file() else base / f"{entry_stem}-agree" / "agreed.json")
|
||||||
|
return passes, models, agreed
|
||||||
|
|
||||||
|
|
||||||
|
def final_of(agreed: Any, candidate: str) -> str | None:
|
||||||
|
if not agreed:
|
||||||
|
return None
|
||||||
|
disputed = {str(d["candidate"]) for d in agreed.get("disputed") or []}
|
||||||
|
for row in agreed.get("candidates") or []:
|
||||||
|
if str(row["candidate"]) == candidate:
|
||||||
|
return "agreed" if row.get("agreed") else "disputed" if candidate in disputed else "rejected"
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def plane_parts(signals: Signals, stems: list[tuple[Path, str]], roles_owner: str | None, candidate: str, line: int,
|
||||||
|
path: str, function: str,
|
||||||
|
verify_expected: bool) -> dict[str, Part]: # fmt: skip
|
||||||
|
"""verify, agree, model_sinks of one candidate: ``stems`` are (run dir, entry stem) that may have asked it."""
|
||||||
|
parts: dict[str, Part] = {"verify": NONE, "agree": NONE}
|
||||||
|
pending = False
|
||||||
|
for base, stem in stems:
|
||||||
|
got = signals.passes(base, stem)
|
||||||
|
if got is None:
|
||||||
|
pending = pending or (base == signals.verify_run and verify_expected)
|
||||||
|
continue
|
||||||
|
passes, models, agreed = got
|
||||||
|
part = verify_part(passes, candidate, line, "+".join(sorted({m for m in models.values() if m})) or None)
|
||||||
|
if part.state == "ran":
|
||||||
|
parts = {"verify": part, "agree": agree_part(final_of(agreed, candidate))}
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if pending:
|
||||||
|
parts = {"verify": MISSING, "agree": MISSING}
|
||||||
|
if roles_owner is None or roles_owner not in signals.roles:
|
||||||
|
parts["model_sinks"] = MISSING
|
||||||
|
else:
|
||||||
|
payload, classified = signals.roles[roles_owner]
|
||||||
|
if path not in classified:
|
||||||
|
parts["model_sinks"] = MISSING
|
||||||
|
else:
|
||||||
|
parts["model_sinks"] = model_sinks_part(from_model_roles(payload), path, function, str(payload.get("model") or "") or None)
|
||||||
|
return parts
|
||||||
|
|
||||||
|
|
||||||
|
def static_parts(root: Path, index: SourceIndex, quick: Mapping, engine: Mapping, engine_state: Part | None, engine_result: Mapping | None,
|
||||||
|
inferred: RoleSet, rules: Mapping, quick_version: str, path: str, function: str, family: str, repository: bool,
|
||||||
|
entries: tuple[set[str], set[str]] | None) -> dict[str, Part]: # fmt: skip
|
||||||
|
language = detect_language(Path(path)) or "other"
|
||||||
|
key = (path, function, family)
|
||||||
|
parts: dict[str, Part] = {}
|
||||||
|
parts["quick"] = quick_part(quick.get(key, []), rules, quick_version) if covers(QUICK_LANGUAGES, language) else NONE
|
||||||
|
if language not in ENGINE_LANGUAGES:
|
||||||
|
parts["engine"] = NONE
|
||||||
|
elif engine_state is not None:
|
||||||
|
parts["engine"] = engine_state
|
||||||
|
else:
|
||||||
|
result = engine_result or {}
|
||||||
|
questions, completed = int(result.get("questions") or 0), int(result.get("completed") or 0)
|
||||||
|
parts["engine"] = engine_part(
|
||||||
|
engine.get(key, []), completion=completed / questions if questions else None, degraded=bool(result.get("degradations")),
|
||||||
|
vocabulary=Vocabulary.load(language), version=str(result.get("image") or "recorded"),
|
||||||
|
) # fmt: skip
|
||||||
|
lines = index.lines(path)
|
||||||
|
parts["source"] = source_part(lines, language, function)
|
||||||
|
parts["roles"] = roles_part(function_of(lines, path, language, function), inferred, language)
|
||||||
|
parts["delta"] = NOT_APPLICABLE
|
||||||
|
if repository and entries is not None:
|
||||||
|
distance = 0 if function == GLOBAL and path in entries[1] else entry_distance(function, entries[0], index.callers())
|
||||||
|
parts["entry_points"] = Part("ran", {"facts.entry_distance": distance})
|
||||||
|
parts["facts"] = facts_part(_callers_of(index, index.callers(), path, function), function, "host")
|
||||||
|
else:
|
||||||
|
parts["entry_points"] = NOT_APPLICABLE
|
||||||
|
parts["facts"] = NOT_APPLICABLE
|
||||||
|
return parts
|
||||||
|
|
||||||
|
|
||||||
|
def engine_for(result: Mapping[str, Any] | None) -> Part | None:
|
||||||
|
"""None when the engine ran (its findings feed engine_part); else the state Part."""
|
||||||
|
if result is None:
|
||||||
|
return MISSING
|
||||||
|
state = result.get("state", "ran" if result.get("questions") else "failed")
|
||||||
|
if state == "ran" and int(result.get("questions") or 0) > 0:
|
||||||
|
return None
|
||||||
|
if state == "none":
|
||||||
|
return NONE
|
||||||
|
return Part("failed", version=str(result.get("image") or "recorded"))
|
||||||
|
|
||||||
|
|
||||||
|
def export(clone: Path, pin: str, target: Path) -> bool:
|
||||||
|
target.mkdir(parents=True)
|
||||||
|
archive = target.parent / "pin.tar"
|
||||||
|
with archive.open("wb") as stream:
|
||||||
|
ok = subprocess.run(["git", "-C", str(clone), "archive", pin], stdout=stream, check=False).returncode == 0
|
||||||
|
ok = ok and subprocess.run(["tar", "-xf", str(archive), "-C", str(target)], check=False).returncode == 0
|
||||||
|
archive.unlink(missing_ok=True)
|
||||||
|
return ok and any(target.iterdir())
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
parser.add_argument("--labels", type=Path, required=True)
|
||||||
|
parser.add_argument("--units", type=Path, required=True, help="units.json of the harvest plane")
|
||||||
|
parser.add_argument("--catalog", type=Path, default=DEFAULT_CATALOG)
|
||||||
|
parser.add_argument("--cache", type=Path, default=Path.home() / ".cache" / "openultrasast")
|
||||||
|
parser.add_argument("--engine", type=Path, default=RESULTS / "plane" / "harvest-engine")
|
||||||
|
parser.add_argument("--verify-run", type=Path, default=RESULTS / "plane" / "harvest-verify")
|
||||||
|
parser.add_argument("--roles-run", type=Path, default=RESULTS / "plane" / "harvest-roles")
|
||||||
|
parser.add_argument("--v46", type=Path, default=RESULTS / "plane" / "validation-46")
|
||||||
|
parser.add_argument("--scratch", type=Path, required=True)
|
||||||
|
parser.add_argument("--min-free-gb", type=float, default=1.2)
|
||||||
|
parser.add_argument("--counts", type=Path, required=True)
|
||||||
|
parser.add_argument("--store", help="OUSAST_MEMORY spec (default: the environment's)")
|
||||||
|
parser.add_argument("--limit", type=int, default=0, help="stop after this many targets (a test)")
|
||||||
|
parser.add_argument("--kinds", default="pairs,pin", help="which targets: pairs, pin (population and recipe pins)")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
labels = [r for r in jsonl(args.labels) if r["unit"] == "pin" and r["source"] not in CONDITIONAL_SOURCES and not r.get("conditional")]
|
||||||
|
units = json.loads(args.units.read_text(encoding="utf-8"))
|
||||||
|
by_pair = {(u["ref"], u["side"]): n for n, u in units.items() if u["source"] == "pairs"}
|
||||||
|
by_pin: dict[tuple[str, str], list[str]] = defaultdict(list)
|
||||||
|
for n, u in units.items():
|
||||||
|
if u["source"] != "pairs":
|
||||||
|
by_pin[(u["repo"], u["pin"])].append(n)
|
||||||
|
targets: dict[tuple[str, str, str], list[dict[str, Any]]] = defaultdict(list)
|
||||||
|
for row in labels:
|
||||||
|
key = ("pairs", row["source_ref"], row["pin_role"]) if row["source"] == "pairs" else ("pin", row["repo"], row["pin"])
|
||||||
|
targets[key].append(row)
|
||||||
|
cases = {c.name: c for c in load_pair_catalog(args.catalog)}
|
||||||
|
loaded = load_ruleset(DEFAULT_RULESET_DIR)
|
||||||
|
rules = {r.rule_id: r for r in loaded}
|
||||||
|
quick_version = ruleset_digest(loaded)
|
||||||
|
signals = Signals(args.verify_run, args.roles_run, args.v46)
|
||||||
|
store = memory.open_store(args.store)
|
||||||
|
tally: Counter[tuple[str, ...]] = Counter()
|
||||||
|
coverage: dict[str, Counter[str]] = defaultdict(Counter)
|
||||||
|
skipped: Counter[str] = Counter()
|
||||||
|
args.scratch.mkdir(parents=True, exist_ok=True)
|
||||||
|
chosen = [(k, r) for k, r in sorted(targets.items()) if k[0] in args.kinds.split(",")]
|
||||||
|
for number, ((kind, ref, role_or_pin), rows) in enumerate(chosen):
|
||||||
|
if args.limit and number >= args.limit:
|
||||||
|
break
|
||||||
|
with tempfile.TemporaryDirectory(dir=args.scratch) as tmp:
|
||||||
|
root = Path(tmp) / "tree"
|
||||||
|
if kind == "pairs":
|
||||||
|
name = by_pair.get((ref, role_or_pin))
|
||||||
|
if name is None or ref not in cases:
|
||||||
|
skipped["pair side not in the harvest units"] += len(rows)
|
||||||
|
continue
|
||||||
|
unit = units[name]
|
||||||
|
_materialize_side(root, cases[ref], side="vuln" if role_or_pin == "vulnerable" else "fixed")
|
||||||
|
engine_result = read_json(args.engine / f"{ref}--{'vuln' if role_or_pin == 'vulnerable' else 'fixed'}.json")
|
||||||
|
stems = [(args.verify_run, name)]
|
||||||
|
owner, repository, repo, pin = name, False, unit["repo"], unit["pin"]
|
||||||
|
else:
|
||||||
|
names = by_pin.get((ref, role_or_pin), [])
|
||||||
|
if not names:
|
||||||
|
skipped["pin not in the harvest units"] += len(rows)
|
||||||
|
continue
|
||||||
|
unit = units[names[0]]
|
||||||
|
repo, pin, repository = ref, role_or_pin, True
|
||||||
|
if shutil.disk_usage(args.scratch).free / 1e9 < args.min_free_gb:
|
||||||
|
skipped["disk guard: pin not exported"] += len(rows)
|
||||||
|
continue
|
||||||
|
if unit["source"] == "dev-php":
|
||||||
|
source_dir = args.cache / "repos" / unit["ref"].split(":")[0] / pin[:12]
|
||||||
|
shutil.copytree(source_dir, root, symlinks=True, ignore=shutil.ignore_patterns(".git"))
|
||||||
|
engine_result = None
|
||||||
|
else:
|
||||||
|
case_id = unit["ref"]
|
||||||
|
if not export(args.cache / "independent" / case_id, pin, root):
|
||||||
|
skipped["pin export failed"] += len(rows)
|
||||||
|
continue
|
||||||
|
split = {r["split"] for r in rows} | {unit["source"]}
|
||||||
|
population = "independent-v1" if "population-v1" in split else "independent-v2"
|
||||||
|
engine_result = read_json(RESULTS / population / "scans" / f"{case_id}--{rows[0]['pin_role']}.json")
|
||||||
|
stems = [(args.verify_run, n) for n in names] + [(args.v46, unit["ref"])]
|
||||||
|
owner = next(
|
||||||
|
(n for n in names if f"{n}-roles" in {e for e in (read_json(args.roles_run / "state.json") or {}).get("tasks", {})}),
|
||||||
|
names[0],
|
||||||
|
)
|
||||||
|
index = SourceIndex(root)
|
||||||
|
targets_ = _targets(root)
|
||||||
|
findings = quick_scan_findings(root, targets_, rank_targets(targets_), None)
|
||||||
|
engine_state = engine_for(engine_result)
|
||||||
|
quick, engine = _signals(index, findings, engine_result if engine_state is None else None, rules)
|
||||||
|
inferred = infer_for_checkout(root)
|
||||||
|
entries = entry_names(root, {r["candidate"].partition("::")[0] for r in rows}) if repository else None
|
||||||
|
out_rows: list[dict[str, Any]] = []
|
||||||
|
seen: set[tuple[str, str]] = set()
|
||||||
|
for row in rows:
|
||||||
|
candidate, family = row["candidate"], row["family"]
|
||||||
|
if (candidate, family) in seen:
|
||||||
|
continue
|
||||||
|
seen.add((candidate, family))
|
||||||
|
path, _, function = candidate.partition("::")
|
||||||
|
cand_line = next((c[2] for n in ([owner] if kind == "pairs" else by_pin[(repo, pin)]) for c in units[n]["candidates"]
|
||||||
|
if f"{c[0]}::{c[1]}" == candidate), None) # fmt: skip
|
||||||
|
parts = static_parts(root, index, quick, engine, engine_state, engine_result, inferred, rules, quick_version, path,
|
||||||
|
function, family, repository, entries) # fmt: skip
|
||||||
|
language = detect_language(Path(path)) or "other"
|
||||||
|
verify_expected = any(units[n]["family"] == family for n in ([owner] if kind == "pairs" else by_pin[(repo, pin)]))
|
||||||
|
plane = {**parts, **plane_parts(signals, stems, owner, candidate, cand_line or 1, path, function, verify_expected)}
|
||||||
|
for profile, use in (("static", parts), ("plane", plane)):
|
||||||
|
rec = record(candidate, family, language, profile, use)
|
||||||
|
out_rows.append({
|
||||||
|
"id": memory.row_id("features", "harvest", owner, f"{candidate}:{family}:{profile}"), "kind": "features",
|
||||||
|
"repo": memory.repo_key(repo), "pin": pin, "run": "harvest", "task": owner, "population": row["source"],
|
||||||
|
"split": row["split"], "image": str((engine_result or {}).get("image") or "none"), **rec,
|
||||||
|
}) # fmt: skip
|
||||||
|
tally[(profile, family)] += 1
|
||||||
|
if profile == "plane":
|
||||||
|
for inst, info in rec["instruments"].items():
|
||||||
|
state = "missing" if info.get("version") == "missing:not-run" else info["state"]
|
||||||
|
coverage[f"{family}:{inst}"][state] += 1
|
||||||
|
store.ingest_rows("harvest", f"features:{owner}", out_rows)
|
||||||
|
print(json.dumps({"target": owner, "rows": len(out_rows)}), flush=True)
|
||||||
|
counts = {
|
||||||
|
"records": {f"{p}:{f}": n for (p, f), n in sorted(tally.items())},
|
||||||
|
"instrument_states_plane": {k: dict(sorted(v.items())) for k, v in sorted(coverage.items())},
|
||||||
|
"skipped_label_rows": dict(skipped),
|
||||||
|
"store": store.describe(),
|
||||||
|
}
|
||||||
|
args.counts.write_text(json.dumps(counts, indent=1, sort_keys=True) + "\n", encoding="utf-8")
|
||||||
|
print(json.dumps({"records": sum(tally.values()), "skipped": dict(skipped)}))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
"""Engine signals for the labelled pair corpus, on the host (learned-decision-engine task 5, design "Cost on the 7 GB host").
|
||||||
|
|
||||||
|
Per labelled pair (``ousast learn labels`` rows of source ``pairs``) and side (``vuln``, ``fixed``): the side's
|
||||||
|
excerpt -- with the documents that register it -- is materialised into a temporary directory, and the Joern engine
|
||||||
|
runs on it in ``openultrasast:dev`` (``benchmarks/push/finding_dump.py`` from a FROZEN source export, ``--network
|
||||||
|
none --memory 3g``, the pair's labelled families, ONE container at a time). The result is one JSON per side under
|
||||||
|
``--out`` (``<pair>--<side>.json``), keyed by the side's content sha256 and the engine image id; a rerun skips sides
|
||||||
|
already recorded, so the job resumes where it stopped.
|
||||||
|
|
||||||
|
The instrument must have read its input (:func:`openultrasast.plane.engine_alerts.read_record`): no result file, no
|
||||||
|
``read N files`` line or ``questions == 0`` is recorded as ``state: failed`` with the reason (retried once), never as
|
||||||
|
zero findings. A side whose language the engine has no model for is ``state: none`` and is not run.
|
||||||
|
|
||||||
|
Guards: free disk is checked before every side and every 60 s while a container runs; below ``--min-free-gb`` the
|
||||||
|
container is killed by its name, the side is left unrecorded (``missing``) and the job stops. A file ``STOP`` in
|
||||||
|
``--out`` stops the job cleanly between sides. Progress lines go to ``--out/progress.jsonl``.
|
||||||
|
|
||||||
|
Usage::
|
||||||
|
|
||||||
|
python benchmarks/learn/engine_pairs.py --labels labels-<sha>.jsonl --source <frozen export> --out <dir>
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import threading
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from openultrasast.pairs import DEFAULT_CATALOG, _materialize_side, load_pair_catalog
|
||||||
|
from openultrasast.plane.engine_alerts import EngineAlertsError, docker_command, frozen_source, read_record
|
||||||
|
from openultrasast.plane.tasks.alerts import engine_languages
|
||||||
|
from openultrasast.preprocess import detect_language
|
||||||
|
|
||||||
|
SIDES = ("vuln", "fixed")
|
||||||
|
_OFFERED = re.compile(r"^read (\d+) files, \d+ bytes; (\d+) regions offer", re.MULTILINE)
|
||||||
|
|
||||||
|
|
||||||
|
def free_gb(path: Path) -> float:
|
||||||
|
return shutil.disk_usage(path).free / 1e9
|
||||||
|
|
||||||
|
|
||||||
|
def units(labels: Path, catalog: Path) -> list[tuple[object, str, tuple[str, ...]]]:
|
||||||
|
"""(pair case, side, families) for every labelled pair, in name order."""
|
||||||
|
families: dict[str, set[str]] = {}
|
||||||
|
for line in labels.read_text(encoding="utf-8").splitlines():
|
||||||
|
row = json.loads(line)
|
||||||
|
if row["source"] == "pairs" and row["unit"] == "pin" and row["family"] != "unknown":
|
||||||
|
families.setdefault(row["source_ref"], set()).add(row["family"])
|
||||||
|
cases = {case.name: case for case in load_pair_catalog(catalog)}
|
||||||
|
return [(cases[name], side, tuple(sorted(families[name]))) for name in sorted(families) for side in SIDES]
|
||||||
|
|
||||||
|
|
||||||
|
def image_id(image: str) -> str:
|
||||||
|
done = subprocess.run(["docker", "image", "inspect", "--format", "{{.Id}}", image], capture_output=True, text=True, check=False)
|
||||||
|
if done.returncode != 0 or not done.stdout.strip():
|
||||||
|
raise SystemExit(f"no engine image {image}")
|
||||||
|
return done.stdout.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def run_side(
|
||||||
|
command: list[str], name: str, timeout: float, out: Path, min_free: float
|
||||||
|
) -> tuple[subprocess.CompletedProcess[str] | None, str]:
|
||||||
|
"""Run one container; a watchdog kills it by name when free disk drops below ``min_free`` GB."""
|
||||||
|
tripped: list[str] = []
|
||||||
|
done = threading.Event()
|
||||||
|
|
||||||
|
def watch() -> None:
|
||||||
|
while not done.wait(60.0):
|
||||||
|
if free_gb(out) < min_free:
|
||||||
|
tripped.append(f"free disk {free_gb(out):.2f} GB < {min_free} GB")
|
||||||
|
subprocess.run(["docker", "kill", name], capture_output=True, check=False)
|
||||||
|
return
|
||||||
|
|
||||||
|
watcher = threading.Thread(target=watch, daemon=True)
|
||||||
|
watcher.start()
|
||||||
|
try:
|
||||||
|
completed = subprocess.run(command, capture_output=True, text=True, timeout=timeout, check=False)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
subprocess.run(["docker", "kill", name], capture_output=True, check=False)
|
||||||
|
completed = None
|
||||||
|
done.set()
|
||||||
|
return completed, (tripped[0] if tripped else "")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
parser.add_argument("--labels", type=Path, required=True)
|
||||||
|
parser.add_argument("--catalog", type=Path, default=DEFAULT_CATALOG)
|
||||||
|
parser.add_argument("--source", type=Path, required=True, help="frozen export: git archive HEAD src benchmarks/push/finding_dump.py")
|
||||||
|
parser.add_argument("--out", type=Path, required=True)
|
||||||
|
parser.add_argument("--image", default="openultrasast:dev")
|
||||||
|
parser.add_argument("--deadline", type=float, default=600.0)
|
||||||
|
parser.add_argument("--min-free-gb", type=float, default=1.0)
|
||||||
|
parser.add_argument("--limit", type=int, default=0, help="stop after this many sides were run (0: all)")
|
||||||
|
args = parser.parse_args()
|
||||||
|
source = frozen_source(args.source)
|
||||||
|
args.out.mkdir(parents=True, exist_ok=True)
|
||||||
|
image = image_id(args.image)
|
||||||
|
covered = engine_languages()
|
||||||
|
progress = (args.out / "progress.jsonl").open("a", encoding="utf-8")
|
||||||
|
ran = 0
|
||||||
|
for case, side, families in units(args.labels, args.catalog):
|
||||||
|
result_path = args.out / f"{case.name}--{side}.json"
|
||||||
|
if result_path.is_file():
|
||||||
|
continue
|
||||||
|
if (args.out / "STOP").exists() or (args.limit and ran >= args.limit):
|
||||||
|
print("stopped between sides", flush=True)
|
||||||
|
return 0
|
||||||
|
if free_gb(args.out) < args.min_free_gb:
|
||||||
|
print(f"disk guard: {free_gb(args.out):.2f} GB free; stopping", flush=True)
|
||||||
|
return 4
|
||||||
|
excerpt = case.vuln_file if side == "vuln" else case.fixed_file
|
||||||
|
if not excerpt.is_file():
|
||||||
|
entry = {"state": "failed", "reason": "excerpt not materialised"}
|
||||||
|
else:
|
||||||
|
entry = {"sha256": hashlib.sha256(excerpt.read_bytes()).hexdigest()}
|
||||||
|
language = detect_language(Path(case.relpath)) or "other"
|
||||||
|
if language not in covered:
|
||||||
|
entry.update(state="none", reason=f"no engine model for {language}")
|
||||||
|
else:
|
||||||
|
entry.update(_scan(case, side, families, source, args, image))
|
||||||
|
ran += 1
|
||||||
|
if entry.get("state") == "missing":
|
||||||
|
print(json.dumps({"pair": case.name, "side": side, **entry}), flush=True)
|
||||||
|
return 4
|
||||||
|
record = {"pair": case.name, "side": side, "families": list(families), "image": image, **entry}
|
||||||
|
result_path.write_text(json.dumps(record, indent=1, sort_keys=True) + "\n", encoding="utf-8")
|
||||||
|
line = {k: record.get(k) for k in ("pair", "side", "state", "questions", "completed", "seconds", "reason")}
|
||||||
|
line["findings"] = len(record.get("findings") or [])
|
||||||
|
progress.write(json.dumps(line) + "\n")
|
||||||
|
progress.flush()
|
||||||
|
print(json.dumps(line), flush=True)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def _scan(case: object, side: str, families: tuple[str, ...], source: Path, args: argparse.Namespace, image: str) -> dict:
|
||||||
|
reason = ""
|
||||||
|
for attempt in (1, 2):
|
||||||
|
with tempfile.TemporaryDirectory(prefix="ep-", dir=args.out) as tmp:
|
||||||
|
checkout = _materialize_side(Path(tmp) / "case", case, side=side)
|
||||||
|
out_dir = Path(tmp) / "out"
|
||||||
|
out_dir.mkdir()
|
||||||
|
name = f"ousast-ep-{hashlib.sha1(f'{case.name}{side}'.encode()).hexdigest()[:12]}"
|
||||||
|
command = docker_command(source, checkout, out_dir, "result", ",".join(families), args.deadline, args.image)
|
||||||
|
command[2:2] = ["--name", name]
|
||||||
|
completed, tripped = run_side(command, name, args.deadline + 300, args.out, args.min_free_gb)
|
||||||
|
if tripped:
|
||||||
|
return {"state": "missing", "reason": tripped}
|
||||||
|
if completed is None:
|
||||||
|
reason = f"timeout after {args.deadline + 300:.0f}s"
|
||||||
|
continue
|
||||||
|
log = (completed.stdout or "") + "\n" + (completed.stderr or "")
|
||||||
|
try:
|
||||||
|
record = read_record(out_dir / "result.json", log, completed.returncode)
|
||||||
|
except EngineAlertsError as exc:
|
||||||
|
reason = f"attempt {attempt}: {exc}"[:600]
|
||||||
|
offered = _OFFERED.search(log)
|
||||||
|
result = out_dir / "result.json"
|
||||||
|
if offered is not None and int(offered.group(1)) > 0 and result.is_file():
|
||||||
|
# It read its input and finished without asking: deterministic (a retry asks nothing either). Still
|
||||||
|
# `failed` by the design's rule (questions == 0 is never zero findings); the reason keeps it apart
|
||||||
|
# from a launch failure, because on a fixed side "no question" may mean "no sink left".
|
||||||
|
recorded = json.loads(result.read_text(encoding="utf-8"))
|
||||||
|
regions = int(offered.group(2))
|
||||||
|
why = "no region offers the families" if regions == 0 else f"no question asked for {regions} regions"
|
||||||
|
return {"state": "failed", "reason": why, "files": int(offered.group(1)), "regions": regions,
|
||||||
|
"seconds": recorded.get("seconds"), "degradations": recorded.get("degradations")} # fmt: skip
|
||||||
|
continue
|
||||||
|
return {"state": "ran", **{k: v for k, v in record.items() if k != "root"}}
|
||||||
|
return {"state": "failed", "reason": reason}
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"modules": 143,
|
"modules": 144,
|
||||||
"counts": {
|
"counts": {
|
||||||
"load_bearing": 136,
|
"load_bearing": 137,
|
||||||
"standalone_capability": 7
|
"standalone_capability": 7
|
||||||
},
|
},
|
||||||
"orphaned": [],
|
"orphaned": [],
|
||||||
@@ -354,6 +354,7 @@
|
|||||||
"cli",
|
"cli",
|
||||||
"learn.features",
|
"learn.features",
|
||||||
"learn.roles",
|
"learn.roles",
|
||||||
|
"plane.harvest",
|
||||||
"plane.tasks.features",
|
"plane.tasks.features",
|
||||||
"plane.tasks.remember",
|
"plane.tasks.remember",
|
||||||
"plane.tasks.roles"
|
"plane.tasks.roles"
|
||||||
@@ -372,13 +373,14 @@
|
|||||||
"classification": "load_bearing",
|
"classification": "load_bearing",
|
||||||
"reason": "reachable from gate, map_gate, pair_gate or the CLI",
|
"reason": "reachable from gate, map_gate, pair_gate or the CLI",
|
||||||
"importers": [
|
"importers": [
|
||||||
"cli"
|
"cli",
|
||||||
|
"plane.harvest"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"module": "learn.roles",
|
"module": "learn.roles",
|
||||||
"classification": "load_bearing",
|
"classification": "load_bearing",
|
||||||
"reason": "imported by learn.features, plane.tasks.features, plane.tasks.roles",
|
"reason": "reachable from gate, map_gate, pair_gate or the CLI",
|
||||||
"importers": [
|
"importers": [
|
||||||
"learn.features",
|
"learn.features",
|
||||||
"plane.tasks.features",
|
"plane.tasks.features",
|
||||||
@@ -709,6 +711,7 @@
|
|||||||
"learn.labels",
|
"learn.labels",
|
||||||
"model.candidates",
|
"model.candidates",
|
||||||
"pair_gate",
|
"pair_gate",
|
||||||
|
"plane.harvest",
|
||||||
"plane.tasks.loop"
|
"plane.tasks.loop"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -722,6 +725,7 @@
|
|||||||
"plane.egress",
|
"plane.egress",
|
||||||
"plane.engine_alerts",
|
"plane.engine_alerts",
|
||||||
"plane.generate",
|
"plane.generate",
|
||||||
|
"plane.harvest",
|
||||||
"plane.memory",
|
"plane.memory",
|
||||||
"plane.reconciler",
|
"plane.reconciler",
|
||||||
"plane.router",
|
"plane.router",
|
||||||
@@ -769,6 +773,15 @@
|
|||||||
"module": "plane.generate",
|
"module": "plane.generate",
|
||||||
"classification": "load_bearing",
|
"classification": "load_bearing",
|
||||||
"reason": "ai-service-plane task 7: an increment's Workspaces, per-case Tasks and Run from a recorded set",
|
"reason": "ai-service-plane task 7: an increment's Workspaces, per-case Tasks and Run from a recorded set",
|
||||||
|
"importers": [
|
||||||
|
"cli",
|
||||||
|
"plane.harvest"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"module": "plane.harvest",
|
||||||
|
"classification": "load_bearing",
|
||||||
|
"reason": "reachable from gate, map_gate, pair_gate or the CLI",
|
||||||
"importers": [
|
"importers": [
|
||||||
"cli"
|
"cli"
|
||||||
]
|
]
|
||||||
@@ -780,6 +793,7 @@
|
|||||||
"importers": [
|
"importers": [
|
||||||
"plane.egress",
|
"plane.egress",
|
||||||
"plane.generate",
|
"plane.generate",
|
||||||
|
"plane.harvest",
|
||||||
"plane.reconciler",
|
"plane.reconciler",
|
||||||
"plane.router",
|
"plane.router",
|
||||||
"plane.runner",
|
"plane.runner",
|
||||||
@@ -803,6 +817,7 @@
|
|||||||
"reason": "ai-service-plane Req 3.1-3.5, 7.3: ax-backed Run execution, status attribution and doctor; `ousast plane`",
|
"reason": "ai-service-plane Req 3.1-3.5, 7.3: ax-backed Run execution, status attribution and doctor; `ousast plane`",
|
||||||
"importers": [
|
"importers": [
|
||||||
"plane.generate",
|
"plane.generate",
|
||||||
|
"plane.harvest",
|
||||||
"plane.memory",
|
"plane.memory",
|
||||||
"plane.workspaces"
|
"plane.workspaces"
|
||||||
]
|
]
|
||||||
@@ -833,6 +848,7 @@
|
|||||||
"learn.roles",
|
"learn.roles",
|
||||||
"plane.engine_alerts",
|
"plane.engine_alerts",
|
||||||
"plane.generate",
|
"plane.generate",
|
||||||
|
"plane.harvest",
|
||||||
"plane.memory",
|
"plane.memory",
|
||||||
"plane.tasks.agree",
|
"plane.tasks.agree",
|
||||||
"plane.tasks.alerts",
|
"plane.tasks.alerts",
|
||||||
@@ -888,6 +904,7 @@
|
|||||||
"learn.labels",
|
"learn.labels",
|
||||||
"learn.roles",
|
"learn.roles",
|
||||||
"plane.generate",
|
"plane.generate",
|
||||||
|
"plane.harvest",
|
||||||
"plane.tasks.alerts",
|
"plane.tasks.alerts",
|
||||||
"plane.tasks.features",
|
"plane.tasks.features",
|
||||||
"plane.tasks.remember",
|
"plane.tasks.remember",
|
||||||
@@ -898,7 +915,9 @@
|
|||||||
"module": "plane.tasks.roles",
|
"module": "plane.tasks.roles",
|
||||||
"classification": "load_bearing",
|
"classification": "load_bearing",
|
||||||
"reason": "learned-decision-engine Req 8.1: model role classification per file chunk (model_sinks.py moved in); its Run template comes with the harvest (task 5)",
|
"reason": "learned-decision-engine Req 8.1: model role classification per file chunk (model_sinks.py moved in); its Run template comes with the harvest (task 5)",
|
||||||
"importers": []
|
"importers": [
|
||||||
|
"plane.harvest"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"module": "plane.tasks.verify",
|
"module": "plane.tasks.verify",
|
||||||
@@ -906,6 +925,7 @@
|
|||||||
"reason": "ai-service-plane Req 5.3/2.1-2.3/7.2: the batched hunt with known callers, metered and resumable per file hunt",
|
"reason": "ai-service-plane Req 5.3/2.1-2.3/7.2: the batched hunt with known callers, metered and resumable per file hunt",
|
||||||
"importers": [
|
"importers": [
|
||||||
"plane.generate",
|
"plane.generate",
|
||||||
|
"plane.harvest",
|
||||||
"plane.tasks.agree",
|
"plane.tasks.agree",
|
||||||
"plane.tasks.roles"
|
"plane.tasks.roles"
|
||||||
]
|
]
|
||||||
@@ -966,6 +986,7 @@
|
|||||||
"model.partitions",
|
"model.partitions",
|
||||||
"model.scan",
|
"model.scan",
|
||||||
"pairs",
|
"pairs",
|
||||||
|
"plane.harvest",
|
||||||
"plane.tasks.alerts",
|
"plane.tasks.alerts",
|
||||||
"plane.tasks.features",
|
"plane.tasks.features",
|
||||||
"plane.tasks.repo_facts",
|
"plane.tasks.repo_facts",
|
||||||
|
|||||||
@@ -0,0 +1,477 @@
|
|||||||
|
{
|
||||||
|
"balance_usd": {
|
||||||
|
"after_roles": 18.23,
|
||||||
|
"after_verify": 18.75,
|
||||||
|
"before": 19.63
|
||||||
|
},
|
||||||
|
"ceilings_usd": {
|
||||||
|
"roles": 10.0,
|
||||||
|
"verify": 10.0
|
||||||
|
},
|
||||||
|
"created": "2026-10-01",
|
||||||
|
"engine": {
|
||||||
|
"frozen_source_commit": "e6ed7854bb8ef17d6a4c39971ea253b4e385af23",
|
||||||
|
"image": "openultrasast:dev sha256:e6f8dc6cc7547f7118bd058687de676e0fcf741799d1d3839b3e8648ce190fbb",
|
||||||
|
"pair_sides_total": 686,
|
||||||
|
"population_engine": "recorded protocol scans of independent-v1/v2 (vulnerable and fixed pins); dev-php not run (missing)",
|
||||||
|
"sides_missing": 302,
|
||||||
|
"sides_recorded": {
|
||||||
|
"failed (read its input, asked no question)": 286,
|
||||||
|
"none": 6,
|
||||||
|
"ran": 92
|
||||||
|
},
|
||||||
|
"status": "running in the background at commit time; unfinished sides are `missing` in the records, never zero"
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"instrument_states_plane": {
|
||||||
|
"access_control:agree": {
|
||||||
|
"none": 26
|
||||||
|
},
|
||||||
|
"access_control:delta": {
|
||||||
|
"not_applicable": 26
|
||||||
|
},
|
||||||
|
"access_control:engine": {
|
||||||
|
"missing": 6,
|
||||||
|
"ran": 20
|
||||||
|
},
|
||||||
|
"access_control:entry_points": {
|
||||||
|
"not_applicable": 26
|
||||||
|
},
|
||||||
|
"access_control:facts": {
|
||||||
|
"not_applicable": 26
|
||||||
|
},
|
||||||
|
"access_control:language": {
|
||||||
|
"ran": 26
|
||||||
|
},
|
||||||
|
"access_control:model_sinks": {
|
||||||
|
"ran": 26
|
||||||
|
},
|
||||||
|
"access_control:quick": {
|
||||||
|
"ran": 26
|
||||||
|
},
|
||||||
|
"access_control:roles": {
|
||||||
|
"failed": 13,
|
||||||
|
"ran": 13
|
||||||
|
},
|
||||||
|
"access_control:source": {
|
||||||
|
"failed": 13,
|
||||||
|
"ran": 13
|
||||||
|
},
|
||||||
|
"access_control:verify": {
|
||||||
|
"none": 26
|
||||||
|
},
|
||||||
|
"config_secrets:agree": {
|
||||||
|
"none": 4,
|
||||||
|
"ran": 31
|
||||||
|
},
|
||||||
|
"config_secrets:delta": {
|
||||||
|
"not_applicable": 35
|
||||||
|
},
|
||||||
|
"config_secrets:engine": {
|
||||||
|
"missing": 4,
|
||||||
|
"none": 23,
|
||||||
|
"ran": 8
|
||||||
|
},
|
||||||
|
"config_secrets:entry_points": {
|
||||||
|
"not_applicable": 8,
|
||||||
|
"ran": 27
|
||||||
|
},
|
||||||
|
"config_secrets:facts": {
|
||||||
|
"not_applicable": 8,
|
||||||
|
"ran": 27
|
||||||
|
},
|
||||||
|
"config_secrets:language": {
|
||||||
|
"ran": 35
|
||||||
|
},
|
||||||
|
"config_secrets:model_sinks": {
|
||||||
|
"ran": 35
|
||||||
|
},
|
||||||
|
"config_secrets:quick": {
|
||||||
|
"ran": 35
|
||||||
|
},
|
||||||
|
"config_secrets:roles": {
|
||||||
|
"failed": 14,
|
||||||
|
"ran": 21
|
||||||
|
},
|
||||||
|
"config_secrets:source": {
|
||||||
|
"failed": 4,
|
||||||
|
"ran": 31
|
||||||
|
},
|
||||||
|
"config_secrets:verify": {
|
||||||
|
"none": 4,
|
||||||
|
"ran": 31
|
||||||
|
},
|
||||||
|
"deserialization:agree": {
|
||||||
|
"none": 40
|
||||||
|
},
|
||||||
|
"deserialization:delta": {
|
||||||
|
"not_applicable": 40
|
||||||
|
},
|
||||||
|
"deserialization:engine": {
|
||||||
|
"failed": 21,
|
||||||
|
"ran": 19
|
||||||
|
},
|
||||||
|
"deserialization:entry_points": {
|
||||||
|
"not_applicable": 40
|
||||||
|
},
|
||||||
|
"deserialization:facts": {
|
||||||
|
"not_applicable": 40
|
||||||
|
},
|
||||||
|
"deserialization:language": {
|
||||||
|
"ran": 40
|
||||||
|
},
|
||||||
|
"deserialization:model_sinks": {
|
||||||
|
"ran": 40
|
||||||
|
},
|
||||||
|
"deserialization:quick": {
|
||||||
|
"ran": 40
|
||||||
|
},
|
||||||
|
"deserialization:roles": {
|
||||||
|
"failed": 20,
|
||||||
|
"ran": 20
|
||||||
|
},
|
||||||
|
"deserialization:source": {
|
||||||
|
"failed": 20,
|
||||||
|
"ran": 20
|
||||||
|
},
|
||||||
|
"deserialization:verify": {
|
||||||
|
"none": 40
|
||||||
|
},
|
||||||
|
"injection:agree": {
|
||||||
|
"missing": 4,
|
||||||
|
"none": 25,
|
||||||
|
"ran": 139
|
||||||
|
},
|
||||||
|
"injection:delta": {
|
||||||
|
"not_applicable": 168
|
||||||
|
},
|
||||||
|
"injection:engine": {
|
||||||
|
"failed": 22,
|
||||||
|
"missing": 78,
|
||||||
|
"none": 16,
|
||||||
|
"ran": 52
|
||||||
|
},
|
||||||
|
"injection:entry_points": {
|
||||||
|
"not_applicable": 70,
|
||||||
|
"ran": 98
|
||||||
|
},
|
||||||
|
"injection:facts": {
|
||||||
|
"not_applicable": 70,
|
||||||
|
"ran": 98
|
||||||
|
},
|
||||||
|
"injection:language": {
|
||||||
|
"ran": 168
|
||||||
|
},
|
||||||
|
"injection:model_sinks": {
|
||||||
|
"missing": 4,
|
||||||
|
"ran": 164
|
||||||
|
},
|
||||||
|
"injection:quick": {
|
||||||
|
"none": 2,
|
||||||
|
"ran": 166
|
||||||
|
},
|
||||||
|
"injection:roles": {
|
||||||
|
"failed": 44,
|
||||||
|
"none": 2,
|
||||||
|
"ran": 122
|
||||||
|
},
|
||||||
|
"injection:source": {
|
||||||
|
"failed": 36,
|
||||||
|
"none": 2,
|
||||||
|
"ran": 130
|
||||||
|
},
|
||||||
|
"injection:verify": {
|
||||||
|
"missing": 4,
|
||||||
|
"none": 25,
|
||||||
|
"ran": 139
|
||||||
|
},
|
||||||
|
"memory:agree": {
|
||||||
|
"none": 346
|
||||||
|
},
|
||||||
|
"memory:delta": {
|
||||||
|
"not_applicable": 346
|
||||||
|
},
|
||||||
|
"memory:engine": {
|
||||||
|
"failed": 116,
|
||||||
|
"missing": 218,
|
||||||
|
"none": 6,
|
||||||
|
"ran": 6
|
||||||
|
},
|
||||||
|
"memory:entry_points": {
|
||||||
|
"not_applicable": 346
|
||||||
|
},
|
||||||
|
"memory:facts": {
|
||||||
|
"not_applicable": 346
|
||||||
|
},
|
||||||
|
"memory:language": {
|
||||||
|
"ran": 346
|
||||||
|
},
|
||||||
|
"memory:model_sinks": {
|
||||||
|
"missing": 4,
|
||||||
|
"ran": 342
|
||||||
|
},
|
||||||
|
"memory:quick": {
|
||||||
|
"none": 4,
|
||||||
|
"ran": 342
|
||||||
|
},
|
||||||
|
"memory:roles": {
|
||||||
|
"none": 346
|
||||||
|
},
|
||||||
|
"memory:source": {
|
||||||
|
"none": 346
|
||||||
|
},
|
||||||
|
"memory:verify": {
|
||||||
|
"none": 346
|
||||||
|
},
|
||||||
|
"output_encoding:agree": {
|
||||||
|
"none": 112
|
||||||
|
},
|
||||||
|
"output_encoding:delta": {
|
||||||
|
"not_applicable": 112
|
||||||
|
},
|
||||||
|
"output_encoding:engine": {
|
||||||
|
"failed": 24,
|
||||||
|
"missing": 82,
|
||||||
|
"ran": 6
|
||||||
|
},
|
||||||
|
"output_encoding:entry_points": {
|
||||||
|
"not_applicable": 112
|
||||||
|
},
|
||||||
|
"output_encoding:facts": {
|
||||||
|
"not_applicable": 112
|
||||||
|
},
|
||||||
|
"output_encoding:language": {
|
||||||
|
"ran": 112
|
||||||
|
},
|
||||||
|
"output_encoding:model_sinks": {
|
||||||
|
"ran": 112
|
||||||
|
},
|
||||||
|
"output_encoding:quick": {
|
||||||
|
"ran": 112
|
||||||
|
},
|
||||||
|
"output_encoding:roles": {
|
||||||
|
"failed": 16,
|
||||||
|
"ran": 96
|
||||||
|
},
|
||||||
|
"output_encoding:source": {
|
||||||
|
"failed": 16,
|
||||||
|
"ran": 96
|
||||||
|
},
|
||||||
|
"output_encoding:verify": {
|
||||||
|
"none": 112
|
||||||
|
},
|
||||||
|
"path:agree": {
|
||||||
|
"none": 29
|
||||||
|
},
|
||||||
|
"path:delta": {
|
||||||
|
"not_applicable": 29
|
||||||
|
},
|
||||||
|
"path:engine": {
|
||||||
|
"failed": 22,
|
||||||
|
"missing": 5,
|
||||||
|
"ran": 2
|
||||||
|
},
|
||||||
|
"path:entry_points": {
|
||||||
|
"not_applicable": 28,
|
||||||
|
"ran": 1
|
||||||
|
},
|
||||||
|
"path:facts": {
|
||||||
|
"not_applicable": 28,
|
||||||
|
"ran": 1
|
||||||
|
},
|
||||||
|
"path:language": {
|
||||||
|
"ran": 29
|
||||||
|
},
|
||||||
|
"path:model_sinks": {
|
||||||
|
"ran": 29
|
||||||
|
},
|
||||||
|
"path:quick": {
|
||||||
|
"ran": 29
|
||||||
|
},
|
||||||
|
"path:roles": {
|
||||||
|
"failed": 15,
|
||||||
|
"ran": 14
|
||||||
|
},
|
||||||
|
"path:source": {
|
||||||
|
"failed": 15,
|
||||||
|
"ran": 14
|
||||||
|
},
|
||||||
|
"path:verify": {
|
||||||
|
"none": 29
|
||||||
|
},
|
||||||
|
"unknown:agree": {
|
||||||
|
"none": 4
|
||||||
|
},
|
||||||
|
"unknown:delta": {
|
||||||
|
"not_applicable": 4
|
||||||
|
},
|
||||||
|
"unknown:engine": {
|
||||||
|
"missing": 2,
|
||||||
|
"none": 2
|
||||||
|
},
|
||||||
|
"unknown:entry_points": {
|
||||||
|
"not_applicable": 4
|
||||||
|
},
|
||||||
|
"unknown:facts": {
|
||||||
|
"not_applicable": 4
|
||||||
|
},
|
||||||
|
"unknown:language": {
|
||||||
|
"ran": 4
|
||||||
|
},
|
||||||
|
"unknown:model_sinks": {
|
||||||
|
"ran": 4
|
||||||
|
},
|
||||||
|
"unknown:quick": {
|
||||||
|
"ran": 4
|
||||||
|
},
|
||||||
|
"unknown:roles": {
|
||||||
|
"none": 4
|
||||||
|
},
|
||||||
|
"unknown:source": {
|
||||||
|
"none": 4
|
||||||
|
},
|
||||||
|
"unknown:verify": {
|
||||||
|
"none": 4
|
||||||
|
},
|
||||||
|
"untrusted_destination:agree": {
|
||||||
|
"none": 11,
|
||||||
|
"ran": 85
|
||||||
|
},
|
||||||
|
"untrusted_destination:delta": {
|
||||||
|
"not_applicable": 96
|
||||||
|
},
|
||||||
|
"untrusted_destination:engine": {
|
||||||
|
"failed": 38,
|
||||||
|
"missing": 12,
|
||||||
|
"none": 17,
|
||||||
|
"ran": 29
|
||||||
|
},
|
||||||
|
"untrusted_destination:entry_points": {
|
||||||
|
"not_applicable": 52,
|
||||||
|
"ran": 44
|
||||||
|
},
|
||||||
|
"untrusted_destination:facts": {
|
||||||
|
"not_applicable": 52,
|
||||||
|
"ran": 44
|
||||||
|
},
|
||||||
|
"untrusted_destination:language": {
|
||||||
|
"ran": 96
|
||||||
|
},
|
||||||
|
"untrusted_destination:model_sinks": {
|
||||||
|
"ran": 96
|
||||||
|
},
|
||||||
|
"untrusted_destination:quick": {
|
||||||
|
"ran": 96
|
||||||
|
},
|
||||||
|
"untrusted_destination:roles": {
|
||||||
|
"failed": 39,
|
||||||
|
"ran": 57
|
||||||
|
},
|
||||||
|
"untrusted_destination:source": {
|
||||||
|
"failed": 33,
|
||||||
|
"ran": 63
|
||||||
|
},
|
||||||
|
"untrusted_destination:verify": {
|
||||||
|
"none": 11,
|
||||||
|
"ran": 85
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"records": {
|
||||||
|
"plane:access_control": 26,
|
||||||
|
"plane:config_secrets": 35,
|
||||||
|
"plane:deserialization": 40,
|
||||||
|
"plane:injection": 168,
|
||||||
|
"plane:memory": 346,
|
||||||
|
"plane:output_encoding": 112,
|
||||||
|
"plane:path": 29,
|
||||||
|
"plane:unknown": 4,
|
||||||
|
"plane:untrusted_destination": 96,
|
||||||
|
"static:access_control": 26,
|
||||||
|
"static:config_secrets": 35,
|
||||||
|
"static:deserialization": 40,
|
||||||
|
"static:injection": 168,
|
||||||
|
"static:memory": 346,
|
||||||
|
"static:output_encoding": 112,
|
||||||
|
"static:path": 29,
|
||||||
|
"static:unknown": 4,
|
||||||
|
"static:untrusted_destination": 96
|
||||||
|
},
|
||||||
|
"skipped_label_rows": {},
|
||||||
|
"store": "file://~/ousast-results/plane/memory (kind features, run harvest)"
|
||||||
|
},
|
||||||
|
"host_peaks": {
|
||||||
|
"disk_free_mb_min": 960,
|
||||||
|
"disk_incident": "Substrate kept every golden actor (~24 MB each, deletion failing on a missing snapshot bucket); free disk fell to 0.95 GB, runs were stopped, the bucket created and orphaned actor directories removed",
|
||||||
|
"mem_available_mb_min": 1990
|
||||||
|
},
|
||||||
|
"label_snapshot_sha256": "18337014d8a5c8df67e06f4e9d8e72c1fb8f82b1ed1b9a18836ab37e6cf4fdc9",
|
||||||
|
"note": "Harvest of the learned decision engine (task 5), COUNTS ONLY. Spend is the plane's attribution table (`ousast plane status`, task meters priced at plane/models/deepseek-flash.yaml); the DeepSeek account moved less (balance below). Feature records are in the local memory store (kind `features`, run `harvest`); the label rows, the units index and the manifests name functions and stay local.",
|
||||||
|
"roles": {
|
||||||
|
"attribution": {
|
||||||
|
"cache_hit_tokens": null,
|
||||||
|
"calls": 1034,
|
||||||
|
"output_tokens": null,
|
||||||
|
"prompt_tokens": null,
|
||||||
|
"usd": 1.4036
|
||||||
|
},
|
||||||
|
"cache_hit_tokens": 329600,
|
||||||
|
"chunks": 1034,
|
||||||
|
"files": 799,
|
||||||
|
"output_tokens": 370155,
|
||||||
|
"prompt_tokens": 2398669,
|
||||||
|
"task_budget_sum_usd": 4.917,
|
||||||
|
"tasks_done": 151,
|
||||||
|
"unclassified_chunks": 0
|
||||||
|
},
|
||||||
|
"runner_image": "localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884",
|
||||||
|
"verify": {
|
||||||
|
"attribution": {
|
||||||
|
"cache_hit_tokens": 6275060,
|
||||||
|
"calls": 1961,
|
||||||
|
"output_tokens": 306941,
|
||||||
|
"prompt_tokens": 10921167,
|
||||||
|
"usd": 2.5373
|
||||||
|
},
|
||||||
|
"file_hunts_done": 364,
|
||||||
|
"flagged_by_pass_units": {
|
||||||
|
"dev-php:vulnerable": {
|
||||||
|
"both": 2
|
||||||
|
},
|
||||||
|
"pairs:fixed": {
|
||||||
|
"both": 4,
|
||||||
|
"none": 58,
|
||||||
|
"one": 1
|
||||||
|
},
|
||||||
|
"pairs:vulnerable": {
|
||||||
|
"both": 45,
|
||||||
|
"none": 11,
|
||||||
|
"one": 7
|
||||||
|
},
|
||||||
|
"population-v1:fixed": {
|
||||||
|
"both": 5,
|
||||||
|
"none": 2,
|
||||||
|
"one": 4
|
||||||
|
},
|
||||||
|
"population-v1:vulnerable": {
|
||||||
|
"both": 8,
|
||||||
|
"none": 2,
|
||||||
|
"one": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hunts_per_pass": 182,
|
||||||
|
"infrastructure_failures": "ax apply / actor template not found for Workspaces over the inline limit (units then skipped); two tasks interrupted by a disk stop were re-run",
|
||||||
|
"skipped_units": {
|
||||||
|
"pairs": 4,
|
||||||
|
"reason": "excerpt over the 20 KB inline Workspace limit"
|
||||||
|
},
|
||||||
|
"task_budget_sum_usd": 8.624,
|
||||||
|
"tasks_done": 474,
|
||||||
|
"units": {
|
||||||
|
"dev-php:vulnerable": 2,
|
||||||
|
"pairs:fixed": 63,
|
||||||
|
"pairs:vulnerable": 63,
|
||||||
|
"population-v1:fixed": 11,
|
||||||
|
"population-v1:vulnerable": 11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,6 +41,13 @@ afterwards (`go clean -cache -modcache`); rerunning the full Substrate install o
|
|||||||
only; the gateway dials the address the actor connected to, so the receiver is a Service dialled by ClusterIP
|
only; the gateway dials the address the actor connected to, so the receiver is a Service dialled by ClusterIP
|
||||||
with its name as Host. The Envoy gateway needs a Rust build; the agentgateway variant needs none.
|
with its name as Host. The Envoy gateway needs a Rust build; the agentgateway variant needs none.
|
||||||
- Apply a Task after the Workspaces it binds; ax copies them at create time.
|
- Apply a Task after the Workspaces it binds; ax copies them at create time.
|
||||||
|
- Every Task is its own actor template with a golden actor (~24 MB under `/var/lib/ate/actors` on the node). Deleting
|
||||||
|
them failed while the snapshot bucket ax's templates name (`dberkov-gke-dev3`, from `AX_SNAPSHOTS_BUCKET`) did not
|
||||||
|
exist in rustfs: golden actors piled up in `DELETING` and filled the disk during a 600-task harvest (2026-10-01).
|
||||||
|
Create that bucket in rustfs (an aws-cli pod with the `rustfs-bucket-init` env); even then a deleted actor's
|
||||||
|
directory stays on the node, so long Runs need a janitor that removes directories no live actor owns.
|
||||||
|
- A Workspace's `files` reach the actor inline in one environment variable: above ~20 KB of content the template
|
||||||
|
fails with "actor template not found" (an 86 KB and a 31 KB excerpt did; 7 KB ran).
|
||||||
|
|
||||||
## Moving to a separate Kubernetes cluster (planned)
|
## Moving to a separate Kubernetes cluster (planned)
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ metadata:
|
|||||||
name: agree
|
name: agree
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: "localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699"
|
image: "localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884"
|
||||||
command: ["agree"]
|
command: ["agree"]
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ metadata:
|
|||||||
name: alerts
|
name: alerts
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: "localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699"
|
image: "localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884"
|
||||||
command: ["alerts"]
|
command: ["alerts"]
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ metadata:
|
|||||||
name: features
|
name: features
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: "localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699"
|
image: "localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884"
|
||||||
command: ["features"]
|
command: ["features"]
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ metadata:
|
|||||||
name: loop
|
name: loop
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: "localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699"
|
image: "localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884"
|
||||||
command: ["loop"]
|
command: ["loop"]
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ metadata:
|
|||||||
name: remember
|
name: remember
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: "localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699"
|
image: "localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884"
|
||||||
command: ["remember"]
|
command: ["remember"]
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ metadata:
|
|||||||
name: repo-facts
|
name: repo-facts
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: "localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699"
|
image: "localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884"
|
||||||
command: ["repo-facts"]
|
command: ["repo-facts"]
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# roles (learned-decision-engine design section 2, Req 8.1): the model reads a repository's source files and names
|
||||||
|
# their roles (sink, source, sanitizer, guard, dispatch), no vocabulary and no framework table. Bound to its Model by
|
||||||
|
# the `openultrasast.io/model` annotation, which the reconciler strips and renders as OUSAST_MODEL /
|
||||||
|
# OUSAST_MODEL_PARAMS. The template of the per-pin Tasks of a harvest Run (`ousast plane harvest`), which name the
|
||||||
|
# files to classify as OUSAST_INPUT_FILES. The image is digest-pinned.
|
||||||
|
apiVersion: ax.io/v1alpha1
|
||||||
|
kind: Task
|
||||||
|
metadata:
|
||||||
|
name: roles
|
||||||
|
atespace: default
|
||||||
|
annotations:
|
||||||
|
openultrasast.io/model: deepseek-flash
|
||||||
|
spec:
|
||||||
|
image: "localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884"
|
||||||
|
command: ["roles"]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: "250m"
|
||||||
|
memory: "384Mi"
|
||||||
|
limits:
|
||||||
|
cpu: "1"
|
||||||
|
memory: "1Gi"
|
||||||
+120
-120
@@ -5,9 +5,9 @@ metadata:
|
|||||||
name: repo-facts-budibase-mongo-template-nosqli
|
name: repo-facts-budibase-mongo-template-nosqli
|
||||||
atespace: default
|
atespace: default
|
||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/memory-key: '{"candidates":"b4ef709df34ab08c","image":"sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699","pin":"b7e63df737eede85d951aa9665b0c0778ece7ccb","repo":"github.com/Budibase/budibase"}'
|
openultrasast.io/memory-key: '{"candidates":"b4ef709df34ab08c","image":"sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884","pin":"b7e63df737eede85d951aa9665b0c0778ece7ccb","repo":"github.com/Budibase/budibase"}'
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- repo-facts
|
- repo-facts
|
||||||
env:
|
env:
|
||||||
@@ -36,7 +36,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -67,7 +67,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -96,7 +96,7 @@ metadata:
|
|||||||
name: agree-budibase-mongo-template-nosqli
|
name: agree-budibase-mongo-template-nosqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- agree
|
- agree
|
||||||
env:
|
env:
|
||||||
@@ -123,9 +123,9 @@ metadata:
|
|||||||
name: repo-facts-cct-studio-server-cmdi
|
name: repo-facts-cct-studio-server-cmdi
|
||||||
atespace: default
|
atespace: default
|
||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/memory-key: '{"candidates":"6c9fa4a6e47cda37","image":"sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699","pin":"acdb5893412a81eaec9862ee24a4613bf296ab45","repo":"github.com/davila7/claude-code-templates"}'
|
openultrasast.io/memory-key: '{"candidates":"6c9fa4a6e47cda37","image":"sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884","pin":"acdb5893412a81eaec9862ee24a4613bf296ab45","repo":"github.com/davila7/claude-code-templates"}'
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- repo-facts
|
- repo-facts
|
||||||
env:
|
env:
|
||||||
@@ -154,7 +154,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -185,7 +185,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -214,7 +214,7 @@ metadata:
|
|||||||
name: agree-cct-studio-server-cmdi
|
name: agree-cct-studio-server-cmdi
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- agree
|
- agree
|
||||||
env:
|
env:
|
||||||
@@ -241,9 +241,9 @@ metadata:
|
|||||||
name: repo-facts-contextforge-prompt-ssti
|
name: repo-facts-contextforge-prompt-ssti
|
||||||
atespace: default
|
atespace: default
|
||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/memory-key: '{"candidates":"b272af6456664ebc","image":"sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699","pin":"0f8e0ad679f1fff685f486e17f642ac863c8ca9e","repo":"github.com/IBM/mcp-context-forge"}'
|
openultrasast.io/memory-key: '{"candidates":"b272af6456664ebc","image":"sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884","pin":"0f8e0ad679f1fff685f486e17f642ac863c8ca9e","repo":"github.com/IBM/mcp-context-forge"}'
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- repo-facts
|
- repo-facts
|
||||||
env:
|
env:
|
||||||
@@ -272,7 +272,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -303,7 +303,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -332,7 +332,7 @@ metadata:
|
|||||||
name: agree-contextforge-prompt-ssti
|
name: agree-contextforge-prompt-ssti
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- agree
|
- agree
|
||||||
env:
|
env:
|
||||||
@@ -359,9 +359,9 @@ metadata:
|
|||||||
name: repo-facts-froxlor-admin-ip-second-order-sqli
|
name: repo-facts-froxlor-admin-ip-second-order-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/memory-key: '{"candidates":"c52240d980ef0105","image":"sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699","pin":"9bf03de643a2edee4642bfc6c94db1f05253da02","repo":"github.com/froxlor/froxlor"}'
|
openultrasast.io/memory-key: '{"candidates":"c52240d980ef0105","image":"sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884","pin":"9bf03de643a2edee4642bfc6c94db1f05253da02","repo":"github.com/froxlor/froxlor"}'
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- repo-facts
|
- repo-facts
|
||||||
env:
|
env:
|
||||||
@@ -390,7 +390,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -421,7 +421,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -450,7 +450,7 @@ metadata:
|
|||||||
name: agree-froxlor-admin-ip-second-order-sqli
|
name: agree-froxlor-admin-ip-second-order-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- agree
|
- agree
|
||||||
env:
|
env:
|
||||||
@@ -477,9 +477,9 @@ metadata:
|
|||||||
name: repo-facts-fuxa-tdengine-escape-sqli
|
name: repo-facts-fuxa-tdengine-escape-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/memory-key: '{"candidates":"ec699ee54d38a8ee","image":"sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699","pin":"193a888f8e3f805325072829b1644a2c768c948b","repo":"github.com/frangoteam/FUXA"}'
|
openultrasast.io/memory-key: '{"candidates":"ec699ee54d38a8ee","image":"sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884","pin":"193a888f8e3f805325072829b1644a2c768c948b","repo":"github.com/frangoteam/FUXA"}'
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- repo-facts
|
- repo-facts
|
||||||
env:
|
env:
|
||||||
@@ -508,7 +508,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -539,7 +539,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -568,7 +568,7 @@ metadata:
|
|||||||
name: agree-fuxa-tdengine-escape-sqli
|
name: agree-fuxa-tdengine-escape-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- agree
|
- agree
|
||||||
env:
|
env:
|
||||||
@@ -595,9 +595,9 @@ metadata:
|
|||||||
name: repo-facts-lmdeploy-media-url-ssrf
|
name: repo-facts-lmdeploy-media-url-ssrf
|
||||||
atespace: default
|
atespace: default
|
||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/memory-key: '{"candidates":"1337c9c717f5ac87","image":"sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699","pin":"71648d239c978452720a6d6692fe914efc8a7b94","repo":"github.com/InternLM/lmdeploy"}'
|
openultrasast.io/memory-key: '{"candidates":"1337c9c717f5ac87","image":"sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884","pin":"71648d239c978452720a6d6692fe914efc8a7b94","repo":"github.com/InternLM/lmdeploy"}'
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- repo-facts
|
- repo-facts
|
||||||
env:
|
env:
|
||||||
@@ -626,7 +626,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -657,7 +657,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -686,7 +686,7 @@ metadata:
|
|||||||
name: agree-lmdeploy-media-url-ssrf
|
name: agree-lmdeploy-media-url-ssrf
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- agree
|
- agree
|
||||||
env:
|
env:
|
||||||
@@ -713,9 +713,9 @@ metadata:
|
|||||||
name: repo-facts-medplum-external-auth-open-redirect
|
name: repo-facts-medplum-external-auth-open-redirect
|
||||||
atespace: default
|
atespace: default
|
||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/memory-key: '{"candidates":"17ba609d5b1a1a00","image":"sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699","pin":"5d4a8654b02aa67c444f96ae1eb5663c09854006","repo":"github.com/medplum/medplum"}'
|
openultrasast.io/memory-key: '{"candidates":"17ba609d5b1a1a00","image":"sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884","pin":"5d4a8654b02aa67c444f96ae1eb5663c09854006","repo":"github.com/medplum/medplum"}'
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- repo-facts
|
- repo-facts
|
||||||
env:
|
env:
|
||||||
@@ -744,7 +744,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -775,7 +775,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -804,7 +804,7 @@ metadata:
|
|||||||
name: agree-medplum-external-auth-open-redirect
|
name: agree-medplum-external-auth-open-redirect
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- agree
|
- agree
|
||||||
env:
|
env:
|
||||||
@@ -831,9 +831,9 @@ metadata:
|
|||||||
name: repo-facts-pgadmin-maintenance-sqli
|
name: repo-facts-pgadmin-maintenance-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/memory-key: '{"candidates":"7f1b83a88024c2d4","image":"sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699","pin":"d112dc3b962218efc3613fa727d54f0fc5b1d527","repo":"github.com/pgadmin-org/pgadmin4"}'
|
openultrasast.io/memory-key: '{"candidates":"7f1b83a88024c2d4","image":"sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884","pin":"d112dc3b962218efc3613fa727d54f0fc5b1d527","repo":"github.com/pgadmin-org/pgadmin4"}'
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- repo-facts
|
- repo-facts
|
||||||
env:
|
env:
|
||||||
@@ -862,7 +862,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -893,7 +893,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -922,7 +922,7 @@ metadata:
|
|||||||
name: agree-pgadmin-maintenance-sqli
|
name: agree-pgadmin-maintenance-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- agree
|
- agree
|
||||||
env:
|
env:
|
||||||
@@ -949,9 +949,9 @@ metadata:
|
|||||||
name: repo-facts-qwed-sympy-eval
|
name: repo-facts-qwed-sympy-eval
|
||||||
atespace: default
|
atespace: default
|
||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/memory-key: '{"candidates":"f071e8db5f5517ab","image":"sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699","pin":"06801f68cbf9c9b5e54cc17f2a61cb2792da7a26","repo":"github.com/QWED-AI/qwed-verification"}'
|
openultrasast.io/memory-key: '{"candidates":"f071e8db5f5517ab","image":"sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884","pin":"06801f68cbf9c9b5e54cc17f2a61cb2792da7a26","repo":"github.com/QWED-AI/qwed-verification"}'
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- repo-facts
|
- repo-facts
|
||||||
env:
|
env:
|
||||||
@@ -980,7 +980,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1011,7 +1011,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1040,7 +1040,7 @@ metadata:
|
|||||||
name: agree-qwed-sympy-eval
|
name: agree-qwed-sympy-eval
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- agree
|
- agree
|
||||||
env:
|
env:
|
||||||
@@ -1067,9 +1067,9 @@ metadata:
|
|||||||
name: repo-facts-reactpress-findall-column-sqli
|
name: repo-facts-reactpress-findall-column-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/memory-key: '{"candidates":"ecb82a10249c6fed","image":"sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699","pin":"c3dd10681b3d2b5e224f7ac647b3769557603975","repo":"github.com/fecommunity/reactpress"}'
|
openultrasast.io/memory-key: '{"candidates":"ecb82a10249c6fed","image":"sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884","pin":"c3dd10681b3d2b5e224f7ac647b3769557603975","repo":"github.com/fecommunity/reactpress"}'
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- repo-facts
|
- repo-facts
|
||||||
env:
|
env:
|
||||||
@@ -1098,7 +1098,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1129,7 +1129,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1158,7 +1158,7 @@ metadata:
|
|||||||
name: agree-reactpress-findall-column-sqli
|
name: agree-reactpress-findall-column-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- agree
|
- agree
|
||||||
env:
|
env:
|
||||||
@@ -1185,9 +1185,9 @@ metadata:
|
|||||||
name: repo-facts-unleash-addon-webhook-ssrf
|
name: repo-facts-unleash-addon-webhook-ssrf
|
||||||
atespace: default
|
atespace: default
|
||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/memory-key: '{"candidates":"4d3debd51fd86f9c","image":"sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699","pin":"b9f3217d327f24094b4352130baa30387f85cffe","repo":"github.com/Unleash/unleash"}'
|
openultrasast.io/memory-key: '{"candidates":"4d3debd51fd86f9c","image":"sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884","pin":"b9f3217d327f24094b4352130baa30387f85cffe","repo":"github.com/Unleash/unleash"}'
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- repo-facts
|
- repo-facts
|
||||||
env:
|
env:
|
||||||
@@ -1216,7 +1216,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1247,7 +1247,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1276,7 +1276,7 @@ metadata:
|
|||||||
name: agree-unleash-addon-webhook-ssrf
|
name: agree-unleash-addon-webhook-ssrf
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- agree
|
- agree
|
||||||
env:
|
env:
|
||||||
@@ -1303,9 +1303,9 @@ metadata:
|
|||||||
name: repo-facts-winml-cli-serve-cors
|
name: repo-facts-winml-cli-serve-cors
|
||||||
atespace: default
|
atespace: default
|
||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/memory-key: '{"candidates":"e3b0c44298fc1c14","image":"sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699","pin":"02179d185f0e3ac23518236b5ca1f61fd37ef680","repo":"github.com/microsoft/winml-cli"}'
|
openultrasast.io/memory-key: '{"candidates":"e3b0c44298fc1c14","image":"sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884","pin":"02179d185f0e3ac23518236b5ca1f61fd37ef680","repo":"github.com/microsoft/winml-cli"}'
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- repo-facts
|
- repo-facts
|
||||||
env:
|
env:
|
||||||
@@ -1334,7 +1334,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1365,7 +1365,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1394,7 +1394,7 @@ metadata:
|
|||||||
name: agree-winml-cli-serve-cors
|
name: agree-winml-cli-serve-cors
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- agree
|
- agree
|
||||||
env:
|
env:
|
||||||
@@ -1421,9 +1421,9 @@ metadata:
|
|||||||
name: repo-facts-wp-directorist-avatar-ssrf
|
name: repo-facts-wp-directorist-avatar-ssrf
|
||||||
atespace: default
|
atespace: default
|
||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/memory-key: '{"candidates":"d6963021f588f39e","image":"sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699","pin":"77cfc9bc8b453f97ab7e720330706fa4ef056867","repo":"github.com/sovware/directorist"}'
|
openultrasast.io/memory-key: '{"candidates":"d6963021f588f39e","image":"sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884","pin":"77cfc9bc8b453f97ab7e720330706fa4ef056867","repo":"github.com/sovware/directorist"}'
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- repo-facts
|
- repo-facts
|
||||||
env:
|
env:
|
||||||
@@ -1452,7 +1452,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1483,7 +1483,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1512,7 +1512,7 @@ metadata:
|
|||||||
name: agree-wp-directorist-avatar-ssrf
|
name: agree-wp-directorist-avatar-ssrf
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- agree
|
- agree
|
||||||
env:
|
env:
|
||||||
@@ -1539,9 +1539,9 @@ metadata:
|
|||||||
name: repo-facts-wp-gopay-log-filter-sqli
|
name: repo-facts-wp-gopay-log-filter-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/memory-key: '{"candidates":"fde4d17144a13d73","image":"sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699","pin":"626bc8b5f8d33de6eefd921e3a05ed52ac320bcd","repo":"github.com/gopaycommunity/gopay-woocommerce-integration"}'
|
openultrasast.io/memory-key: '{"candidates":"fde4d17144a13d73","image":"sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884","pin":"626bc8b5f8d33de6eefd921e3a05ed52ac320bcd","repo":"github.com/gopaycommunity/gopay-woocommerce-integration"}'
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- repo-facts
|
- repo-facts
|
||||||
env:
|
env:
|
||||||
@@ -1570,7 +1570,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1601,7 +1601,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1630,7 +1630,7 @@ metadata:
|
|||||||
name: agree-wp-gopay-log-filter-sqli
|
name: agree-wp-gopay-log-filter-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- agree
|
- agree
|
||||||
env:
|
env:
|
||||||
@@ -1657,9 +1657,9 @@ metadata:
|
|||||||
name: repo-facts-wp-groundhogg-confirm-redirect
|
name: repo-facts-wp-groundhogg-confirm-redirect
|
||||||
atespace: default
|
atespace: default
|
||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/memory-key: '{"candidates":"fde4d17144a13d73","image":"sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699","pin":"9472a1dd79d4556c40eece501a61930793f170d3","repo":"github.com/groundhoggwp/groundhogg"}'
|
openultrasast.io/memory-key: '{"candidates":"fde4d17144a13d73","image":"sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884","pin":"9472a1dd79d4556c40eece501a61930793f170d3","repo":"github.com/groundhoggwp/groundhogg"}'
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- repo-facts
|
- repo-facts
|
||||||
env:
|
env:
|
||||||
@@ -1688,7 +1688,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1719,7 +1719,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1748,7 +1748,7 @@ metadata:
|
|||||||
name: agree-wp-groundhogg-confirm-redirect
|
name: agree-wp-groundhogg-confirm-redirect
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- agree
|
- agree
|
||||||
env:
|
env:
|
||||||
@@ -1777,7 +1777,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1808,7 +1808,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1839,7 +1839,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1870,7 +1870,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1901,7 +1901,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1932,7 +1932,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1963,7 +1963,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -1994,7 +1994,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -2025,7 +2025,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -2056,7 +2056,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -2087,7 +2087,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -2118,7 +2118,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -2149,7 +2149,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -2180,7 +2180,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -2211,7 +2211,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- verify
|
- verify
|
||||||
env:
|
env:
|
||||||
@@ -2240,7 +2240,7 @@ metadata:
|
|||||||
name: features-budibase-mongo-template-nosqli
|
name: features-budibase-mongo-template-nosqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- features
|
- features
|
||||||
env:
|
env:
|
||||||
@@ -2263,7 +2263,7 @@ metadata:
|
|||||||
name: remember-budibase-mongo-template-nosqli
|
name: remember-budibase-mongo-template-nosqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- remember
|
- remember
|
||||||
env:
|
env:
|
||||||
@@ -2288,7 +2288,7 @@ metadata:
|
|||||||
name: features-cct-studio-server-cmdi
|
name: features-cct-studio-server-cmdi
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- features
|
- features
|
||||||
env:
|
env:
|
||||||
@@ -2311,7 +2311,7 @@ metadata:
|
|||||||
name: remember-cct-studio-server-cmdi
|
name: remember-cct-studio-server-cmdi
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- remember
|
- remember
|
||||||
env:
|
env:
|
||||||
@@ -2336,7 +2336,7 @@ metadata:
|
|||||||
name: features-contextforge-prompt-ssti
|
name: features-contextforge-prompt-ssti
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- features
|
- features
|
||||||
env:
|
env:
|
||||||
@@ -2359,7 +2359,7 @@ metadata:
|
|||||||
name: remember-contextforge-prompt-ssti
|
name: remember-contextforge-prompt-ssti
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- remember
|
- remember
|
||||||
env:
|
env:
|
||||||
@@ -2384,7 +2384,7 @@ metadata:
|
|||||||
name: features-froxlor-admin-ip-second-order-sqli
|
name: features-froxlor-admin-ip-second-order-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- features
|
- features
|
||||||
env:
|
env:
|
||||||
@@ -2407,7 +2407,7 @@ metadata:
|
|||||||
name: remember-froxlor-admin-ip-second-order-sqli
|
name: remember-froxlor-admin-ip-second-order-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- remember
|
- remember
|
||||||
env:
|
env:
|
||||||
@@ -2432,7 +2432,7 @@ metadata:
|
|||||||
name: features-fuxa-tdengine-escape-sqli
|
name: features-fuxa-tdengine-escape-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- features
|
- features
|
||||||
env:
|
env:
|
||||||
@@ -2455,7 +2455,7 @@ metadata:
|
|||||||
name: remember-fuxa-tdengine-escape-sqli
|
name: remember-fuxa-tdengine-escape-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- remember
|
- remember
|
||||||
env:
|
env:
|
||||||
@@ -2480,7 +2480,7 @@ metadata:
|
|||||||
name: features-lmdeploy-media-url-ssrf
|
name: features-lmdeploy-media-url-ssrf
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- features
|
- features
|
||||||
env:
|
env:
|
||||||
@@ -2503,7 +2503,7 @@ metadata:
|
|||||||
name: remember-lmdeploy-media-url-ssrf
|
name: remember-lmdeploy-media-url-ssrf
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- remember
|
- remember
|
||||||
env:
|
env:
|
||||||
@@ -2528,7 +2528,7 @@ metadata:
|
|||||||
name: features-medplum-external-auth-open-redirect
|
name: features-medplum-external-auth-open-redirect
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- features
|
- features
|
||||||
env:
|
env:
|
||||||
@@ -2551,7 +2551,7 @@ metadata:
|
|||||||
name: remember-medplum-external-auth-open-redirect
|
name: remember-medplum-external-auth-open-redirect
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- remember
|
- remember
|
||||||
env:
|
env:
|
||||||
@@ -2576,7 +2576,7 @@ metadata:
|
|||||||
name: features-pgadmin-maintenance-sqli
|
name: features-pgadmin-maintenance-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- features
|
- features
|
||||||
env:
|
env:
|
||||||
@@ -2599,7 +2599,7 @@ metadata:
|
|||||||
name: remember-pgadmin-maintenance-sqli
|
name: remember-pgadmin-maintenance-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- remember
|
- remember
|
||||||
env:
|
env:
|
||||||
@@ -2624,7 +2624,7 @@ metadata:
|
|||||||
name: features-qwed-sympy-eval
|
name: features-qwed-sympy-eval
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- features
|
- features
|
||||||
env:
|
env:
|
||||||
@@ -2647,7 +2647,7 @@ metadata:
|
|||||||
name: remember-qwed-sympy-eval
|
name: remember-qwed-sympy-eval
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- remember
|
- remember
|
||||||
env:
|
env:
|
||||||
@@ -2672,7 +2672,7 @@ metadata:
|
|||||||
name: features-reactpress-findall-column-sqli
|
name: features-reactpress-findall-column-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- features
|
- features
|
||||||
env:
|
env:
|
||||||
@@ -2695,7 +2695,7 @@ metadata:
|
|||||||
name: remember-reactpress-findall-column-sqli
|
name: remember-reactpress-findall-column-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- remember
|
- remember
|
||||||
env:
|
env:
|
||||||
@@ -2720,7 +2720,7 @@ metadata:
|
|||||||
name: features-unleash-addon-webhook-ssrf
|
name: features-unleash-addon-webhook-ssrf
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- features
|
- features
|
||||||
env:
|
env:
|
||||||
@@ -2743,7 +2743,7 @@ metadata:
|
|||||||
name: remember-unleash-addon-webhook-ssrf
|
name: remember-unleash-addon-webhook-ssrf
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- remember
|
- remember
|
||||||
env:
|
env:
|
||||||
@@ -2768,7 +2768,7 @@ metadata:
|
|||||||
name: features-winml-cli-serve-cors
|
name: features-winml-cli-serve-cors
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- features
|
- features
|
||||||
env:
|
env:
|
||||||
@@ -2791,7 +2791,7 @@ metadata:
|
|||||||
name: remember-winml-cli-serve-cors
|
name: remember-winml-cli-serve-cors
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- remember
|
- remember
|
||||||
env:
|
env:
|
||||||
@@ -2816,7 +2816,7 @@ metadata:
|
|||||||
name: features-wp-directorist-avatar-ssrf
|
name: features-wp-directorist-avatar-ssrf
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- features
|
- features
|
||||||
env:
|
env:
|
||||||
@@ -2839,7 +2839,7 @@ metadata:
|
|||||||
name: remember-wp-directorist-avatar-ssrf
|
name: remember-wp-directorist-avatar-ssrf
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- remember
|
- remember
|
||||||
env:
|
env:
|
||||||
@@ -2864,7 +2864,7 @@ metadata:
|
|||||||
name: features-wp-gopay-log-filter-sqli
|
name: features-wp-gopay-log-filter-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- features
|
- features
|
||||||
env:
|
env:
|
||||||
@@ -2887,7 +2887,7 @@ metadata:
|
|||||||
name: remember-wp-gopay-log-filter-sqli
|
name: remember-wp-gopay-log-filter-sqli
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- remember
|
- remember
|
||||||
env:
|
env:
|
||||||
@@ -2912,7 +2912,7 @@ metadata:
|
|||||||
name: features-wp-groundhogg-confirm-redirect
|
name: features-wp-groundhogg-confirm-redirect
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- features
|
- features
|
||||||
env:
|
env:
|
||||||
@@ -2935,7 +2935,7 @@ metadata:
|
|||||||
name: remember-wp-groundhogg-confirm-redirect
|
name: remember-wp-groundhogg-confirm-redirect
|
||||||
atespace: default
|
atespace: default
|
||||||
spec:
|
spec:
|
||||||
image: localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699
|
image: localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884
|
||||||
command:
|
command:
|
||||||
- remember
|
- remember
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ metadata:
|
|||||||
annotations:
|
annotations:
|
||||||
openultrasast.io/model: deepseek-flash
|
openultrasast.io/model: deepseek-flash
|
||||||
spec:
|
spec:
|
||||||
image: "localhost:5001/ousast-runner@sha256:e9964977659c4dcea7d8b25390ca0e16368ac901dd076aa6138df8303a0bb699"
|
image: "localhost:5001/ousast-runner@sha256:412db0a1504af8f1b23a395af8d1dcbd152c1bb6d16594f2b733067163a31884"
|
||||||
command: ["verify"]
|
command: ["verify"]
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
|
|||||||
@@ -296,6 +296,21 @@ def _main(argv: list[str] | None) -> int:
|
|||||||
plane_engine.add_argument("--image", default="openultrasast:dev")
|
plane_engine.add_argument("--image", default="openultrasast:dev")
|
||||||
plane_engine.add_argument("--repos", type=Path, help="the case cache (default ~/.cache/openultrasast/independent)")
|
plane_engine.add_argument("--repos", type=Path, help="the case cache (default ~/.cache/openultrasast/independent)")
|
||||||
plane_engine.add_argument("--work", type=Path, help="where pins are exported and results land (default: a temporary directory)")
|
plane_engine.add_argument("--work", type=Path, help="where pins are exported and results land (default: a temporary directory)")
|
||||||
|
plane_harvest = plane_sub.add_parser(
|
||||||
|
"harvest", help="the decision engine's harvest Runs (verify a/b + agree, model roles) over a label snapshot"
|
||||||
|
)
|
||||||
|
plane_harvest.add_argument("--labels", type=Path, required=True, help="the full label rows (`ousast learn labels --out`)")
|
||||||
|
plane_harvest.add_argument(
|
||||||
|
"--plane", type=Path, required=True, help="where to write runs/, tasks/, workspaces/, models/, units.json (scratch)"
|
||||||
|
)
|
||||||
|
plane_harvest.add_argument("--name", default="harvest", help="Run name prefix: <name>-verify and <name>-roles")
|
||||||
|
plane_harvest.add_argument("--templates", type=Path, default=Path("plane"), help="the plane root holding tasks/ and models/ templates")
|
||||||
|
plane_harvest.add_argument("--catalog", type=Path, default=Path("benchmarks/pairs/catalog.toml"))
|
||||||
|
plane_harvest.add_argument(
|
||||||
|
"--cache", type=Path, default=Path.home() / ".cache" / "openultrasast", help="case clones and recipe checkouts"
|
||||||
|
)
|
||||||
|
plane_harvest.add_argument("--ceiling", type=float, default=10.0, help="USD: each Run's task budgets sum to at most this")
|
||||||
|
plane_harvest.add_argument("--runner-image", type=Path, help="re-pin the task templates to the image in this file first (ops/ax/up.sh)")
|
||||||
plane_ws = plane_sub.add_parser("workspaces", help="one Workspace manifest per case pin of a population file")
|
plane_ws = plane_sub.add_parser("workspaces", help="one Workspace manifest per case pin of a population file")
|
||||||
plane_ws.add_argument("population", type=Path)
|
plane_ws.add_argument("population", type=Path)
|
||||||
plane_ws.add_argument("--out", type=Path, default=Path("plane/workspaces"))
|
plane_ws.add_argument("--out", type=Path, default=Path("plane/workspaces"))
|
||||||
@@ -1371,6 +1386,8 @@ def _plane(args: argparse.Namespace) -> int:
|
|||||||
return 0
|
return 0
|
||||||
if args.plane_command == "alerts-engine":
|
if args.plane_command == "alerts-engine":
|
||||||
return _plane_alerts_engine(args)
|
return _plane_alerts_engine(args)
|
||||||
|
if args.plane_command == "harvest":
|
||||||
|
return _plane_harvest(args)
|
||||||
if args.plane_command == "doctor":
|
if args.plane_command == "doctor":
|
||||||
checks = reconciler.doctor()
|
checks = reconciler.doctor()
|
||||||
for name, ok, text in checks:
|
for name, ok, text in checks:
|
||||||
@@ -1385,6 +1402,22 @@ def _plane(args: argparse.Namespace) -> int:
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def _plane_harvest(args: argparse.Namespace) -> int:
|
||||||
|
from .plane.generate import repin_templates
|
||||||
|
from .plane.harvest import write_harvest
|
||||||
|
|
||||||
|
if args.runner_image is not None:
|
||||||
|
repin_templates(args.templates, args.runner_image)
|
||||||
|
command = f"ousast plane harvest --labels {args.labels.name} --name {args.name} --ceiling {args.ceiling:g}"
|
||||||
|
files = write_harvest(
|
||||||
|
args.labels, args.plane, name=args.name, command=command, catalog=args.catalog, cache=args.cache, templates=args.templates,
|
||||||
|
ceiling=args.ceiling,
|
||||||
|
) # fmt: skip
|
||||||
|
for relative in sorted(k for k in files if k.startswith("runs/")):
|
||||||
|
print(f"{args.plane / relative}: {files[relative].splitlines()[1].lstrip('# ')}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def _plane_alerts_engine(args: argparse.Namespace) -> int:
|
def _plane_alerts_engine(args: argparse.Namespace) -> int:
|
||||||
from .plane import engine_alerts
|
from .plane import engine_alerts
|
||||||
|
|
||||||
|
|||||||
@@ -254,7 +254,9 @@ def function_span(lines: Sequence[str], language: str, function: str) -> int | N
|
|||||||
|
|
||||||
|
|
||||||
def source_part(lines: Sequence[str] | None, language: str, function: str) -> Part:
|
def source_part(lines: Sequence[str] | None, language: str, function: str) -> Part:
|
||||||
if lines is None:
|
"""The function's span; ``none`` without the file or a declaration pattern for its language (C, say: no coverage,
|
||||||
|
not a failure), ``failed`` when a covered file does not declare the function."""
|
||||||
|
if lines is None or (function != GLOBAL and language not in DECLARATION):
|
||||||
return NONE
|
return NONE
|
||||||
span = function_span(lines, language, function)
|
span = function_span(lines, language, function)
|
||||||
return Part("ran", {"facts.function_lines": span}) if span is not None else Part("failed")
|
return Part("ran", {"facts.function_lines": span}) if span is not None else Part("failed")
|
||||||
@@ -294,8 +296,9 @@ def agree_part(final: str | None) -> Part:
|
|||||||
|
|
||||||
def roles_part(function: Function | None, roles: RoleSet | None, language: str) -> Part:
|
def roles_part(function: Function | None, roles: RoleSet | None, language: str) -> Part:
|
||||||
"""The deterministic roles of the candidate's function (language-level entries plus wrapper inference; priors
|
"""The deterministic roles of the candidate's function (language-level entries plus wrapper inference; priors
|
||||||
off): ``none`` when inference did not run, ``failed`` when the function's body could not be found."""
|
off): ``none`` when inference did not run or cannot read the language's declarations, ``failed`` when the
|
||||||
if roles is None or "inferred_wrapper" not in roles.sources:
|
function's body could not be found."""
|
||||||
|
if roles is None or "inferred_wrapper" not in roles.sources or language not in DECLARATION:
|
||||||
return NONE
|
return NONE
|
||||||
if function is None:
|
if function is None:
|
||||||
return Part("failed", version=VERSION)
|
return Part("failed", version=VERSION)
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ CASE_PATH = "/workspace/case"
|
|||||||
INPUTS_PATH = "/workspace/inputs"
|
INPUTS_PATH = "/workspace/inputs"
|
||||||
FIXED_PATH = "/workspace/fixed"
|
FIXED_PATH = "/workspace/fixed"
|
||||||
PROJECT_PATH = "/workspace/project"
|
PROJECT_PATH = "/workspace/project"
|
||||||
TEMPLATES = ("repo-facts", "verify", "agree", "remember", "alerts", "loop", "features")
|
TEMPLATES = ("repo-facts", "verify", "agree", "remember", "alerts", "loop", "features", "roles")
|
||||||
FIXED_RANGES_BASIS = "git diff -U0 <vulnerable> <fixed>, new side: the fix's lines at the fixed pin"
|
FIXED_RANGES_BASIS = "git diff -U0 <vulnerable> <fixed>, new side: the fix's lines at the fixed pin"
|
||||||
LOOP_MANIFEST = "benchmarks/manifests/java-spring-boot-vulnerable.toml" # the equality baseline's `improve` manifest
|
LOOP_MANIFEST = "benchmarks/manifests/java-spring-boot-vulnerable.toml" # the equality baseline's `improve` manifest
|
||||||
LOOP_CATALOG = "benchmarks/pairs/catalog.toml"
|
LOOP_CATALOG = "benchmarks/pairs/catalog.toml"
|
||||||
|
|||||||
@@ -0,0 +1,379 @@
|
|||||||
|
"""The harvest Runs of the learned decision engine (design, commit sequence item 5; Req 1.1).
|
||||||
|
|
||||||
|
``ousast plane harvest --labels labels-<sha>.jsonl --plane DIR`` writes two Runs over the labelled units of a label
|
||||||
|
snapshot (``ousast learn labels --out``), with the Workspaces and Tasks they need, under ``DIR`` (a scratch plane
|
||||||
|
root: the excerpts and candidates are inputs, never committed):
|
||||||
|
|
||||||
|
- ``runs/<name>-verify.yaml``: verify passes a and b and ``agree`` (no tie-break) on every verify-family unit
|
||||||
|
(:data:`.tasks.verify.OPERATIONS`): both sides of each labelled pair, and the development pins -- population v1's
|
||||||
|
vulnerable and fixed pins, the dev-php recipes -- with ``repo-facts`` first for their callers;
|
||||||
|
- ``runs/<name>-roles.yaml``: ``roles`` (model roles) on the candidate files of every labelled pin unit: the pair
|
||||||
|
sides, grouped many to a Workspace (a roles prompt sees one chunk of one file, so grouping changes nothing it
|
||||||
|
reads), and one Task per population or recipe pin.
|
||||||
|
|
||||||
|
Units carry no label. A pair side is a files-only Workspace holding the excerpt (and the documents that register
|
||||||
|
it) under ``repo/`` and the candidates under ``inputs/`` -- outside the hunt's root, so the tools cannot read them;
|
||||||
|
its name is opaque (``h-<sha>``): the pair's name says its CWE and its side. ``agree`` gets no declared sites, so
|
||||||
|
no ``site_match`` is computed. ``units.json`` maps each unit name to its source, reference, side, repository, pin
|
||||||
|
and candidates for the host-side feature build; it names functions and stays local.
|
||||||
|
|
||||||
|
Every Run entry has a budget; the sum over each Run is held under ``ceiling`` (USD) by construction: verify gets
|
||||||
|
:data:`USD_PER_HUNT` per hunt of an excerpt or a repository (scaled down when the hunts would exceed the ceiling),
|
||||||
|
roles a per-chunk estimate times a headroom, scaled down to the ceiling.
|
||||||
|
A pair side's pin is the git blob sha1 of its excerpt (the store keys rows by
|
||||||
|
a 40-hex pin; an excerpt has no commit of its own).
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
from collections.abc import Iterable, Mapping, Sequence
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from ..preprocess import detect_language
|
||||||
|
from .generate import ATESPACE, CALLS_PER_HUNT, CASE_PATH, INPUTS_PATH, _dump, _json, _task
|
||||||
|
from .manifests import GIT_COMMITS_ANNOTATION, RUN_API_VERSION, Task
|
||||||
|
from .reconciler import _ax_name, _doc
|
||||||
|
from .tasks.repo_facts import DECLARATION, GLOBAL, _declared_name
|
||||||
|
from .tasks.roles import CHUNK_LINES
|
||||||
|
from .tasks.verify import OPERATIONS, units_of
|
||||||
|
|
||||||
|
__all__ = ["Unit", "declaration_line", "pair_units", "population_units", "render_harvest", "write_harvest"]
|
||||||
|
|
||||||
|
Candidate = tuple[str, str, int]
|
||||||
|
REPO = "repo"
|
||||||
|
# Per verify hunt (pilot 2026-10-01: an excerpt hunt cost $0.003-0.004, a repository hunt $0.019-0.022): ~3x and ~2.5x.
|
||||||
|
USD_PER_HUNT = {"excerpt": 0.012, "repository": 0.05}
|
||||||
|
ROLES_GROUP_FILES = 40
|
||||||
|
# A Workspace's files travel inline: ax hands them to the actor in one environment variable (AX_WORKSPACES_YAML), which
|
||||||
|
# Linux caps at 128 KiB (MAX_ARG_STRLEN) after YAML escaping. An 86 KB excerpt failed with "actor template not found"
|
||||||
|
# (2026-10-01), so did a 31 KB one; 7 KB ran. A unit whose own files exceed the limit is skipped, listed in `units.json`.
|
||||||
|
MAX_INLINE_BYTES = 20_000
|
||||||
|
ROLES_OUTPUT_TOKENS = 700 # per chunk, generous: a role list with evidence quotes
|
||||||
|
ROLES_HEADROOM = 2.5
|
||||||
|
UNKNOWN_SIZE = (80_000, 2_000) # (characters, lines) assumed for a candidate file the host could not read
|
||||||
|
PRICES = {"input_per_m": 0.44, "output_per_m": 1.32} # plane/models/deepseek-flash.yaml
|
||||||
|
POPULATION_SOURCES = ("population-v1", "population-v2", "dev-php", "adjudications")
|
||||||
|
VERIFY_SOURCES = ("population-v1", "dev-php") # the development cases (design section 3); v2 has its recorded Run
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class Unit:
|
||||||
|
"""One pin of the harvest: a repository at a commit (``files`` empty) or one side of a pair (``files`` holds the
|
||||||
|
excerpt). ``family`` is the verify family, ``""`` when the unit is classified by ``roles`` only."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
source: str
|
||||||
|
ref: str
|
||||||
|
side: str
|
||||||
|
repo: str
|
||||||
|
pin: str
|
||||||
|
family: str
|
||||||
|
candidates: tuple[Candidate, ...]
|
||||||
|
files: tuple[tuple[str, str], ...] = field(default=())
|
||||||
|
verify: tuple[Candidate, ...] = field(default=()) # the candidates of ``family`` (all of them when empty)
|
||||||
|
sizes: tuple[tuple[str, int, int], ...] = field(default=()) # (path, characters, lines) of a pin's candidate files
|
||||||
|
|
||||||
|
@property
|
||||||
|
def paths(self) -> list[str]:
|
||||||
|
return sorted({c[0] for c in self.candidates})
|
||||||
|
|
||||||
|
def index_row(self) -> dict[str, Any]:
|
||||||
|
return {"source": self.source, "ref": self.ref, "side": self.side, "repo": self.repo, "pin": self.pin,
|
||||||
|
"family": self.family, "candidates": [list(c) for c in self.candidates]} # fmt: skip
|
||||||
|
|
||||||
|
|
||||||
|
def _opaque(*parts: str) -> str:
|
||||||
|
return "h-" + hashlib.sha256("\x00".join(parts).encode("utf-8")).hexdigest()[:12]
|
||||||
|
|
||||||
|
|
||||||
|
def blob_sha1(text: str) -> str:
|
||||||
|
data = text.encode("utf-8")
|
||||||
|
return hashlib.sha1(b"blob %d\x00" % len(data) + data).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def declaration_line(lines: Sequence[str] | None, path: str, function: str) -> int:
|
||||||
|
"""1-based line of the first declaration of ``function`` in ``lines``; 1 for ``<global>`` or when not declared."""
|
||||||
|
pattern = DECLARATION.get(detect_language(Path(path)) or "")
|
||||||
|
if not lines or pattern is None or function == GLOBAL:
|
||||||
|
return 1
|
||||||
|
return next((i + 1 for i, line in enumerate(lines) if _declared_name(pattern, line) == function), 1)
|
||||||
|
|
||||||
|
|
||||||
|
def _read_labels(labels: Path) -> list[dict[str, Any]]:
|
||||||
|
return [json.loads(line) for line in labels.read_text(encoding="utf-8").splitlines() if line.strip()]
|
||||||
|
|
||||||
|
|
||||||
|
def pair_units(labels: Path, catalog: Path) -> list[Unit]:
|
||||||
|
"""Both sides of every labelled pair (pin units), each with its labelled candidates of every family; ``family`` is
|
||||||
|
the pair's verify family when it has one."""
|
||||||
|
from ..pairs import load_pair_catalog
|
||||||
|
|
||||||
|
wanted: dict[str, dict[str, set[str]]] = {}
|
||||||
|
for row in _read_labels(labels):
|
||||||
|
if row["source"] == "pairs" and row["unit"] == "pin":
|
||||||
|
wanted.setdefault(row["source_ref"], {}).setdefault(row["family"], set()).add(row["candidate"])
|
||||||
|
cases = {case.name: case for case in load_pair_catalog(catalog)}
|
||||||
|
out: list[Unit] = []
|
||||||
|
for name in sorted(wanted):
|
||||||
|
case = cases[name]
|
||||||
|
families = wanted[name]
|
||||||
|
verify = sorted(f for f in families if f in OPERATIONS)
|
||||||
|
for side in ("vuln", "fixed"):
|
||||||
|
excerpt = case.vuln_file if side == "vuln" else case.fixed_file
|
||||||
|
if not excerpt.is_file():
|
||||||
|
raise ValueError(f"{name}: the {side} excerpt is not materialised ({excerpt}); fetch pointer pairs first")
|
||||||
|
texts = {case.relpath: excerpt.read_text(encoding="utf-8", errors="replace")}
|
||||||
|
for relpath, vuln_doc, fixed_doc in case.context_files:
|
||||||
|
texts[relpath] = (vuln_doc if side == "vuln" else fixed_doc).read_text(encoding="utf-8", errors="replace")
|
||||||
|
lines = {path: text.splitlines() for path, text in texts.items()}
|
||||||
|
|
||||||
|
def located(names: Iterable[str], lines: Mapping[str, list[str]] = lines) -> tuple[Candidate, ...]:
|
||||||
|
return tuple(sorted({(p, fn, declaration_line(lines.get(p), p, fn)) for c in names for p, _, fn in [c.partition("::")]}))
|
||||||
|
|
||||||
|
role = "vulnerable" if side == "vuln" else "fixed"
|
||||||
|
out.append(Unit(
|
||||||
|
_opaque("pairs", name, side), "pairs", name, role, case.repo or f"pairs/{case.slice}/{name}",
|
||||||
|
blob_sha1(texts[case.relpath]), verify[0] if verify else "", located(set().union(*families.values())),
|
||||||
|
tuple(sorted(texts.items())), located(families[verify[0]]) if verify else (),
|
||||||
|
)) # fmt: skip
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def population_units(labels: Path, cache: Path) -> list[Unit]:
|
||||||
|
"""One unit per (repository, pin, family) of the population, recipe and adjudication pin labels, candidates with
|
||||||
|
their declaration line at that pin (read from the case clone or the recipe checkout). ``family`` is set for the
|
||||||
|
development cases' verify families (:data:`VERIFY_SOURCES`, and v1 adjudications), else ``""``."""
|
||||||
|
groups: dict[tuple[str, str, str], dict[str, Any]] = {}
|
||||||
|
for row in _read_labels(labels):
|
||||||
|
if row["unit"] != "pin" or row["source"] not in POPULATION_SOURCES:
|
||||||
|
continue
|
||||||
|
key = (row["repo"], row["pin"], row["family"])
|
||||||
|
group = groups.setdefault(key, {"sources": set(), "refs": set(), "side": row["pin_role"], "candidates": set()})
|
||||||
|
group["sources"].add(row["split"] if row["source"] == "adjudications" else row["source"])
|
||||||
|
group["refs"].add(row["source_ref"])
|
||||||
|
group["candidates"].add(row["candidate"])
|
||||||
|
case_ids = {r: ref for (r, _, _), g in groups.items() for ref in g["refs"] if ":" not in ref and "#" not in ref}
|
||||||
|
out: list[Unit] = []
|
||||||
|
for (repo, pin, family), group in sorted(groups.items()):
|
||||||
|
source = sorted(group["sources"])[0]
|
||||||
|
ref = case_ids[repo] if source.startswith("population") and repo in case_ids else str(sorted(group["refs"])[0])
|
||||||
|
reader = _reader(cache, source, ref, pin)
|
||||||
|
texts = {p: reader(p) for p in {c.partition("::")[0] for c in group["candidates"]}}
|
||||||
|
candidates = sorted({(p, fn, declaration_line(texts[p], p, fn)) for c in group["candidates"] for p, _, fn in [c.partition("::")]})
|
||||||
|
sizes = tuple((p, sum(len(x) + 1 for x in t), len(t)) for p, t in sorted(texts.items()) if t is not None)
|
||||||
|
verify = family if family in OPERATIONS and source in VERIFY_SOURCES else ""
|
||||||
|
out.append(Unit(_opaque(repo, pin, family), source, ref, group["side"], repo, pin, verify, tuple(candidates), sizes=sizes))
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def _reader(cache: Path, source: str, ref: str, pin: str) -> Any:
|
||||||
|
"""Lines of a path at the pin: the case clone (populations), else the recipe checkout (dev-php)."""
|
||||||
|
from ..learn.labels import Clone, LabelSourceError
|
||||||
|
|
||||||
|
if source == "dev-php":
|
||||||
|
root = cache / "repos" / ref.split(":")[0] / pin[:12]
|
||||||
|
return lambda path: (root / path).read_text(encoding="utf-8", errors="replace").splitlines() if (root / path).is_file() else None
|
||||||
|
try:
|
||||||
|
clone = Clone(cache / "independent" / ref)
|
||||||
|
except LabelSourceError:
|
||||||
|
return lambda path: None
|
||||||
|
return lambda path: clone.lines(pin, path)
|
||||||
|
|
||||||
|
|
||||||
|
# --- manifests -------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
def _git_workspace(unit: Unit) -> dict[str, Any]:
|
||||||
|
doc = _doc("Workspace", _ax_name(unit.name, "pin"), {"git": [{"name": REPO, "repo": unit.repo, "dir": REPO, "depth": 1}]}, ATESPACE)
|
||||||
|
doc["metadata"]["annotations"] = {GIT_COMMITS_ANNOTATION: f"{REPO}={unit.pin}"}
|
||||||
|
return doc
|
||||||
|
|
||||||
|
|
||||||
|
def _files_workspace(name: str, files: Mapping[str, str]) -> dict[str, Any]:
|
||||||
|
return _doc("Workspace", name, {"files": [{"path": k, "content": v} for k, v in sorted(files.items())]}, ATESPACE)
|
||||||
|
|
||||||
|
|
||||||
|
def _verify_docs(unit: Unit, templates: Mapping[str, Task], usd_per_hunt: float) -> tuple[list[dict], list[dict], list[dict]]:
|
||||||
|
"""(Workspaces, Tasks, Run entries) of one verify unit."""
|
||||||
|
asked = list(unit.verify or unit.candidates)
|
||||||
|
candidates = {"family": unit.family, "candidates": [list(c) for c in asked]}
|
||||||
|
hunts = max(len(units_of(asked)), 1)
|
||||||
|
budget = {"usd": math.floor(hunts * usd_per_hunt * 1000) / 1000, "calls": hunts * CALLS_PER_HUNT}
|
||||||
|
on_repo = {"OUSAST_WORKSPACE_DIR": f"{CASE_PATH}/{REPO}"}
|
||||||
|
workspaces: list[dict] = []
|
||||||
|
tasks: list[dict] = []
|
||||||
|
entries: list[dict] = []
|
||||||
|
if unit.files:
|
||||||
|
files = {f"{REPO}/{path}": text for path, text in unit.files} | {"inputs/candidates.json": _json(candidates)}
|
||||||
|
workspace = _files_workspace(_ax_name(unit.name, "side"), files)
|
||||||
|
workspaces.append(workspace)
|
||||||
|
bindings = [(workspace["metadata"]["name"], CASE_PATH)]
|
||||||
|
inputs = f"{CASE_PATH}/inputs/candidates.json"
|
||||||
|
else:
|
||||||
|
pinned = _git_workspace(unit)
|
||||||
|
functions = [{"path": p, "function": fn, "line": ln} for p, fn, ln in asked]
|
||||||
|
files_doc = _files_workspace(
|
||||||
|
_ax_name(unit.name, "inputs"), {"candidates.json": _json(candidates), "functions.json": _json(functions)}
|
||||||
|
)
|
||||||
|
workspaces += [pinned, files_doc]
|
||||||
|
bindings = [(pinned["metadata"]["name"], CASE_PATH), (files_doc["metadata"]["name"], INPUTS_PATH)]
|
||||||
|
inputs = f"{INPUTS_PATH}/candidates.json"
|
||||||
|
facts_env = {**on_repo, "OUSAST_INPUT_CANDIDATES": f"{INPUTS_PATH}/functions.json"}
|
||||||
|
tasks.append(_task(templates["repo-facts"], f"repo-facts-{unit.name}", facts_env, bindings))
|
||||||
|
entries.append({"name": f"{unit.name}-facts", "task": f"repo-facts-{unit.name}", "outputs": ["facts.json", "summary.json"],
|
||||||
|
"budget": {"usd": 0, "calls": 0}, "serialize": "repo-facts"}) # fmt: skip
|
||||||
|
for label in ("a", "b"):
|
||||||
|
env = {**on_repo, "OUSAST_INPUT_CANDIDATES": inputs, "OUSAST_PASS": label}
|
||||||
|
tasks.append(_task(templates["verify"], f"verify-{label}-{unit.name}", env, bindings))
|
||||||
|
entry: dict[str, Any] = {"name": f"{unit.name}-v{label}", "task": f"verify-{label}-{unit.name}",
|
||||||
|
"outputs": ["units.jsonl", "summary.json"], "budget": dict(budget)} # fmt: skip
|
||||||
|
if not unit.files:
|
||||||
|
entry["inputs"] = {"facts": f"{unit.name}-facts/facts.json"}
|
||||||
|
entries.append(entry)
|
||||||
|
tasks.append(
|
||||||
|
_task(templates["agree"], f"agree-{unit.name}", {"OUSAST_INPUT_CANDIDATES": inputs}, bindings[-1:] if not unit.files else bindings)
|
||||||
|
)
|
||||||
|
entries.append({
|
||||||
|
"name": f"{unit.name}-agree", "task": f"agree-{unit.name}",
|
||||||
|
"inputs": {"pass_a": f"{unit.name}-va/units.jsonl", "pass_b": f"{unit.name}-vb/units.jsonl"},
|
||||||
|
"outputs": ["agreed.json", "disputed.json", "summary.json"], "budget": {"usd": 0, "calls": 0},
|
||||||
|
}) # fmt: skip
|
||||||
|
return workspaces, tasks, entries
|
||||||
|
|
||||||
|
|
||||||
|
def _roles_estimate(sizes: Iterable[tuple[int, int]]) -> tuple[float, int]:
|
||||||
|
"""(usd, chunks) of classifying files of ``(characters, lines)``: input at ~3.5 characters a token plus the
|
||||||
|
prompt, a generous output."""
|
||||||
|
usd, chunks = 0.0, 0
|
||||||
|
for characters, count in sizes:
|
||||||
|
lines = max(count, 1)
|
||||||
|
n = math.ceil(lines / CHUNK_LINES)
|
||||||
|
tokens_in = (characters + 8 * lines) / 3.5 + 400 * n
|
||||||
|
usd += tokens_in * PRICES["input_per_m"] / 1e6 + n * ROLES_OUTPUT_TOKENS * PRICES["output_per_m"] / 1e6
|
||||||
|
chunks += n
|
||||||
|
return usd, chunks
|
||||||
|
|
||||||
|
|
||||||
|
def _kind(unit: Unit) -> str:
|
||||||
|
return "excerpt" if unit.files else "repository"
|
||||||
|
|
||||||
|
|
||||||
|
def _inline(unit: Unit, *, roles: bool = False) -> int:
|
||||||
|
"""Bytes of the unit's files a Workspace would carry inline (roles: its candidate files only)."""
|
||||||
|
return sum(len(text.encode("utf-8")) for path, text in unit.files if not roles or path in unit.paths)
|
||||||
|
|
||||||
|
|
||||||
|
def oversized(unit: Unit) -> str | None:
|
||||||
|
"""Why a unit cannot run on ax, or None: its files exceed :data:`MAX_INLINE_BYTES`."""
|
||||||
|
return f"excerpt {_inline(unit)} bytes over the {MAX_INLINE_BYTES}-byte inline limit" if _inline(unit) > MAX_INLINE_BYTES else None
|
||||||
|
|
||||||
|
|
||||||
|
def _roles_groups(units: Sequence[Unit]) -> list[list[Unit]]:
|
||||||
|
groups: list[list[Unit]] = [[]]
|
||||||
|
size = 0
|
||||||
|
for unit in units:
|
||||||
|
weight = _inline(unit, roles=True)
|
||||||
|
if groups[-1] and (len(groups[-1]) >= ROLES_GROUP_FILES or size + weight > MAX_INLINE_BYTES):
|
||||||
|
groups.append([])
|
||||||
|
size = 0
|
||||||
|
groups[-1].append(unit)
|
||||||
|
size += weight
|
||||||
|
return [g for g in groups if g]
|
||||||
|
|
||||||
|
|
||||||
|
def render_harvest(
|
||||||
|
units: Sequence[Unit], templates: Mapping[str, Task], name: str, command: str, *, ceiling: float = 10.0
|
||||||
|
) -> dict[str, str]:
|
||||||
|
"""Relative path under the plane root -> file text: both Runs, their Workspaces and Tasks, and ``units.json``.
|
||||||
|
A population file whose size is unknown is estimated at :data:`UNKNOWN_SIZE`."""
|
||||||
|
header = f"# generated by `{command}`; do not edit, regenerate.\n"
|
||||||
|
out: dict[str, str] = {}
|
||||||
|
verify_units = [u for u in units if u.family and oversized(u) is None]
|
||||||
|
hunts = sum(max(len(units_of(list(u.verify or u.candidates))), 1) for u in verify_units)
|
||||||
|
wanted = 2 * sum(max(len(units_of(list(u.verify or u.candidates))), 1) * USD_PER_HUNT[_kind(u)] for u in verify_units) # passes a, b
|
||||||
|
scale = min(1.0, ceiling * 0.98 / wanted) if wanted else 1.0
|
||||||
|
workspaces: list[dict] = []
|
||||||
|
tasks: list[dict] = []
|
||||||
|
entries: list[dict] = []
|
||||||
|
for unit in verify_units:
|
||||||
|
w, t, e = _verify_docs(unit, templates, USD_PER_HUNT[_kind(unit)] * scale)
|
||||||
|
workspaces += w
|
||||||
|
tasks += t
|
||||||
|
entries += e
|
||||||
|
out.update(_run_files(header, f"{name}-verify", workspaces, tasks, entries, f"{len(verify_units)} units, {hunts} hunts per pass"))
|
||||||
|
emitted = {w["metadata"]["name"] for w in workspaces} # a pin Workspace both Runs bind is written once
|
||||||
|
workspaces, tasks, entries, estimates = [], [], [], []
|
||||||
|
for group in _roles_groups([u for u in units if u.files and _inline(u, roles=True) <= MAX_INLINE_BYTES]):
|
||||||
|
files = {f"{REPO}/{u.name}/{p}": t for u in group for p, t in u.files if p in u.paths}
|
||||||
|
listing = sorted(f.removeprefix(f"{REPO}/") for f in files)
|
||||||
|
workspace = _files_workspace(_ax_name(name, "roles", group[0].name), files | {"inputs/files.json": _json(listing)})
|
||||||
|
workspaces.append(workspace)
|
||||||
|
estimates.append(_roles_estimate((len(text), len(text.splitlines())) for text in files.values()))
|
||||||
|
bound = [(workspace["metadata"]["name"], CASE_PATH)]
|
||||||
|
env = {"OUSAST_WORKSPACE_DIR": f"{CASE_PATH}/{REPO}", "OUSAST_INPUT_FILES": f"{CASE_PATH}/inputs/files.json"}
|
||||||
|
tasks.append(_task(templates["roles"], f"roles-{group[0].name}", env, bound))
|
||||||
|
entries.append(
|
||||||
|
{"name": f"{group[0].name}-roles", "task": f"roles-{group[0].name}", "outputs": ["roles.json", "units.jsonl", "summary.json"]}
|
||||||
|
)
|
||||||
|
seen: set[tuple[str, str]] = set()
|
||||||
|
for unit in (u for u in units if not u.files):
|
||||||
|
if (unit.repo, unit.pin) in seen:
|
||||||
|
continue
|
||||||
|
seen.add((unit.repo, unit.pin))
|
||||||
|
same = [u for u in units if not u.files and (u.repo, u.pin) == (unit.repo, unit.pin)]
|
||||||
|
paths = sorted({p for u in same for p in u.paths})
|
||||||
|
known = {p: (chars, lines) for u in same for p, chars, lines in u.sizes}
|
||||||
|
pinned = _git_workspace(unit)
|
||||||
|
files_doc = _files_workspace(_ax_name(unit.name, "roles-in"), {"files.json": _json(paths)})
|
||||||
|
workspaces += [w for w in (pinned, files_doc) if w["metadata"]["name"] not in emitted]
|
||||||
|
estimates.append(_roles_estimate(known.get(p, UNKNOWN_SIZE) for p in paths))
|
||||||
|
bound = [(pinned["metadata"]["name"], CASE_PATH), (files_doc["metadata"]["name"], INPUTS_PATH)]
|
||||||
|
env = {"OUSAST_WORKSPACE_DIR": f"{CASE_PATH}/{REPO}", "OUSAST_INPUT_FILES": f"{INPUTS_PATH}/files.json"}
|
||||||
|
tasks.append(_task(templates["roles"], f"roles-{unit.name}", env, bound))
|
||||||
|
entries.append(
|
||||||
|
{"name": f"{unit.name}-roles", "task": f"roles-{unit.name}", "outputs": ["roles.json", "units.jsonl", "summary.json"]}
|
||||||
|
)
|
||||||
|
wanted = sum(usd for usd, _ in estimates) * ROLES_HEADROOM
|
||||||
|
scale = min(1.0, ceiling * 0.98 / wanted) if wanted else 1.0
|
||||||
|
for entry, (usd, chunks) in zip(entries, estimates, strict=True):
|
||||||
|
entry["budget"] = {"usd": max(math.floor(usd * ROLES_HEADROOM * scale * 1000) / 1000, 0.001), "calls": chunks * 2 + 2}
|
||||||
|
out.update(_run_files(header, f"{name}-roles", workspaces, tasks, entries, f"{len(entries)} roles tasks"))
|
||||||
|
index = {u.name: u.index_row() | ({"skipped": oversized(u)} if oversized(u) else {}) for u in units}
|
||||||
|
out["units.json"] = json.dumps(index, indent=1, sort_keys=True) + "\n"
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def _run_files(header: str, run: str, workspaces: list[dict], tasks: list[dict], entries: list[dict], note: str) -> dict[str, str]:
|
||||||
|
total = sum(float(e["budget"]["usd"]) for e in entries)
|
||||||
|
metadata = {"name": run, "annotations": {"openultrasast.io/population": "harvest", "openultrasast.io/split": "learn"}}
|
||||||
|
doc = {"apiVersion": RUN_API_VERSION, "kind": "Run", "metadata": metadata, "spec": {"tasks": entries}}
|
||||||
|
files = {f"workspaces/{run}.yaml": _dump(header, workspaces), f"tasks/{run}.yaml": _dump(header, tasks)}
|
||||||
|
files[f"runs/{run}.yaml"] = _dump(header + f"# {note}; usd ceiling {total:.3f}.\n", [doc])
|
||||||
|
return files
|
||||||
|
|
||||||
|
|
||||||
|
def write_harvest(
|
||||||
|
labels: Path, plane: Path, *, name: str, command: str, catalog: Path, cache: Path, templates: Path, ceiling: float = 10.0
|
||||||
|
) -> dict[str, str]:
|
||||||
|
"""Build the units, render, write under ``plane`` (with the Model manifests copied beside); returns the rendered
|
||||||
|
files."""
|
||||||
|
from .manifests import load_manifests
|
||||||
|
|
||||||
|
units = pair_units(labels, catalog) + population_units(labels, cache)
|
||||||
|
loaded = load_manifests([templates / "tasks" / f"{n}.yaml" for n in ("repo-facts", "verify", "agree", "roles")]).tasks
|
||||||
|
files = render_harvest(units, loaded, name, command, ceiling=ceiling)
|
||||||
|
for path in sorted((templates / "models").glob("*.yaml")):
|
||||||
|
files[f"models/{path.name}"] = path.read_text(encoding="utf-8")
|
||||||
|
for relative, text in files.items():
|
||||||
|
target = plane / relative
|
||||||
|
target.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
target.write_text(text, encoding="utf-8")
|
||||||
|
yaml.safe_load_all(files[f"runs/{name}-verify.yaml"]) # parse check
|
||||||
|
return files
|
||||||
@@ -156,6 +156,18 @@ def test_roles_feature_part(tmp_path: Path) -> None:
|
|||||||
assert [f.name for f in functions_of("a.php", lines, "php")][:2] == ["run_sql", "fetch_rows"]
|
assert [f.name for f in functions_of("a.php", lines, "php")][:2] == ["run_sql", "fetch_rows"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_a_language_without_declarations_is_none_not_failed() -> None:
|
||||||
|
"""C has no declaration pattern: the span and wrapper roles cannot run there (no coverage), which is not a broken
|
||||||
|
instrument (harvest 2026-10-01: every memory pair read as `failed`)."""
|
||||||
|
from openultrasast.learn.features import source_part
|
||||||
|
from openultrasast.learn.roles import RoleSet
|
||||||
|
|
||||||
|
lines = ["int f(char *s) {", " return strcpy(buf, s);", "}"]
|
||||||
|
assert source_part(lines, "c", "f").state == "none"
|
||||||
|
assert roles_part(None, RoleSet(sources=("inferred_wrapper",)), "c").state == "none"
|
||||||
|
assert source_part(["def g():", " pass"], "python", "missing").state == "failed"
|
||||||
|
|
||||||
|
|
||||||
def test_build_for_scan_records_the_roles_instrument(tmp_path: Path) -> None:
|
def test_build_for_scan_records_the_roles_instrument(tmp_path: Path) -> None:
|
||||||
from openultrasast.findings import quick_scan_findings
|
from openultrasast.findings import quick_scan_findings
|
||||||
from openultrasast.preprocess import preprocess_repository
|
from openultrasast.preprocess import preprocess_repository
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
"""The decision engine's harvest Runs (learned-decision-engine task 5): `ousast plane harvest`'s generator."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from openultrasast.plane import reconciler
|
||||||
|
from openultrasast.plane.harvest import MAX_INLINE_BYTES, Unit, blob_sha1, declaration_line, render_harvest
|
||||||
|
from openultrasast.plane.manifests import load_manifests
|
||||||
|
|
||||||
|
PLANE = Path("plane")
|
||||||
|
PIN = "0123456789abcdef0123456789abcdef01234567"
|
||||||
|
|
||||||
|
|
||||||
|
def _templates() -> dict:
|
||||||
|
return load_manifests([PLANE / "tasks" / f"{n}.yaml" for n in ("repo-facts", "verify", "agree", "roles")]).tasks
|
||||||
|
|
||||||
|
|
||||||
|
def _units() -> list[Unit]:
|
||||||
|
code = "import os\n\ndef run(cmd):\n os.system(cmd)\n"
|
||||||
|
excerpt = Unit("h-aaaaaaaaaaaa", "pairs", "x-cwe-078-os-system", "vulnerable", "pairs/github/x", blob_sha1(code), "injection",
|
||||||
|
(("app.py", "run", 3),), (("app.py", code),)) # fmt: skip
|
||||||
|
roles_only = Unit("h-bbbbbbbbbbbb", "pairs", "y-cwe-416", "fixed", "pairs/vfc/y", blob_sha1("int f(){}\n"), "",
|
||||||
|
(("f.c", "f", 1),), (("f.c", "int f(){}\n"),)) # fmt: skip
|
||||||
|
big = "x = 1\n" * (MAX_INLINE_BYTES // 6 + 10)
|
||||||
|
oversized = Unit(
|
||||||
|
"h-cccccccccccc",
|
||||||
|
"pairs",
|
||||||
|
"z",
|
||||||
|
"vulnerable",
|
||||||
|
"pairs/github/z",
|
||||||
|
blob_sha1(big),
|
||||||
|
"injection",
|
||||||
|
(("big.py", GLOBAL_, 1),),
|
||||||
|
(("big.py", big),),
|
||||||
|
)
|
||||||
|
repo = Unit("h-dddddddddddd", "population-v1", "case", "vulnerable", "https://github.com/o/r", PIN, "injection",
|
||||||
|
(("a.py", "q", 10), ("b.py", "r", 20)), sizes=(("a.py", 4000, 100), ("b.py", 8000, 900))) # fmt: skip
|
||||||
|
return [excerpt, roles_only, oversized, repo]
|
||||||
|
|
||||||
|
|
||||||
|
GLOBAL_ = "<global>"
|
||||||
|
|
||||||
|
|
||||||
|
def _render(tmp_path: Path, ceiling: float = 10.0) -> tuple[dict[str, str], Path]:
|
||||||
|
files = render_harvest(_units(), _templates(), "hv", "test", ceiling=ceiling)
|
||||||
|
for rel, text in files.items():
|
||||||
|
(tmp_path / rel).parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
(tmp_path / rel).write_text(text)
|
||||||
|
(tmp_path / "models").mkdir()
|
||||||
|
(tmp_path / "models" / "deepseek-flash.yaml").write_text((PLANE / "models" / "deepseek-flash.yaml").read_text())
|
||||||
|
return files, tmp_path
|
||||||
|
|
||||||
|
|
||||||
|
def test_verify_run_shape_and_ceiling(tmp_path: Path) -> None:
|
||||||
|
files, root = _render(tmp_path, ceiling=0.05)
|
||||||
|
run, manifests = reconciler.load_run(root / "runs" / "hv-verify.yaml")
|
||||||
|
names = [t.name for t in run.tasks]
|
||||||
|
assert names == [
|
||||||
|
"h-aaaaaaaaaaaa-va", "h-aaaaaaaaaaaa-vb", "h-aaaaaaaaaaaa-agree",
|
||||||
|
"h-dddddddddddd-facts", "h-dddddddddddd-va", "h-dddddddddddd-vb", "h-dddddddddddd-agree",
|
||||||
|
] # fmt: skip
|
||||||
|
assert sum(float(t.budget.usd) for t in run.tasks) <= 0.05 # scaled down to the ceiling
|
||||||
|
assert all(float(t.budget.usd) == 0 for t in run.tasks if t.name.endswith(("-agree", "-facts")))
|
||||||
|
excerpt = manifests.tasks["verify-a-h-aaaaaaaaaaaa"]
|
||||||
|
env = {e.name: e.value for e in excerpt.env}
|
||||||
|
assert env["OUSAST_WORKSPACE_DIR"].endswith("/repo") and "/inputs/" in env["OUSAST_INPUT_CANDIDATES"]
|
||||||
|
workspace = manifests.workspaces["h-aaaaaaaaaaaa-side"]
|
||||||
|
paths = {f.path for f in workspace.files}
|
||||||
|
assert paths == {"repo/app.py", "inputs/candidates.json"} # candidates outside the hunt's root
|
||||||
|
assert "cwe" not in yaml.safe_dump([workspace.metadata.name, *paths]) # the pair's name never reaches the sandbox
|
||||||
|
units = json.loads(files["units.json"])
|
||||||
|
assert "skipped" in units["h-cccccccccccc"] and "skipped" not in units["h-aaaaaaaaaaaa"]
|
||||||
|
agree = {e.name: e.value for e in manifests.tasks["agree-h-dddddddddddd"].env}
|
||||||
|
assert "OUSAST_INPUT_SITES" not in agree # no declared sites: no site_match is computed
|
||||||
|
|
||||||
|
|
||||||
|
def test_roles_run_groups_excerpts_and_pins(tmp_path: Path) -> None:
|
||||||
|
_, root = _render(tmp_path)
|
||||||
|
run, manifests = reconciler.load_run(root / "runs" / "hv-roles.yaml")
|
||||||
|
assert len(run.tasks) == 2 and sum(float(t.budget.usd) for t in run.tasks) <= 10.0
|
||||||
|
grouped = next(w for w in manifests.workspaces.values() if w.metadata.name.startswith("hv-roles"))
|
||||||
|
listing = json.loads(next(f.content for f in grouped.files if f.path == "inputs/files.json"))
|
||||||
|
assert listing == ["h-aaaaaaaaaaaa/app.py", "h-bbbbbbbbbbbb/f.c"] # the oversized excerpt is left out
|
||||||
|
assert sum(len(f.content) for f in grouped.files) <= MAX_INLINE_BYTES + 200
|
||||||
|
pin = manifests.tasks["roles-h-dddddddddddd"]
|
||||||
|
assert {e.name: e.value for e in pin.env}["OUSAST_INPUT_FILES"].endswith("/files.json")
|
||||||
|
|
||||||
|
|
||||||
|
def test_blob_sha1_is_gits_and_declaration_lines() -> None:
|
||||||
|
text = "def a():\n pass\n\ndef b():\n pass\n"
|
||||||
|
done = subprocess.run(["git", "hash-object", "--stdin"], input=text, capture_output=True, text=True, check=True)
|
||||||
|
assert blob_sha1(text) == done.stdout.strip()
|
||||||
|
lines = text.splitlines()
|
||||||
|
assert declaration_line(lines, "m.py", "b") == 4
|
||||||
|
assert declaration_line(lines, "m.py", "missing") == 1 and declaration_line(None, "m.py", "a") == 1
|
||||||
Reference in New Issue
Block a user