fix(arcade-cli): resolve org/project coordinator URL from arcade login - #912
Draft
HBX814 wants to merge 1 commit into
Draft
fix(arcade-cli): resolve org/project coordinator URL from arcade login#912HBX814 wants to merge 1 commit into
HBX814 wants to merge 1 commit into
Conversation
HBX814
force-pushed
the
fix/cli-coordinator-url-resolution
branch
from
August 22, 2026 12:02
94a487d to
7af7b3f
Compare
Codecov Report❌ Patch coverage is
🚀 New features to boost your workflow:
|
The `org` and `project` command groups built their coordinator URL from `PROD_COORDINATOR_HOST`, while `get_auth_headers` resolved the token from the `coordinator_url` saved by `arcade login`. On a dedicated instance the two disagreed: the request went to `https://cloud.arcade.dev` carrying a token minted by the tenant coordinator, so `arcade project list` failed with 401 immediately after a successful login — and it is the very command the login success message suggests. Resolve the group URL as explicit flags, then the saved coordinator, then production, mirroring the precedence introduced for the engine URL in ArcadeAI#892 so the token and the request URL always name the same environment. Resolves: ArcadeAI#896
HBX814
force-pushed
the
fix/cli-coordinator-url-resolution
branch
from
August 24, 2026 20:27
7af7b3f to
eedd182
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
arcade login -h <coordinator-host>saves the coordinator it authenticated against, and the token it saves is only valid for that coordinator. Theorgandprojectcommand groups, however, built their request URL fromPROD_COORDINATOR_HOST, whileget_auth_headersalready fell back to the savedconfig.coordinator_urlfor the token. On a dedicated instance the two halves of the request disagreed: the call went tohttps://cloud.arcade.devcarrying a token minted by the tenant coordinator, and came back401 Unauthorized.That made the failure land in a bad spot —
arcade project listis the command the login success message itself suggests, so the first thing a user does after a successful login fails.This resolves the group URL as explicit flags → coordinator saved by
arcade login→ production, so the token and the request URL always name the same environment.Resolves: #896
Design decisions
Resolution lives in one shared helper.
resolve_coordinator_urlinarcade_cli/utils.pysits next toget_auth_headers, which already does the token half of the same resolution. Keeping them adjacent is the point: these two must agree, and the bug was precisely that they didn't.Explicit flags stay authoritative, and that includes
--port/--tls/--no-tls, not just--host. The saved coordinator is a full URL, so honoring it while applying a partial override would mean guessing which half wins (does the saved:8443survive a bare--tls?). Rather than invent that precedence, any explicit connection flag means the caller is describing the target and the URL is built from the flags alone. This also keeps behavior byte-identical for anyone currently passing flags, including thearcade project -h <host> listworkaround from the issue.The saved coordinator is used verbatim, preserving its scheme and port, rather than being decomposed into a host and rebuilt.
--hostnow defaults toNoneinstead ofPROD_COORDINATOR_HOST. With the old default, a user explicitly typing-h cloud.arcade.devwas indistinguishable from not passing the flag, so "was this overridden?" could not be answered.Nonemakes that distinction real.Reads go through a small
_coordinator_url()accessor. The module-levelstatedict previously held a hardcoded production URL that the group callback overwrote on every real invocation. Seeding it with production meant that if the callback were ever bypassed, the fallback would be the exact silent-401 behavior being fixed here. The accessor re-resolves instead, so the correct behavior is also the fallback.Failure to read the config degrades to
None, not an exception. Importingarcade_core.configloads the credentials file at import time and raises when logged out, soget_saved_coordinator_urlswallows that and lets callers fall back to production. A logged-out user gets today's behavior.Scope
In scope:
organdprojectcommand groups (the groups reported in [Bug] CLI: org/project commands ignore saved coordinator host and default to Arcade Cloud #896).Not in scope (deliberately):
secret.py, which the issue flags for the same audit. It has the same shape of bug, but it is engine-scoped (PROD_ENGINE_HOST), not coordinator-scoped, so fixing it needs thecloud.*→api.*derivation added in fix(arcade-mcp-server): derive engine URL from arcade login coordinator #892 — which currently lives inarcade_mcp_server/server.pyas_engine_url_from_coordinator. Doing it properly means promoting that helper intoarcade-coreso the CLI and the MCP server share one implementation instead of duplicating it. That is a wider refactor across two packages and reads better as its own PR. Happy to follow up with it if you want it.connect.pyalready resolvescoordinator_url or f"https://{PROD_COORDINATOR_HOST}", so it is unaffected.Test plan
New
libs/tests/cli/test_coordinator_url.py(20 tests) covering the resolver, the config read, both command groups end-to-end through Typer (listandset), and the accessor fallback.Confirmed the new tests actually reproduce the bug. Reverting only
project.py/org.pyto the original code fails 4 of them withActual: fetch_projects('https://cloud.arcade.dev', 'org_1')— the exact URL from the issue. They pass with the fix.Exercised the real end-user path with no mocks, via a genuine post-login
credentials.yaml(written throughConfig.save_to_file) andARCADE_WORK_DIR:project listtargetsorg listtargetshttps://cloud.arcade.dev(→ 401)https://cloud.arcade.dev(→ 401)https://coordinator.tenant.example.comhttps://coordinator.tenant.example.comAnd
arcade project -h override.example.com liststill targetshttps://override.example.com, so the issue's workaround keeps working.Logged-out / unreadable-config case falls back to
https://cloud.arcade.devwithout raising.libs/tests/cli/green: 806 passed, 45 skipped (786 before this change, +20 new).Codecov flagged 2 uncovered patch lines on the first run: the
_coordinator_url()call sites insidearcade project set/arcade org set, which the original tests did not reach. Those subcommands resolve the Coordinator the same waylistdoes, so they are now covered too — a real gap, not a coverage-chasing edit.ruff check,ruff format --check, andpre-commit run --files <changed>clean on the changed files;mypyclean onarcade-cli(29 files).Full
libs/tests/run: 3218 passed, 532 skipped. The 2 failures inarcade_mcp_server/integration/test_end_to_end.py(test_stdio_e2e,test_http_e2e) are pre-existing onmain— verified by stashing this change and re-running — and are a local server-spawn/port issue on Windows, unrelated toarcade-cli.No version bump: behavior-only fix, no public API or dependency change.
Risk note
Behavior changes only for users who pass no connection flags to
arcade org/arcade project:cloud.arcade.deveither way).Anyone passing
--host/--port/--tls/--no-tlsis unaffected by construction. The one way this could surprise someone is a stalecoordinator_urlincredentials.yamlfrom an old login, which would now be honored where production was used before;arcade logout && arcade login, or an explicit-h, resolves that.