mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 19:59:26 +00:00
feat(three-stage-scan): add language recipes with inconclusive fallback
This commit is contained in:
@@ -1,14 +1,17 @@
|
||||
"""Isolated regression snippets and verdicts."""
|
||||
|
||||
from .candidate import INCONCLUSIVE, SAFETY_REJECTED, RegressionRunner, RegressionVerdict, select_candidates
|
||||
from .candidate import INCONCLUSIVE, MISSING_RECIPE, SAFETY_REJECTED, RegressionRunner, RegressionVerdict, select_candidates
|
||||
from .recipes import recipe_for
|
||||
from .safety import UnsafeSnippetError, check_snippet_safety
|
||||
|
||||
__all__ = [
|
||||
"INCONCLUSIVE",
|
||||
"MISSING_RECIPE",
|
||||
"SAFETY_REJECTED",
|
||||
"RegressionRunner",
|
||||
"RegressionVerdict",
|
||||
"UnsafeSnippetError",
|
||||
"check_snippet_safety",
|
||||
"recipe_for",
|
||||
"select_candidates",
|
||||
]
|
||||
|
||||
@@ -4,15 +4,19 @@ from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping, Sequence
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
from ..complexity.ledger import hotspot_key, select_forced_candidates
|
||||
from ..complexity.map import Hotspot
|
||||
from ..config import SandboxConfig
|
||||
from ..findings import StaticFinding
|
||||
from ..sandbox import SandboxJob, SandboxResult, SandboxRunner
|
||||
from .recipes import recipe_for
|
||||
from .safety import UnsafeSnippetError, check_snippet_safety
|
||||
|
||||
INCONCLUSIVE = "inconclusive"
|
||||
SAFETY_REJECTED = "safety_rejected"
|
||||
MISSING_RECIPE = "missing_recipe"
|
||||
TRIGGERABLE = "triggerable"
|
||||
NOT_TRIGGERABLE = "not_triggerable"
|
||||
|
||||
@@ -81,7 +85,23 @@ class RegressionRunner:
|
||||
def __init__(self, sandbox: SandboxRunner) -> None:
|
||||
self._sandbox = sandbox
|
||||
|
||||
def run_snippet(self, snippet: str, job: SandboxJob) -> RegressionVerdict:
|
||||
def run_recipe(
|
||||
self,
|
||||
language: str,
|
||||
snippet: str,
|
||||
image: str,
|
||||
sandbox_limits: SandboxConfig,
|
||||
*,
|
||||
repo_root: Path,
|
||||
) -> RegressionVerdict:
|
||||
job = recipe_for(language, snippet, image, sandbox_limits, repo_root=repo_root)
|
||||
if job is None:
|
||||
return RegressionVerdict(verdict=INCONCLUSIVE, reason=MISSING_RECIPE)
|
||||
return self.run_snippet(snippet, job)
|
||||
|
||||
def run_snippet(self, snippet: str, job: SandboxJob | None) -> RegressionVerdict:
|
||||
if job is None:
|
||||
return RegressionVerdict(verdict=INCONCLUSIVE, reason=MISSING_RECIPE)
|
||||
try:
|
||||
check_snippet_safety(snippet)
|
||||
except UnsafeSnippetError:
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
"""Language command recipes for isolated regression snippets."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from ..config import SandboxConfig
|
||||
from ..sandbox.runner import SCRATCH_MOUNT, WORKSPACE_MOUNT, SandboxJob
|
||||
|
||||
_PYTHON_FILE = "case.py"
|
||||
_JS_FILE = "case.js"
|
||||
_C_FILE = "case.c"
|
||||
_C_BIN = "case"
|
||||
|
||||
|
||||
def recipe_for(
|
||||
language: str,
|
||||
snippet: str,
|
||||
image: str,
|
||||
sandbox_limits: SandboxConfig,
|
||||
*,
|
||||
repo_root: Path,
|
||||
) -> SandboxJob | None:
|
||||
"""Return a sandbox job for `language`, or None when no recipe exists."""
|
||||
key = language.strip().lower()
|
||||
if key == "python":
|
||||
return _job(
|
||||
image,
|
||||
sandbox_limits,
|
||||
repo_root,
|
||||
command=("env", f"PYTHONPATH={WORKSPACE_MOUNT}", "python", f"{SCRATCH_MOUNT}/{_PYTHON_FILE}"),
|
||||
scratch_files={_PYTHON_FILE: snippet},
|
||||
)
|
||||
if key == "javascript":
|
||||
return _job(
|
||||
image,
|
||||
sandbox_limits,
|
||||
repo_root,
|
||||
command=("env", f"NODE_PATH={WORKSPACE_MOUNT}", "node", f"{SCRATCH_MOUNT}/{_JS_FILE}"),
|
||||
scratch_files={_JS_FILE: snippet},
|
||||
)
|
||||
if key == "c":
|
||||
source = f"{SCRATCH_MOUNT}/{_C_FILE}"
|
||||
binary = f"{SCRATCH_MOUNT}/{_C_BIN}"
|
||||
return _job(
|
||||
image,
|
||||
sandbox_limits,
|
||||
repo_root,
|
||||
command=("sh", "-c", f"cc {source} -o {binary} && {binary}"),
|
||||
scratch_files={_C_FILE: snippet},
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
def _job(
|
||||
image: str,
|
||||
sandbox_limits: SandboxConfig,
|
||||
repo_root: Path,
|
||||
*,
|
||||
command: tuple[str, ...],
|
||||
scratch_files: dict[str, str],
|
||||
) -> SandboxJob:
|
||||
return SandboxJob(
|
||||
image=image,
|
||||
command=command,
|
||||
repo_root=repo_root,
|
||||
scratch_files=scratch_files,
|
||||
timeout_seconds=sandbox_limits.timeout_seconds,
|
||||
memory_mb=sandbox_limits.memory_mb,
|
||||
pids_limit=sandbox_limits.pids_limit,
|
||||
)
|
||||
Reference in New Issue
Block a user