mirror of
https://github.com/usestrix/strix.git
synced 2026-10-01 02:03:55 +00:00
129 lines
3.7 KiB
Python
129 lines
3.7 KiB
Python
from __future__ import annotations
|
|
|
|
import inspect
|
|
import subprocess
|
|
from typing import TYPE_CHECKING
|
|
|
|
import pytest
|
|
|
|
|
|
if TYPE_CHECKING:
|
|
from pathlib import Path
|
|
from strix.fix import (
|
|
CandidateLocation,
|
|
CommandSpec,
|
|
FixCandidateV1,
|
|
FixEdit,
|
|
FixPreparationRequestV1,
|
|
ReproductionSpec,
|
|
SourceIdentity,
|
|
SourceIdentityKind,
|
|
)
|
|
from strix.fix import runtime as fix_runtime
|
|
|
|
|
|
def _git(workspace: Path, *args: str) -> str:
|
|
result = subprocess.run( # noqa: S603
|
|
["/usr/bin/git", *args],
|
|
cwd=workspace,
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
return result.stdout.strip()
|
|
|
|
|
|
def _workspace(tmp_path: Path) -> tuple[Path, str]:
|
|
workspace = tmp_path / "repository"
|
|
workspace.mkdir()
|
|
_git(workspace, "init")
|
|
(workspace / "app.py").write_text("def result():\n return 'unsafe'\n", encoding="utf-8")
|
|
_git(workspace, "add", "app.py")
|
|
_git(
|
|
workspace,
|
|
"-c",
|
|
"user.name=Strix Test",
|
|
"-c",
|
|
"user.email=strix@example.com",
|
|
"commit",
|
|
"-m",
|
|
"fixture",
|
|
)
|
|
return workspace, _git(workspace, "rev-parse", "HEAD")
|
|
|
|
|
|
def _request(commit: str) -> FixPreparationRequestV1:
|
|
candidate = FixCandidateV1(
|
|
source_identity=SourceIdentity(
|
|
kind=SourceIdentityKind.COMMIT,
|
|
value=commit,
|
|
),
|
|
security_invariant="The function must return the safe value.",
|
|
finding_locations=[
|
|
CandidateLocation(
|
|
file="app.py",
|
|
start_line=2,
|
|
end_line=2,
|
|
snippet=" return 'unsafe'",
|
|
)
|
|
],
|
|
draft_edits=[
|
|
FixEdit(
|
|
file="app.py",
|
|
start_line=2,
|
|
end_line=2,
|
|
before=" return 'unsafe'",
|
|
after=" return 'safe'",
|
|
)
|
|
],
|
|
reproduction=ReproductionSpec(
|
|
instructions="Confirm that the function returns the safe value.",
|
|
command=CommandSpec(
|
|
name="security reproduction",
|
|
argv=[
|
|
"/usr/bin/python3",
|
|
"-c",
|
|
"from app import result; assert result() == 'safe'",
|
|
],
|
|
),
|
|
),
|
|
)
|
|
return FixPreparationRequestV1(
|
|
scan_id="scan-1",
|
|
finding_id="finding-1",
|
|
candidate=candidate,
|
|
checks=[
|
|
CommandSpec(
|
|
name="repository check",
|
|
argv=["/usr/bin/python3", "-m", "compileall", "app.py"],
|
|
)
|
|
],
|
|
)
|
|
|
|
|
|
def test_run_fix_preparation_requires_sandbox() -> None:
|
|
parameter = inspect.signature(fix_runtime.run_fix_preparation).parameters["sandbox_session"]
|
|
assert parameter.default is inspect.Parameter.empty
|
|
|
|
|
|
def test_role_budgets_default_and_legacy_override() -> None:
|
|
request = _request("a" * 40)
|
|
assert (request.repair_turn_limit, request.review_turn_limit) == (300, 250)
|
|
request.max_agent_turns = 100
|
|
assert (request.repair_turn_limit, request.review_turn_limit) == (100, 100)
|
|
request.max_repair_turns = 180
|
|
request.max_review_turns = 80
|
|
assert (request.repair_turn_limit, request.review_turn_limit) == (180, 80)
|
|
restored = FixPreparationRequestV1.model_validate_json(request.model_dump_json())
|
|
assert (restored.repair_turn_limit, restored.review_turn_limit) == (180, 80)
|
|
|
|
|
|
def test_runtime_rejects_repository_metadata_paths(tmp_path: Path) -> None:
|
|
workspace = tmp_path / "repository"
|
|
(workspace / ".git").mkdir(parents=True)
|
|
environment = fix_runtime._RuntimeEnvironment(
|
|
workspace=workspace,
|
|
)
|
|
|
|
with pytest.raises(ValueError, match="repository source"):
|
|
environment.resolve(".git/config")
|