Skip to content

fix(auth): review follow-ups: scopes exit 4 on empty refresh token, --readonly poll refuses before polling, envelope docs - #55

Merged
automagik-genie merged 2 commits into
mainfrom
fix/review-followups
Sep 26, 2026
Merged

automagik-genie merged 2 commits into
mainfrom
fix/review-followups

Conversation

@automagik-genie

Copy link
Copy Markdown
Collaborator

Follow-ups to the review of #50–#54.

1. docs/agent.md: JSON Error Envelope

The section said a failing command writes "nothing to stdout". That is false for --fail-empty: exit 3 still prints the empty JSON payload on stdout, and TestExecute_JSONErrors_EmptyResults asserts it. The corrected sentence says the envelope never goes to stdout, a command that fails before producing a result leaves stdout empty, and --fail-empty prints its empty payload first.

2. wk auth scopes: empty refresh token exits 4

A stored record with a blank refresh token reached InspectGrantedScopes, which returned its unexported missing-token error (internal/googleauth/token_scopes.go:54-55). WrapOAuthError then turned that into exit 1 (internal/cmd/auth_scopes.go). The command now checks the record itself and exits 4 (auth_required) with wk --client <c> auth add <email> --force-consent, like a missing or revoked token.

New tests (internal/cmd/auth_scopes_test.go):

  • TestAuthScopes_EmptyRefreshTokenExitsAuth runs the real inspector over a record with a blank refresh token. It expects exit 4, the fix command in the message, and kind: auth_required in the stderr envelope. The real inspector rejects the token before any network call.
  • TestAuthScopes_JSON_Source checks that the JSON source field is token_endpoint on the refresh path and tokeninfo on the fallback path.

3. auth poll --readonly over a token with no recorded scopes

Until now only the secrets layer tested this. The command-level test found a real gap: auth poll --readonly --email <e> polled the relay and called userinfo before the store-time merge check refused. The poll now runs the same pre-flight CheckReadOnlyMerge as auth add --readonly (shared helper refuseReadOnlyMerge). It exits 2 before any poll or OAuth round trip. Without --email the address is only known after the poll, so that path still refuses at store time. docs/auth.md says so.

New test: TestAuthPoll_Readonly_RefusesTokenWithoutRecordedScopesBeforePoll (internal/cmd/auth_readonly_hygiene_test.go). It expects exit 2, the "records no scopes" message with the --client hint, zero poll and zero userinfo calls, and the imported token left untouched.

docs/auth.md also now names source and the exit-4 case for a record without a refresh token.

Revert checks (each new test fails without its fix)

Reverted Test Result
internal/cmd/auth_scopes.go → origin/main TestAuthScopes_EmptyRefreshTokenExitsAuth FAIL exit = 1, want 4 (err=missing token)
internal/cmd/auth.go → origin/main TestAuthPoll_Readonly_RefusesTokenWithoutRecordedScopesBeforePoll FAIL no poll or OAuth round trip may run before the refusal (poll=1 userinfo=1)
"source" dropped from the JSON map TestAuthScopes_JSON_Source FAIL on both subtests (source = "", want "token_endpoint" / "tokeninfo")

All HTTP stays in fakes. No Google call is made with real credentials.

Gate

make ci at c3c3968 (throwaway HOME, WK_* unset, own TMPDIR, GOFLAGS=-timeout=45m because the race stage passes 10 min on the loaded host): rc 0, deadcode baseline check: OK, coverage total: 70.6% (min 70.0%).

🤖 Generated with Claude Code

namastex888 and others added 2 commits September 26, 2026 21:27
The JSON Error Envelope section said a failing command writes nothing to
stdout. That is false for --fail-empty: exit 3 still prints the empty
JSON payload on stdout, and TestExecute_JSONErrors_EmptyResults asserts
it. The envelope itself never goes to stdout; say that instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…before polling

`wk auth scopes` exited 1 when the stored record had an empty refresh
token: InspectGrantedScopes returned its unexported missing-token error,
which fell through to the generic OAuth wrapper. The command now checks
the record itself and exits 4 (auth_required) with the re-authorize
command, like a missing token.

`auth poll --readonly --email <email>` polled the relay and asked Google
for the account before the store-time merge check refused a stored token
that records no scopes. It now runs the same pre-flight check as
`auth add --readonly`, so the refusal (exit 2) comes before any poll or
OAuth round trip. Without --email the address is known only after the
poll, so that path still refuses at store time.

Tests:
- TestAuthScopes_EmptyRefreshTokenExitsAuth drives the real inspector
  over a record with a blank refresh token and expects exit 4.
- TestAuthScopes_JSON_Source asserts `source` is token_endpoint on the
  refresh path and tokeninfo on the fallback path.
- TestAuthPoll_Readonly_RefusesTokenWithoutRecordedScopesBeforePoll
  expects exit 2 with zero poll and userinfo calls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 26, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 76264997-15ab-4d4a-909e-6ea5da5aac84


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.

@automagik-genie
automagik-genie merged commit 7b69c54 into main Sep 26, 2026
12 checks passed
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.

2 participants