From f3f1b37221648b8e07c00f45b99fa201f59fe923 Mon Sep 17 00:00:00 2001 From: ARIA Date: Tue, 25 Aug 2026 13:42:46 +0200 Subject: [PATCH] Fix iris setup: embed generated token in the pairing URL/QR interactive_setup() generated a fresh IRIS_TOKEN and saved it to .env, but the local `token` variable was never updated, so the pairing URL and QR payload were built with an empty token (token=). The gateway accepted the saved token, but the app never received it, so pairing was impossible. Assign the generated value back to `token` so the pairing URL/QR carry it. Add a regression test (test_interactive_setup_generates_token_in_pairing_url). --- gateway-plugin/setup.py | 6 +++--- tests/test_android.py | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/gateway-plugin/setup.py b/gateway-plugin/setup.py index f1fbe43..1beb261 100644 --- a/gateway-plugin/setup.py +++ b/gateway-plugin/setup.py @@ -481,9 +481,9 @@ def interactive_setup() -> None: print_info("📱 Android / Desktop (Iris x Hermes)") token = get_env_value("IRIS_TOKEN") or "" if not token: - generated = generate_token() - save_env_value("IRIS_TOKEN", generated) - print_success(f"Generated pairing token: {generated}") + token = generate_token() + save_env_value("IRIS_TOKEN", token) + print_success(f"Generated pairing token: {token}") print_warning("Keep this secret -- the app presents it on connect.") else: print_info("Existing IRIS_TOKEN found (not shown).") diff --git a/tests/test_android.py b/tests/test_android.py index 41e0144..f0aaa2c 100644 --- a/tests/test_android.py +++ b/tests/test_android.py @@ -3024,6 +3024,44 @@ def test_offer_device_removal_setup_flow(tmp_path, monkeypatch): _run([]) # any input() call would raise StopIteration → test fails +def test_interactive_setup_generates_token_in_pairing_url(tmp_path, monkeypatch, capsys): + """interactive_setup: when no IRIS_TOKEN is set, the generated token is + saved AND embedded in the printed pairing URL (regression: the token was + generated but the local ``token`` stayed empty, so the pairing URL carried + ``token=`` and pairing was impossible).""" + plugin = _load_plugin() + monkeypatch.setenv("HERMES_HOME", str(tmp_path)) + + saved: dict[str, str] = {} + monkeypatch.setattr( + "hermes_cli.config.get_env_value", + lambda name: saved.get(name, ""), + ) + monkeypatch.setattr( + "hermes_cli.config.save_env_value", + lambda name, value: saved.__setitem__(name, value), + ) + # prompt returns the default (no interactive input needed). + monkeypatch.setattr( + "hermes_cli.cli_output.prompt", + lambda question, default="": default, + ) + # Skip the device-removal / TLS sub-flows, LAN-IP discovery, and the + # terminal QR block. + monkeypatch.setattr(plugin.setup, "_offer_device_removal", lambda: None) + monkeypatch.setattr(plugin.setup, "_offer_tls_setup", lambda *a, **k: None) + monkeypatch.setattr(plugin.setup, "advertise_host", lambda host: "10.0.0.111") + monkeypatch.setattr(plugin.qr, "render_qr", lambda *a, **k: "") + + plugin.setup.interactive_setup() + + out = capsys.readouterr().out + token = saved.get("IRIS_TOKEN", "") + assert token, "IRIS_TOKEN was not saved" + # The pairing URL must carry the generated token (not an empty token=). + assert f"token={token}" in out, f"pairing URL missing the generated token:\n{out}" + + # ── TLS setup: self-signed cert generation (install.md Part 4, Option B) ──