fix(opencode): the auth check is the binary, and create takes the adapter's verdict (Issue #60, Linux item 3)

opencode 2.x needs no login: a fresh HOME runs a free default model and a
local provider has no key, while 2.x keeps no auth.json. auth_ok is now
"opencode on PATH or under <HOME>/.opencode/bin". `python -m lib_py.agents
auth-ok <agent>` exits with an adapter's verdict, and create's opencode
branch uses it (same 7 lines) instead of its own auth.json/key test and
`opencode --version`, which wrote a line to the real opencode log.
test_a4's opencode block now pins the binary rule (decision D1, required
by the brief's item 3 and by both reviewers). Other agents are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
GodopuandClaude Opus 5.5 committed 2026-10-18 13:38:58 +00:00
1 parent 7803d47026
commit d17cd80bd9
5 files changed
+100 -17

No files matched your search

+74
View File
@@ -9,6 +9,8 @@
(binary, HOME, XDG_DATA_HOME) in a process.
2. A graceful stop whose `/exit` worked says so: the agent exits instead of
turning `working`, so the delivery is unconfirmed, and no kill step ran.
3. opencode's auth check is the binary alone (2.x needs no login), and create
takes the adapter's verdict instead of running `opencode --version`.
"""
from __future__ import annotations
@@ -279,3 +281,75 @@ def test_the_graceful_stop_reports_what_happened(mam_sandbox, mock_herdr, mock_a
else:
# The kill step runs, so it is named.
assert "still alive → kill-session" in out, out
# ---------------------------------------------------------------------------
# 3. opencode's auth check is the binary
# ---------------------------------------------------------------------------
def _executable(path: Path) -> Path:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text("#!/bin/sh\n")
path.chmod(0o755)
return path
@pytest.fixture
def bare_home(tmp_path, monkeypatch):
"""An empty HOME_DIR and a PATH with no opencode."""
monkeypatch.setenv("HOME_DIR", str(tmp_path / "home"))
monkeypatch.setenv("PATH", str(tmp_path / "empty-bin"))
for var in ("ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GEMINI_API_KEY", "GROQ_API_KEY"):
monkeypatch.delenv(var, raising=False)
return tmp_path
def test_keys_and_auth_json_without_the_binary_are_not_enough(bare_home, monkeypatch):
opencode = get_adapter("opencode")
assert opencode.auth_ok() is False
monkeypatch.setenv("ANTHROPIC_API_KEY", "test-key")
assert opencode.auth_ok() is False
auth = bare_home / "home" / ".local" / "share" / "opencode" / "auth.json"
auth.parent.mkdir(parents=True)
auth.write_text("{}")
assert opencode.auth_ok() is False
@pytest.mark.parametrize("where", ["path", "home"])
def test_the_binary_alone_is_enough(bare_home, monkeypatch, where):
if where == "path":
_executable(bare_home / "bin" / "opencode")
monkeypatch.setenv("PATH", str(bare_home / "bin"))
else:
_executable(bare_home / "home" / ".opencode" / "bin" / "opencode")
assert get_adapter("opencode").auth_ok() is True
def test_the_auth_ok_command_exits_with_the_verdict(bare_home):
def rc(*args):
env = dict(os.environ, PYTHONPATH=str(SKILLS))
return subprocess.run([sys.executable, "-m", "lib_py.agents", "auth-ok", *args],
capture_output=True, text=True, env=env).returncode
assert rc("opencode") == 1
_executable(bare_home / "home" / ".opencode" / "bin" / "opencode")
assert rc("opencode") == 0
assert rc("no-such-agent") == 1
def test_create_decides_opencode_auth_without_running_it(mam_sandbox, mock_herdr, mock_agents, monkeypatch):
# Every opencode call create makes is logged; --version was the old check.
log = mam_sandbox / "opencode-calls.log"
wrap = mam_sandbox / "logbin" / "opencode"
wrap.parent.mkdir()
wrap.write_text(f'#!/bin/sh\necho "$*" >> "{log}"\nexec "{shutil.which("opencode")}" "$@"\n')
wrap.chmod(0o755)
monkeypatch.setenv("PATH", f"{wrap.parent}:{os.environ['PATH']}")
for var in ("ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GEMINI_API_KEY", "GROQ_API_KEY"):
monkeypatch.delenv(var, raising=False)
create = mam_sandbox / ".agents" / "skills" / "multi-agent-mux-create" / "scripts" / "create_session.sh"
res = subprocess.run(["bash", str(create), "--workspace", str(mam_sandbox), "--agent", "opencode",
"--role", "creator", "--no-onboard"],
capture_output=True, text=True, cwd=str(mam_sandbox), timeout=300)
assert res.returncode == 0, res.stdout + res.stderr
calls = log.read_text().splitlines() if log.exists() else []
assert "--version" not in calls, calls