Skip to content

Refresh workspace token in relayfile login when one is registered#137

Merged
khaliqgant merged 3 commits into
mainfrom
agent-relay/login-refresh-workspace-token
May 11, 2026
Merged

Refresh workspace token in relayfile login when one is registered#137
khaliqgant merged 3 commits into
mainfrom
agent-relay/login-refresh-workspace-token

Conversation

@khaliqgant
Copy link
Copy Markdown
Member

Summary

  • Plain relayfile login only wrote ~/.relayfile/cloud-credentials.json and left the data-plane JWT in ~/.relayfile/credentials.json stale. Every workspace op (status, tree, read, mount auth) returned http 401 unauthorized: Token has expired after the cloud sign-in claimed success.
  • After ensureCloudCredentials succeeds, resolve the active workspace and re-mint the data-plane JWT via joinWorkspaceViaCloud + persistJoinedWorkspace so both credential files are fresh in one step.
  • Adds --workspace NAME (errors if refresh fails) and --skip-workspace-refresh (retain cloud-only behavior). No-ops silently when no workspace is registered, so the cold-start TestLoginDefaultsToCloudBrowserFlow path is unchanged.

Background

Hit while verifying the v2 file-native adapter rollout against rw_517d60b6. After the data-plane JWT expired mid-session, the only documented recoveries were relayfile login --api-key (needs an API key the user doesn't have) or relayfile setup (re-triggers OAuth and mount). The refreshMountAuth loop inside relayfile mount already has the right shape — this PR lifts the same join+persist into the user-facing login command.

Test plan

  • go test ./cmd/relayfile-cli/ — full suite green (4.5s).
  • go vet ./cmd/relayfile-cli/ clean.
  • New TestLoginRefreshesWorkspaceTokenForDefaultWorkspace — asserts /api/v1/workspaces/<id>/join fires and credentials.json is rewritten with the refreshed token + server URL.
  • New TestLoginSkipsWorkspaceRefreshWhenFlagSet — asserts --skip-workspace-refresh suppresses the join call and leaves credentials.json absent.
  • Existing TestLoginDefaultsToCloudBrowserFlow (cold-start, no workspace) still passes — silent no-op path verified.
  • Manual: run relayfile login on a host with an expired credentials.json; verify relayfile status succeeds without a follow-up command.

🤖 Generated with Claude Code

Plain `relayfile login` only wrote ~/.relayfile/cloud-credentials.json,
leaving the data-plane JWT in ~/.relayfile/credentials.json stale.
Users hit `http 401 unauthorized: Token has expired` on every workspace
operation after the cloud sign-in succeeded, and the only documented
recovery was `--api-key` (requires a key the user doesn't have) or
`relayfile setup` (re-triggers OAuth).

After ensureCloudCredentials succeeds, resolve the active workspace and
re-mint the data-plane JWT via joinWorkspaceViaCloud +
persistJoinedWorkspace so both credential files are fresh in one step.

- Add --workspace flag to target a specific workspace (errors if the
  refresh fails, matching the explicit-intent contract).
- Add --skip-workspace-refresh to retain the cloud-only behavior.
- No-op silently when no workspace is registered (the cold-start path
  the existing TestLoginDefaultsToCloudBrowserFlow exercises).
- Soft-warn when the workspace exists but the join call fails so the
  cloud login still counts as successful.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

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: 44fbeb5b-b2e3-4229-ba0d-fc10a408df07

📥 Commits

Reviewing files that changed from the base of the PR and between aad1a9c and ca39776.

📒 Files selected for processing (2)
  • cmd/relayfile-cli/main.go
  • cmd/relayfile-cli/main_test.go

📝 Walkthrough

Walkthrough

Adds optional workspace token refresh to Cloud browser login. New flags --workspace and --skip-workspace-refresh control resolving and re-joining a workspace after sign-in, persisting refreshed credentials, and conditional error vs. warning behavior.

Changes

Workspace Token Refresh on Cloud Login

Layer / File(s) Summary
Flag Definitions & Refresh Logic
cmd/relayfile-cli/main.go
Adds --workspace and --skip-workspace-refresh flags; after Cloud credentials are acquired, the command resolves the target workspace, POSTs to /api/v1/workspaces/<id>/join to obtain a refreshed workspace JWT and server URL, persists the joined workspace into credentials.json, prints Refreshed workspace token for <name> (<id>) on success, and treats refresh errors as fatal when --workspace is explicit or as warnings/skips when implicit.
Test Coverage
cmd/relayfile-cli/main_test.go
Adds tests: TestLoginRefreshesWorkspaceTokenForDefaultWorkspace (ensures /join is called and credentials persisted), TestLoginSkipsWorkspaceRefreshWhenFlagSet (ensures no requests/writes when skip set), TestLoginRejectsWorkspaceWithSkipFlag (mutually-exclusive flags error), TestLoginExplicitWorkspaceReturnsErrorWhenPersistFails (explicit workspace + persist failure yields error), and TestLoginDefaultWorkspaceWarnsWhenPersistFails (implicit default workspace + persist failure emits warning but succeeds).

Sequence Diagram

sequenceDiagram
  participant CLI as relayfile login (CLI)
  participant CloudAPI as Cloud API
  participant LocalStorage as Local Storage (credentials.json)
  CLI->>CloudAPI: Browser login flow (OIDC)
  CloudAPI-->>CLI: Cloud credentials acquired
  alt skip-workspace-refresh not set
    CLI->>CLI: Resolve workspace (flag or active)
    CLI->>CloudAPI: POST /api/v1/workspaces/<id>/join
    CloudAPI-->>CLI: Refreshed workspace JWT & server URL
    CLI->>LocalStorage: Write refreshed workspace credentials
    LocalStorage-->>CLI: Persist success
    CLI-->>CLI: Print "Refreshed workspace token for <name> (<id>)"
  else skip-workspace-refresh set
    CLI-->>CLI: Skip workspace refresh
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • AgentWorkforce/relayfile#125: Modifies the Cloud browser sign-in flow and related tests; closely related to this PR's changes to login and workspace handling.

Poem

🐰 I hopped to the cloud with a key in my paw,
Refreshed every workspace the CLI ever saw,
With --skip to pause or a name to renew,
Tokens snugly saved — refreshed and true,
A tiny rabbit cheers, hop, login, hooray! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding workspace token refresh functionality to the relayfile login command when a workspace is registered.
Description check ✅ Passed The description is directly related to the changeset, providing context about the problem (stale credentials), the solution (refreshing tokens during login), and implementation details.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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-relay/login-refresh-workspace-token

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

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/relayfile-cli/main.go`:
- Around line 1290-1295: When persistJoinedWorkspace(record, joined,
creds.APIURL, record.LocalDir) returns an error, change the logic so that if the
command was invoked with an explicit --workspace value (check the variable that
represents the flag/option used elsewhere in main.go, e.g., workspaceFlag or
opts.Workspace), propagate and return that error instead of printing a warning;
otherwise keep the current warning behavior. Update the branch that currently
prints "warning: workspace token refresh succeeded but persisting it failed: %v"
to conditionally return the error when --workspace was provided, and only print
the warning when no explicit workspace flag was used.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 974bf42e-a20f-448b-b843-549ba8104ce8

📥 Commits

Reviewing files that changed from the base of the PR and between 4d2ea77 and 264d89a.

📒 Files selected for processing (2)
  • cmd/relayfile-cli/main.go
  • cmd/relayfile-cli/main_test.go

Comment thread cmd/relayfile-cli/main.go
Address CodeRabbit P1 on relayfile#137: a persist failure during workspace
token refresh was always downgraded to a warning, even when --workspace
was passed explicitly. That left credentials.json stale while the command
reported success — inconsistent with the join/resolve branches above,
which already return the error when --workspace is explicit.

Mirror that contract for the persist branch:
- Explicit --workspace: return fmt.Errorf("refresh workspace token:
  persist refreshed credentials: %w", perr)
- Implicit default workspace: keep the warning so the cloud login itself
  still counts as successful

Two new tests cover both branches by pre-creating credentials.json as a
non-empty directory so writeFileAtomically succeeds at the temp-write
stage but fails at the final os.Rename. That keeps cloud-credentials.json
writable (it lives at a different path) so the test only exercises the
persist-failure branch, not the cloud-credentials write branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/relayfile-cli/main.go`:
- Around line 1238-1250: The code currently lets --skip-workspace-refresh
silently override --workspace; after flag parsing validate that the two flags
are not used together by checking the parsed pointers workspaceFlag and
skipWorkspace (e.g., if *workspaceFlag != "" && *skipWorkspace) and return a
user-facing error or exit non-zero with a clear message stating that --workspace
and --skip-workspace-refresh are mutually exclusive. Add this check immediately
after the fs.Parse(...) succeeds (before any workspace/token refresh logic) so
the command fails fast on contradictory input.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: cd529b8d-7241-4082-b653-6af073b57bfc

📥 Commits

Reviewing files that changed from the base of the PR and between 264d89a and aad1a9c.

📒 Files selected for processing (2)
  • cmd/relayfile-cli/main.go
  • cmd/relayfile-cli/main_test.go

Comment thread cmd/relayfile-cli/main.go
Address CodeRabbit minor on relayfile#137: the two flags are
contradictory — --workspace says "refresh the JWT for this workspace",
--skip-workspace-refresh says "don't touch the workspace JWT at all".
Currently --skip-workspace-refresh silently wins, so

  relayfile login --workspace demo --skip-workspace-refresh

succeeds while leaving credentials.json unchanged, which is the exact
silent-success-with-stale-creds shape the rest of this PR is trying to
eliminate. Fail fast with a clear error immediately after fs.Parse.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant khaliqgant merged commit 1fe5fb0 into main May 11, 2026
6 of 7 checks passed
@khaliqgant khaliqgant deleted the agent-relay/login-refresh-workspace-token branch May 11, 2026 20:34
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