feat(apikey): auto-fetch from pass agentes/api-key when env empty

Launching from the App Hub (or any double-click) no longer needs
AGENTS_API_KEY manually injected. Order of resolution:

  1. AGENTS_API_KEY env var          → apikey_source = "env"
  2. `pass agentes/api-key` shell    → apikey_source = "pass"
  3. neither                          → apikey_source = "missing"

On Windows the fallback shells via `wsl.exe -e sh -c "pass ... | head -n1"`
so the secret stays in the WSL user's GnuPG keychain (never copied to a
Windows file). On Linux it's a direct popen of `pass ...`.

Failure mode: GPG agent locked → empty output → "missing" state in UI
with a "Retry pass" button (user runs `pass agentes/api-key` once to
unlock the agent, clicks Retry, app refetches without restart).

Connection panel shows the active source:
  ✓ loaded from AGENTS_API_KEY env var
  ✓ loaded via `pass agentes/api-key`
  ⚠ apikey not found (env empty + pass failed)

--connect-test uses the same two-tier resolution so e2e exercises the
production code path.

E2E: renamed test_connect_fails_without_apikey →
test_connect_falls_back_to_pass_when_env_empty. Verifies that with
empty env, the .exe still returns OK N. Skips if `pass` is locked.

All 24 tests passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-22 23:16:22 +02:00
parent aa88a1cb4a
commit 18b5ffdfd9
2 changed files with 147 additions and 30 deletions
+19 -6
View File
@@ -82,18 +82,31 @@ def test_connect_succeeds_with_valid_apikey():
assert n > 0, f"expected at least 1 agent, got {n}"
def test_connect_fails_without_apikey():
"""FAIL on stderr, exit 1, when AGENTS_API_KEY is empty."""
# Force-empty AGENTS_API_KEY; bypass WSLENV by clearing it too.
def test_connect_falls_back_to_pass_when_env_empty():
"""When AGENTS_API_KEY env is empty, the .exe must fetch apikey via
`wsl.exe pass agentes/api-key` (or `pass` on Linux). This is what makes
launching from the App Hub work without manual env injection.
Skipped if `pass agentes/api-key` itself can't be read (GPG locked).
"""
# Verify pass is unlocked before testing the fallback
pass_check = subprocess.run(
["pass", "agentes/api-key"],
capture_output=True, text=True, timeout=5,
)
if pass_check.returncode != 0 or not pass_check.stdout.strip():
pytest.skip("pass agentes/api-key not readable (GPG locked?)")
# Force-empty AGENTS_API_KEY + bypass WSLENV propagation
r = subprocess.run(
[str(_exe()), "--connect-test", _url()],
capture_output=True,
text=True,
timeout=30,
env={**os.environ, "AGENTS_API_KEY": "", "WSLENV": "AGENTS_API_KEY"},
env={**os.environ, "AGENTS_API_KEY": "", "WSLENV": ""},
)
assert r.returncode != 0
assert "AGENTS_API_KEY" in r.stderr, f"stderr=[{r.stderr!r}]"
assert r.returncode == 0, f"pass fallback failed: stdout={r.stdout!r} stderr={r.stderr!r}"
assert r.stdout.startswith("OK "), f"stdout=[{r.stdout!r}]"
def test_connect_fails_on_bad_host():