Skip to content

fix(cli): resolve cloud enrollment workspace identifiers#1343

Merged
khaliqgant merged 3 commits into
mainfrom
agent/fix-cloud-enrollment-workspace-resolution
Jul 19, 2026
Merged

fix(cli): resolve cloud enrollment workspace identifiers#1343
khaliqgant merged 3 commits into
mainfrom
agent/fix-cloud-enrollment-workspace-resolution

Conversation

@khaliqgant

@khaliqgant khaliqgant commented Jul 19, 2026

Copy link
Copy Markdown
Member

Scope

This Relay PR fixes the client-side workspace-ID namespace and diagnostics for session-based fleet enrollment. It does not claim to fix the production owner denial: the authoritative authorization defect is in AgentWorkforce/cloud and requires a Cloud change plus deploy.

What changed

  • validate --workspace as a non-secret Cloud UUID or unified rw_ ID, then resolve it through GET /api/v1/workspaces/:workspaceId/resolve before minting
  • send the returned Cloud workspace UUID to POST /api/v1/fleet/enrollment-tokens
  • carry any refreshed bearer returned by workspace resolution into the mint request
  • reject unsupported identifiers before auth or network I/O, never echoing the supplied value (including an rk_live_... secret) in errors
  • cover canonical resolution, refreshed-auth continuity, secret-safe identifier rejection, resolver 403/404/429 and malformed responses, and downstream mint errors

Root cause and production blocker

There are two independent failures:

  1. 204337648549896192 is not a supported Cloud workspace UUID or unified rw_ workspace ID. A raw production request returns 404 {"error":"Workspace not found"} from GET /api/v1/workspaces/204337648549896192/resolve. The current Cloud workspace UUID is 50587328-441d-4acb-b8f3-dbe1b3c5de99.
  2. Even with that correct UUID, production enrollment returns 403. The Cloud route packages/web/app/api/v1/fleet/enrollment-tokens/route.ts calls resolveRequestAuth(request) and then immediately rejects !requireSessionAuth(auth). The stored Cloud login is source=token, subjectType=cli, with scopes auth:workspace:follow-user, cli:auth, so every CLI bearer is rejected before findWorkspace or requireOrgOwner can evaluate the owner's role. /api/v1/auth/whoami reports the current organization role as owner.

The Cloud fix must keep the secret-mint boundary strict: admit only an authenticated CLI subject with the required CLI scope(s), bind it to the exact target Cloud workspace, then query an active owner|admin role before minting. packages/web/lib/auth/deployment-api-token-access.ts is an existing exact-workspace/active-role DB-join reference; packages/web/app/api/v1/fleet/local-surface/route.ts is the existing deliberate session-or-cli:auth route pattern. The Cloud regression suite must prove owner/admin success and deny member/non-owner, unrelated workspace, non-CLI token, and missing-scope token cases. A production Cloud deploy is required after that fix.

Verbatim evidence

Before, released agent-relay 10.6.5:

$ agent-relay cloud enroll --workspace 204337648549896192
You do not have permission to enroll nodes in workspace 204337648549896192. An organization owner or admin must run this command.

After this Relay change, the unsupported identifier is rejected locally—without being echoed—before auth, resolution, or minting:

$ node packages/cli/dist/cli/index.js cloud enroll --workspace 204337648549896192
Unsupported Cloud workspace identifier. Use a Cloud workspace UUID or unified rw_ workspace ID.

The canonical UUID reaches the authoritative mint route and proves the remaining Cloud blocker:

$ node packages/cli/dist/cli/index.js cloud enroll --workspace 50587328-441d-4acb-b8f3-dbe1b3c5de99
You do not have permission to enroll nodes in workspace 50587328-441d-4acb-b8f3-dbe1b3c5de99. An organization owner or admin must run this command.

Direct production contract evidence:

GET  /api/v1/workspaces/204337648549896192/resolve -> 404 {"error":"Workspace not found"}
GET  /api/v1/workspaces/50587328-441d-4acb-b8f3-dbe1b3c5de99/resolve -> 200 (cloudWorkspaceId 50587328-441d-4acb-b8f3-dbe1b3c5de99)
POST /api/v1/fleet/enrollment-tokens {"workspaceId":"50587328-441d-4acb-b8f3-dbe1b3c5de99"} -> 403 {"error":"Forbidden"}

Validation

  • failing regressions first: canonical resolution failed with exit:1; unsupported numeric/rk_live_... selectors reached resolution and were echoed before validation/redaction; resolver 429 responses lost Retry-After; malformed resolver descriptors were misreported as unlinked workspaces
  • npm run build
  • npm run typecheck
  • npm test — 96 files passed, 2 skipped; 1,297 tests passed, 18 skipped
  • npm run lint — 0 errors (38 pre-existing warnings)
  • npm run format:check
  • live before/after commands above

PR #1342 has no enrollment-source overlap; only the root changelog may need routine rebase conflict resolution.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 413ddd41-69d1-47b5-8652-b633852eb2d3

📥 Commits

Reviewing files that changed from the base of the PR and between 7d1faa4 and 043cfdc.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • packages/cli/src/cli/commands/cloud.test.ts
  • packages/cli/src/cli/commands/cloud.ts

📝 Walkthrough

Walkthrough

cloud enroll --workspace now validates UUID and rw_ identifiers, resolves them to canonical Cloud workspace UUIDs, and uses that UUID when minting enrollment credentials. Tests cover resolver errors, invalid responses, rate limits, unsupported identifiers, and updated messaging.

Changes

Cloud enrollment workspace resolution

Layer / File(s) Summary
Workspace identifier validation and resolution
packages/cli/src/cli/commands/cloud.ts
Supported workspace identifiers are validated and resolved through the Cloud resolver, with explicit handling for HTTP and malformed-response errors.
Resolved workspace enrollment minting
packages/cli/src/cli/commands/cloud.ts
Enrollment minting uses the resolved cloudWorkspaceId, and the command help describes the resolve-and-mint flow.
Enrollment flow validation and release notes
packages/cli/src/cli/commands/cloud.test.ts, CHANGELOG.md
Tests cover successful resolution, resolver and mint failures, rate limits, invalid descriptors, unsupported identifiers, and updated error messages; the changelog records the fix.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CloudEnrollCommand
  participant CloudResolver
  participant EnrollmentAPI
  User->>CloudEnrollCommand: provide workspace identifier
  CloudEnrollCommand->>CloudResolver: resolve identifier
  CloudResolver-->>CloudEnrollCommand: return canonical cloudWorkspaceId
  CloudEnrollCommand->>EnrollmentAPI: mint enrollment token
  EnrollmentAPI-->>CloudEnrollCommand: return enrollment credentials
Loading

Possibly related PRs

Suggested reviewers: willwashburn

Poem

I hop through UUIDs, neat and bright,
Resolve each workspace just right.
No false permission tale,
No mint on a failed trail—
Then tokens bloom in Cloudlight! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: resolving cloud enrollment workspace identifiers.
Description check ✅ Passed The description is thorough and covers scope, changes, blockers, and validation, with only the template headings differing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/fix-cloud-enrollment-workspace-resolution

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the agent-relay cloud enroll --workspace command to resolve Cloud workspace UUIDs, unified rw_ IDs, and workspace keys before minting enrollment tokens, and handles incompatible Relaycast-only IDs gracefully. Feedback on these changes suggests improving error handling during workspace resolution by explicitly checking for rate-limiting (429 status) and handling cases where the response payload fails to parse as JSON to avoid misleading error messages.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/cli/src/cli/commands/cloud.ts
Comment thread packages/cli/src/cli/commands/cloud.ts

@khaliqgant khaliqgant left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent review verdict: REQUEST CHANGES (narrow Relay PR).

The pushed secret-selector repair is correct: rk_live_… and the reported numeric ID are rejected before auth/network I/O, resolver errors no longer echo selectors, the accepted rw_ grammar matches Cloud’s authoritative isValidWorkspaceId, and refreshed auth is carried into minting.

Two resolver-stage gaps remain before signoff:

  1. A resolver 429 falls through to the generic error and drops Retry-After; the existing rate-limit test covers only the later mint request. Preserve Retry-After at the new preflight stage and prove mint is not attempted.
  2. A successful resolver response with invalid/non-JSON content is reported as “not linked,” which misdiagnoses a malformed server response. Emit a generic malformed-response error (without the selector) and test it.

Please also add resolver 403/404 regression coverage proving the redacted generic messages and that failures stop before mint. These findings match the two existing Gemini inline comments.

Scope note: even after these Relay changes, this PR does not fix the owner authorization denial. Production still requires the separate Cloud route change and deploy that admits only scoped CLI subjects and then enforces active owner/admin authority on the exact workspace.

GitHub does not allow the authenticated PR author account to submit an actual REQUEST_CHANGES review, so this is posted as a COMMENT review; the verdict above is unchanged.

@khaliqgant khaliqgant left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent re-review verdict on 043cfdcd: SIGNOFF — no remaining findings for this narrowly scoped Relay client change.

Verified line-by-line:

  • accepted selectors are limited to non-secret Cloud UUIDs and authoritative lowercase rw_ IDs
  • unsupported/numeric/rk_live_… values fail before login or network I/O and are not echoed
  • resolver 403/404 and generic failures do not trust or echo response payloads
  • resolver 429 preserves Retry-After
  • malformed descriptors and non-UUID cloudWorkspaceId values fail before minting
  • refreshed auth from resolution is used for the mint request
  • direct --token enrollment remains unchanged
  • PR #1342 has no code overlap; only CHANGELOG.md may need a routine rebase resolution

Independent local verification: targeted cloud.test.ts (42/42), changed-file Prettier check, and full TypeScript typecheck all pass. The author reports the full suite at 1,297 passing tests; GitHub Actions for this head are still running as of this review.

Important scope boundary: this signoff does not mean the reported owner enrollment failure is fixed. Production still denies the correct Cloud UUID because the Cloud mint route rejects CLI bearer auth before owner/admin evaluation. The separate Cloud authorization fix, deploy, negative permission tests, and live owner enrollment verification remain mandatory. Do not treat this Relay PR as READY FOR MERGE for the end-to-end issue.

GitHub does not allow the authenticated PR-author account to approve its own PR, so this signoff is recorded as a COMMENT review.

@khaliqgant
khaliqgant marked this pull request as ready for review July 19, 2026 10:55
@khaliqgant
khaliqgant requested a review from willwashburn as a code owner July 19, 2026 10:55
@cursor

cursor Bot commented Jul 19, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@khaliqgant khaliqgant left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review from cloud-train lead (verified against live repro):

Client-side changes: APPROVE. The identifier-validation + resolver + honest-error-mapping design is right, and the diagnosis matches my live failure exactly — my original denial used the relaycast numeric id (204337648549896192), an unsupported identifier the server mislabeled as a permission failure. The rk_live non-disclosure test is a nice touch, as is refusing to mint on an invalid resolver descriptor.

But this PR alone does not fix enrollment — server-side bug confirmed live. Just now on sf-mini (agent-relay 10.6.5, khaliq's owner account, verified identical cloud whoami on both machines):

$ agent-relay cloud enroll --workspace 50587328-441d-4acb-b8f3-dbe1b3c5de99 --name sf-mini
You do not have permission to enroll nodes in workspace 50587328-441d-4acb-b8f3-dbe1b3c5de99. An organization owner or admin must run this command.

That's the proper cloud workspace UUID and the org owner being denied at /api/v1/fleet/enrollment-tokens — a server-side role-mapping defect (CLI subject → workspace owner/admin), which lives in the agentrelay.com service, not this repo. Please make sure the PR body names that server component + endpoint explicitly as the remaining half, so this doesn't get closed as 'fixed' while enrollment still fails for owners.

Two smaller notes: (1) confirm /api/v1/workspaces/{id}/resolve exists in the deployed cloud API — if it doesn't, the new resolver path 404s and the 'identifier was not found' message would mislead; state its availability in the PR body. (2) UNIFIED_WORKSPACE_ID_PATTERN pins rw_ + exactly 8 [a-z0-9] — fine if that's the format contract, but worth a comment citing where that contract is defined.

@khaliqgant
khaliqgant merged commit 756a0df into main Jul 19, 2026
45 checks passed
@khaliqgant
khaliqgant deleted the agent/fix-cloud-enrollment-workspace-resolution branch July 19, 2026 19:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant