mirror of
https://github.com/usestrix/strix.git
synced 2026-10-03 02:24:24 +00:00
refactor: use one auto-fix setting and infer fix delivery
This commit is contained in:
parent
9edb2ae00c
commit
8bd7f4cbd2
6 changed files with 14 additions and 34 deletions
|
|
@ -500,22 +500,11 @@ async def run_strix_scan(
|
|||
)
|
||||
|
||||
report_state = get_global_report_state()
|
||||
auto_fix_enabled = (
|
||||
scan_config.get(
|
||||
"auto_fix_enabled",
|
||||
scan_config.get("one_click_fixes_enabled", True),
|
||||
)
|
||||
is not False
|
||||
)
|
||||
local_fix_branches_enabled = (
|
||||
scan_config.get("local_fix_branches_enabled") is True and fix_sink is None
|
||||
)
|
||||
if (
|
||||
auto_fix_enabled
|
||||
scan_config.get("auto_fix_enabled", True) is not False
|
||||
and scan_config.get("mode") != "pr_review"
|
||||
and report_state is not None
|
||||
and local_sources
|
||||
and (not interactive or local_fix_branches_enabled)
|
||||
):
|
||||
fixes = ScanFixes(
|
||||
session=sandbox_session,
|
||||
|
|
@ -527,7 +516,6 @@ async def run_strix_scan(
|
|||
report_state=report_state,
|
||||
event_sink=event_sink,
|
||||
sink=fix_sink,
|
||||
publish_local_branches=local_fix_branches_enabled,
|
||||
)
|
||||
report_state.defer_completion = True
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ class ScanFixes:
|
|||
report_state: Any,
|
||||
event_sink: Any = None,
|
||||
sink: FixSink | None = None,
|
||||
publish_local_branches: bool = False,
|
||||
) -> None:
|
||||
self.session, self.coordinator = session, coordinator
|
||||
self.scan_id, self.directory = scan_id, state_dir / "fixes"
|
||||
|
|
@ -77,7 +76,6 @@ class ScanFixes:
|
|||
if s.get("source_path")
|
||||
}
|
||||
self.hooks, self.event_sink, self.sink = hooks, event_sink, sink
|
||||
self.publish_local_branches = publish_local_branches
|
||||
self.report_state = report_state
|
||||
self.tasks: dict[str, asyncio.Task[Any]] = {}
|
||||
self.dispatches: set[asyncio.Task[Any]] = set()
|
||||
|
|
@ -152,7 +150,7 @@ class ScanFixes:
|
|||
)
|
||||
except Exception as error: # noqa: BLE001 - report launch failure to the scan
|
||||
await self._cancel_active(finding_id)
|
||||
if candidate is not None and self.publish_local_branches:
|
||||
if candidate is not None and self.sink is None:
|
||||
record = self.records.setdefault(finding_id, {})
|
||||
record.update(digest=candidate.digest(), status="stopped", reason=str(error))
|
||||
self._save()
|
||||
|
|
@ -431,7 +429,7 @@ class ScanFixes:
|
|||
await self._reconcile()
|
||||
self.closed = True
|
||||
await asyncio.gather(*self.tasks.values(), return_exceptions=True)
|
||||
if not self.publish_local_branches:
|
||||
if self.sink is not None:
|
||||
return [], []
|
||||
|
||||
branches: list[dict[str, str]] = []
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@ async def run_cli(args: Any) -> None: # noqa: PLR0915
|
|||
"scan_mode": scan_mode,
|
||||
"non_interactive": bool(getattr(args, "non_interactive", False)),
|
||||
"auto_fix_enabled": bool(args.auto_fix),
|
||||
"local_fix_branches_enabled": bool(args.auto_fix),
|
||||
"local_sources": getattr(args, "local_sources", None) or [],
|
||||
"workspace_files": getattr(args, "workspace_files", None) or [],
|
||||
"scope_mode": getattr(args, "scope_mode", "auto"),
|
||||
|
|
|
|||
|
|
@ -92,7 +92,6 @@ class GoTuiRuntime:
|
|||
"scan_mode": self.args.scan_mode,
|
||||
"non_interactive": False,
|
||||
"auto_fix_enabled": bool(self.args.auto_fix),
|
||||
"local_fix_branches_enabled": bool(self.args.auto_fix),
|
||||
"local_sources": self.args.local_sources or [],
|
||||
"workspace_files": getattr(self.args, "workspace_files", None) or [],
|
||||
"scope_mode": self.args.scope_mode,
|
||||
|
|
|
|||
|
|
@ -106,7 +106,12 @@ async def test_a_live_child_is_settled_before_sessions_close(
|
|||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
"interactive,local_branches,is_resume",
|
||||
[(False, False, False), (False, True, False), (True, True, False), (True, True, True)],
|
||||
[
|
||||
(interactive, local_branches, resume)
|
||||
for interactive in (False, True)
|
||||
for local_branches in (False, True)
|
||||
for resume in ((False, True) if interactive else (False,))
|
||||
],
|
||||
)
|
||||
async def test_assessment_publishes_before_fixes_end_and_sandbox_teardown(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
|
|
@ -135,7 +140,6 @@ async def test_assessment_publishes_before_fixes_end_and_sandbox_teardown(
|
|||
|
||||
class Fixes:
|
||||
def __init__(self, **options: Any) -> None:
|
||||
assert options["publish_local_branches"] is local_branches
|
||||
assert (options["sink"] is not None) is not local_branches
|
||||
|
||||
def start(self, *_: Any) -> None:
|
||||
|
|
@ -183,7 +187,6 @@ async def test_assessment_publishes_before_fixes_end_and_sandbox_teardown(
|
|||
scan_config={
|
||||
"targets": [],
|
||||
"scan_mode": "deep",
|
||||
"local_fix_branches_enabled": local_branches,
|
||||
},
|
||||
scan_id="scan",
|
||||
image="image",
|
||||
|
|
@ -202,17 +205,15 @@ async def test_assessment_publishes_before_fixes_end_and_sandbox_teardown(
|
|||
@pytest.mark.parametrize(
|
||||
"fix_config",
|
||||
[
|
||||
{"one_click_fixes_enabled": False},
|
||||
{"auto_fix_enabled": False},
|
||||
{"mode": "pr_review"},
|
||||
{
|
||||
"mode": "pr_review",
|
||||
"one_click_fixes_enabled": True,
|
||||
"auto_fix_enabled": True,
|
||||
"local_fix_branches_enabled": True,
|
||||
},
|
||||
],
|
||||
)
|
||||
async def test_disabled_one_click_fixes_skips_fix_runtime(
|
||||
async def test_disabled_auto_fix_skips_fix_runtime(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
tmp_path: Path,
|
||||
interactive: bool,
|
||||
|
|
|
|||
|
|
@ -127,7 +127,9 @@ async def test_native_parallel_fixes_deliver_patches_and_preserve_scan_source(
|
|||
assert first["success"] and second["success"], (first, second)
|
||||
duplicate = await delegate(context)
|
||||
assert duplicate["agent_id"] == first["agent_id"]
|
||||
await fixes.wait()
|
||||
branches, errors = await fixes.wait()
|
||||
assert branches == errors == []
|
||||
assert _git(source, "branch", "--list", "strix/fix-*") == ""
|
||||
assert len(models) == 2
|
||||
assert all(record["status"] == "done" for record in fixes.records.values()), fixes.records
|
||||
assert all(Path(record["artifact"]).exists() for record in fixes.records.values())
|
||||
|
|
@ -150,7 +152,6 @@ async def test_ready_fix_creates_local_branch_without_changing_checkout(
|
|||
tmp_path, monkeypatch, interactive
|
||||
):
|
||||
fixes, _, source, _, _, context, sessions = setup(tmp_path, interactive=interactive)
|
||||
fixes.publish_local_branches = True
|
||||
original_head = _git(source, "rev-parse", "HEAD")
|
||||
original_branch = _git(source, "branch", "--show-current")
|
||||
monkeypatch.setattr(
|
||||
|
|
@ -205,7 +206,6 @@ async def test_delegation_errors_reach_reporting_agent_before_any_model_call(tmp
|
|||
@pytest.mark.asyncio
|
||||
async def test_blocked_native_child_has_no_patch(tmp_path, monkeypatch):
|
||||
fixes, _, _, _, _, context, sessions = setup(tmp_path)
|
||||
fixes.publish_local_branches = True
|
||||
monkeypatch.setattr(
|
||||
scan_module,
|
||||
"_run_config",
|
||||
|
|
@ -233,7 +233,6 @@ async def test_cancelled_verification_is_reported_without_publishing_a_branch(
|
|||
tmp_path, monkeypatch, withdrawn
|
||||
):
|
||||
fixes, _, source, _, reports, context, sessions = setup(tmp_path, interactive=True)
|
||||
fixes.publish_local_branches = True
|
||||
reviewing = asyncio.Event()
|
||||
|
||||
async def verify(*_args):
|
||||
|
|
@ -272,7 +271,6 @@ async def test_cancelled_verification_is_reported_without_publishing_a_branch(
|
|||
@pytest.mark.parametrize("status", ["running", "stopped", "failed", "done"])
|
||||
async def test_wait_omits_withdrawn_records_but_keeps_current_fix_errors(tmp_path, status):
|
||||
fixes, _, source, _, _, _, _ = setup(tmp_path)
|
||||
fixes.publish_local_branches = True
|
||||
digest = fixes._finding("finding")[1].digest()
|
||||
fixes.records = {
|
||||
"finding": {"digest": digest, "status": "stopped", "reason": "Tests failed"},
|
||||
|
|
@ -294,7 +292,6 @@ async def test_wait_omits_withdrawn_records_but_keeps_current_fix_errors(tmp_pat
|
|||
@pytest.mark.asyncio
|
||||
async def test_dispatch_failure_is_reported_before_an_agent_exists(tmp_path, monkeypatch):
|
||||
fixes, _, _, _, _, context, _ = setup(tmp_path)
|
||||
fixes.publish_local_branches = True
|
||||
fixes._parent_ctx = context.context
|
||||
monkeypatch.setattr(fixes, "spawn", AsyncMock(side_effect=RuntimeError("Source unavailable")))
|
||||
await fixes._dispatch("finding")
|
||||
|
|
@ -306,7 +303,6 @@ async def test_dispatch_failure_is_reported_before_an_agent_exists(tmp_path, mon
|
|||
@pytest.mark.asyncio
|
||||
async def test_revised_candidate_does_not_publish_stale_ready_artifact(tmp_path, monkeypatch):
|
||||
fixes, report, source, _, _, _, _ = setup(tmp_path)
|
||||
fixes.publish_local_branches = True
|
||||
original_digest = fixes._finding("finding")[1].digest()
|
||||
artifact = tmp_path / "state/fixes/stale/prepared-fix.zip"
|
||||
artifact.parent.mkdir(parents=True)
|
||||
|
|
@ -330,7 +326,6 @@ async def test_revised_candidate_does_not_publish_stale_ready_artifact(tmp_path,
|
|||
@pytest.mark.asyncio
|
||||
async def test_local_branch_failure_is_persisted_and_returned(tmp_path):
|
||||
fixes, _, _, _, _, _, _ = setup(tmp_path)
|
||||
fixes.publish_local_branches = True
|
||||
digest = fixes._finding("finding")[1].digest()
|
||||
artifact = tmp_path / "state/fixes/broken/prepared-fix.zip"
|
||||
artifact.parent.mkdir(parents=True)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue