Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions argus_skill/apps/cli/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ def main(argv: list[str] | None = None) -> int:
backend=getattr(args, "backend", None),
auth_mode=getattr(args, "auth_mode", None),
non_interactive=bool(getattr(args, "non_interactive", False)),
allow_prerelease=bool(getattr(args, "allow_prerelease", False)),
allow_prerelease=getattr(args, "allow_prerelease", None),
api_url=getattr(args, "api_url", None),
api_key=getattr(args, "api_key", None),
api_model=getattr(args, "api_model", None),
Expand Down Expand Up @@ -752,7 +752,7 @@ def _cmd_daemon_start(args: argparse.Namespace, *, foreground: bool) -> int:
getattr(args, "auth_mode", None),
probe_auth=True,
probe_vault=not skip_vault_probe,
allow_prerelease=bool(getattr(args, "allow_prerelease", False)),
allow_prerelease=getattr(args, "allow_prerelease", None),
)
if not readiness.ok:
sys.stderr.write(format_backend_readiness(readiness) + "\n")
Expand Down Expand Up @@ -839,7 +839,7 @@ def _maintenance_context(args: argparse.Namespace):
install_mode=install_mode,
backend=getattr(args, "backend", None),
auth_mode=getattr(args, "auth_mode", None),
allow_prerelease=bool(getattr(args, "allow_prerelease", False)),
allow_prerelease=getattr(args, "allow_prerelease", None),
)


Expand Down
1 change: 1 addition & 0 deletions argus_skill/apps/cli/_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ def build_parser() -> argparse.ArgumentParser:
capability_grp.add_argument(
"--allow-prerelease",
action="store_true",
default=None,
help="allow an explicitly selected prerelease backend CLI",
)
capability_grp.add_argument(
Expand Down
2 changes: 1 addition & 1 deletion argus_skill/maintenance/doctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class DoctorContext:
install_mode: str = "source"
backend: str | None = None
auth_mode: str | None = None
allow_prerelease: bool = False
allow_prerelease: bool | None = None

def fingerprint_payload(self) -> dict[str, str | int]:
return {
Expand Down
4 changes: 2 additions & 2 deletions argus_skill/tools/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ def _run_noninteractive_setup(
*,
backend: str | None,
auth_mode: str | None,
allow_prerelease: bool,
allow_prerelease: bool | None,
api_url: str | None,
api_key: str | None,
api_model: str | None,
Expand Down Expand Up @@ -502,7 +502,7 @@ def run_setup(
backend: str | None = None,
auth_mode: str | None = None,
non_interactive: bool = False,
allow_prerelease: bool = False,
allow_prerelease: bool | None = None,
api_url: str | None = None,
api_key: str | None = None,
api_model: str | None = None,
Expand Down
4 changes: 2 additions & 2 deletions argus_skill/webapi/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ def _check_backend_preflight(
backend: str | None = None,
auth_mode: str | None = None,
probe_auth: bool = True,
allow_prerelease: bool = False,
allow_prerelease: bool | None = None,
) -> Check:
from ..core.backend_readiness import check_backend_readiness

Expand Down Expand Up @@ -399,7 +399,7 @@ def run_diagnostics(
backend: str | None = None,
auth_mode: str | None = None,
probe_auth: bool = True,
allow_prerelease: bool = False,
allow_prerelease: bool | None = None,
) -> list[Check]:
"""Run every diagnostic and return the ordered list of :class:`Check`.

Expand Down
82 changes: 82 additions & 0 deletions tests/core/test_backend_readiness.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
from __future__ import annotations

import inspect
import subprocess
from types import SimpleNamespace

import pytest

from argus_skill.apps.cli import _core, build_parser
from argus_skill.core import backend_readiness as readiness
from argus_skill.maintenance.doctor import DoctorContext
from argus_skill.webapi import diagnostics


def _completed(
Expand Down Expand Up @@ -678,3 +685,78 @@ def test_pi_readiness_warns_once_per_distinct_model(monkeypatch, tmp_path) -> No
report = readiness.check_backend_readiness("pi", "subscription_cli")

assert len(report.warnings) == 1, report.warnings


def fake_cli(monkeypatch):
monkeypatch.setattr(readiness, "resolve_runner_bin", lambda *_: "/bin/codex")
monkeypatch.setattr(readiness, "_run_text", lambda *a, **k: subprocess.CompletedProcess(a, 0, "codex-cli 0.154.0-alpha.3\n", ""))
monkeypatch.setenv("ARGUS_SKILL_ALLOW_BACKEND_PRERELEASE", "1")
Comment on lines +690 to +693


def test_unspecified_cli_flag_is_not_an_explicit_refusal():
assert build_parser().parse_args([]).allow_prerelease is None
assert build_parser().parse_args(["--allow-prerelease"]).allow_prerelease is True


def test_cli_context_preserves_unspecified_value(tmp_path):
args=SimpleNamespace(life_dir=str(tmp_path), resume="", allow_prerelease=None)
assert _core._maintenance_context(args).allow_prerelease is None


def test_doctor_default_inherits_documented_environment(monkeypatch, tmp_path):
fake_cli(monkeypatch)
ctx=DoctorContext(global_root=tmp_path,project_root=tmp_path)
report=readiness.check_backend_readiness("codex","subscription_cli",probe_auth=False,allow_prerelease=ctx.allow_prerelease)
assert report.ok, report.problems


def test_web_default_does_not_shadow_environment():
assert inspect.signature(diagnostics.run_diagnostics).parameters["allow_prerelease"].default is None
assert inspect.signature(diagnostics._check_backend_preflight).parameters["allow_prerelease"].default is None


def test_explicit_api_refusal_still_overrides_environment(monkeypatch):
fake_cli(monkeypatch)
report=readiness.check_backend_readiness("codex","subscription_cli",probe_auth=False,allow_prerelease=False)
assert not report.ok
assert "prerelease" in report.problems[0].detail


@pytest.mark.parametrize("env_value", [None, "0", "1"])
@pytest.mark.parametrize("explicit", [None, False, True])
def test_web_preflight_preserves_policy_precedence(monkeypatch, env_value, explicit):
fake_cli(monkeypatch)
if env_value is None:
monkeypatch.delenv("ARGUS_SKILL_ALLOW_BACKEND_PRERELEASE")
else:
monkeypatch.setenv("ARGUS_SKILL_ALLOW_BACKEND_PRERELEASE", env_value)
result = diagnostics._check_backend_preflight(
backend="codex", auth_mode="subscription_cli", probe_auth=False,
allow_prerelease=explicit,
)
expected = explicit if explicit is not None else env_value == "1"
assert result.ok is expected


@pytest.mark.parametrize("non_interactive", [False, True])
@pytest.mark.parametrize("explicit", ["omitted", False, True])
def test_setup_passes_unspecified_and_explicit_policy(monkeypatch, non_interactive, explicit):
from argus_skill.tools import setup

monkeypatch.setattr(setup, "_banner", lambda: None)
monkeypatch.setattr(setup, "_configure_runner_backend", lambda value: value)
monkeypatch.setattr(setup, "_configure_auth_mode", lambda *args: "subscription_cli")
monkeypatch.setattr(setup, "default_model_for_backend", lambda *args: None)
monkeypatch.setattr(setup, "_resolve_setup_runner_bin", lambda *args, **kwargs: "fixture")
monkeypatch.setattr(setup, "format_backend_readiness", lambda report: "fixture")
seen = []

def check(*args, **kwargs):
seen.append(kwargs["allow_prerelease"])
return SimpleNamespace(ok=False)

monkeypatch.setattr(setup, "check_backend_readiness", check)
options = {} if explicit == "omitted" else {"allow_prerelease": explicit}
assert setup.run_setup(backend="codex", non_interactive=non_interactive, **options) == setup.SETUP_EXIT_NOT_READY
assert seen == [None if explicit == "omitted" else explicit]