Visitar URL original
feat(auth): read the token from a file descriptor and print grant error codes by tkkhq · Pull Request #479 · Kong/volcano-cli · GitHub
Skip to content

feat(auth): read the token from a file descriptor and print grant error codes - #479

Open
tkkhq wants to merge 21 commits into
feat/grant-migration-runsfrom
feat/grant-token-fd
Open

tkkhq wants to merge 21 commits into
feat/grant-migration-runsfrom
feat/grant-token-fd

Conversation

@tkkhq

@tkkhq tkkhq commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Tracking

Why

  • The CLI parses the code in Hosting's error bodies but never prints it, so a Builder worker has to match message text to tell grant_budget_exhausted, grant_reserved_variable, grant_permission_missing, grant_route_not_allowed, rate_limit_exceeded and delegated_grant_required apart.
  • R11: any process the model left running in the VM can read the CLI's environment, so a grant in VOLCANO_TOKEN is exposed while the CLI runs, and every process the CLI starts inherits it.

Summary

  • error codes, grant only: when the command ran with a delegated grant and the API error has a code, the CLI prints one more line after the error, Error code: <code>. Nothing else is reworded, and every other credential sees errors exactly as before. I chose this over appending (<code>) to every error, which would change the text for all users
  • add VOLCANO_TOKEN_FD=<n> (internal/config/token_source.go). At startup, before anything reads the configuration, main reads the token from that descriptor up to the first newline (16 KiB cap), so a writer that keeps its end open does not hold the CLI up, and unsets the variable. A descriptor of 3 or more is opened and closed after the read. 0 reads stdin through os.Stdin and leaves it open, so the number can't pass to the next file the CLI opens; 1 and 2 are refused. This one option also covers "token on stdin". I chose it over --token-stdin because the CLI takes its credential from env vars, and several commands already read stdin for their own input
  • a grant in VOLCANO_TOKEN is moved into memory and removed from the CLI's environment at startup, so processes the CLI starts (the telemetry flush, git, docker, the updater) don't inherit it. Other tokens stay in VOLCANO_TOKEN, because the telemetry flush reads an account token from there
  • refused at startup with exit 2, without echoing what was read: setting both VOLCANO_TOKEN_FD and VOLCANO_TOKEN, a bad descriptor number, or an empty or oversized read
  • local mode ignores the adopted token, as it ignores VOLCANO_TOKEN
  • limit, for the worker: on Linux, unsetting a variable does not change /proc/<pid>/environ, which still shows the CLI's starting environment to same-user processes. Only VOLCANO_TOKEN_FD keeps the grant out of the CLI's environment entirely, so the worker should use it
  • a run on a token taken into memory (any token from VOLCANO_TOKEN_FD, or a grant from VOLCANO_TOKEN) sends no telemetry event. The flush process can't see that token, and would otherwise send the saved login's token with the event
  • docs: docs/authentication.md describes VOLCANO_TOKEN_FD and the code line
  • changed in review: an earlier version of this PR appended the code to every API error for every credential. It now prints the code line under a grant only

Verification

  • go build ./...
  • make check (openapi-generated-check, release-workflow-check, lint with 0 issues, test)
  • TestGrantErrorPrintsTheAPICode (the code line follows the unchanged error under a grant) and TestNonGrantErrorPrintsNoCodeLine
  • TestAdoptTokenReadsTheDescriptorAndClosesIt, TestAdoptTokenTakesAGrantOutOfTheEnvironment (both run env as a child process and check the token is absent), TestAdoptTokenLeavesOtherTokensInTheEnvironment, TestAdoptTokenRefusals (including descriptors 1 and 2)
  • TestAdoptTokenStopsAtTheFirstNewline (the writer stays open after pg-…\n; fails on a 5 s timeout) and TestAdoptTokenReadsStdinAndLeavesItOpen (stdin still reads what follows the token's line)
  • TestRecord_AdoptedTokenSendsNothing and the adopted-grant case of TestConnectRefusesALoginThatVolcanoTokenWouldOverride
  • built the binary with VOLCANO_API_URL on a closed port: VOLCANO_TOKEN_FD=2 prints the refusal (exit 2), and 3< <(echo pg-x; sleep 5) returns at once
  • the descriptor tests live in _unix_test.go files and pass a dup'd descriptor that no *os.File owns. Passing a pipe's own Fd() made two owners of one descriptor, and the second close hit an HTTP socket that reused the number (seen once in make check). Ran go test -count=5 ./internal/config ./cmd/volcano after the fix, and GOOS=windows go vet on both packages
  • TestGrantFromATokenDescriptor runs cloud functions list through the real command tree with the grant on a pipe and VOLCANO_TOKEN unset, and checks the request carried it
  • built the binary and ran VOLCANO_TOKEN_FD=3 volcano cloud functions list 3<<<"pg-…" (a fake grant), with VOLCANO_TOKEN unset, against a local recording server: exit 0, and the request carried Bearer pg-…

Decisions for Ted

  • the code is printed as its own line (Error code: <code>), not inside the error line, so no existing text changes. If the worker would rather parse Error (<code>): …, that is a one-line change

@tkkhq tkkhq changed the title feat(auth): read the token from a file descriptor and print API error codes feat(auth): read the token from a file descriptor and print grant error codes Nov 12, 2026
@tkkhq
tkkhq marked this pull request as ready for review November 13, 2026 12:23
@tkkhq
tkkhq requested a review from a team as a code owner November 13, 2026 12:23
Copilot AI balanced review requested due to automatic review settings November 13, 2026 12:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Unresolved issues cause incorrect grant-error labeling for local requests, omit API codes from HTTP 426 responses, and can hang configuration tests on systems with small pipe buffers.

3 open issues
What changed in this PR

This PR extends delegated-grant support with file-descriptor token input and grant-specific API error codes, helping workers handle credentials safely and distinguish failures.

Changes:

  • Adopt tokens into memory at startup and prevent child processes from inheriting adopted credentials.
  • Print API error codes for delegated grants and skip telemetry events for adopted tokens.
  • Update authentication checks, documentation, and tests for the new token source.
File Description
internal/​telemetry/​telemetry.go Skip events when a token was adopted.
internal/​telemetry/​telemetry_test.go Test telemetry suppression for adopted tokens.
internal/​config/​token_source.go Read, validate, and adopt descriptor or grant tokens.
internal/​config/​token_source_unix_test.go Test descriptor lifecycle, input limits, and stdin handling.
internal/​config/​token_source_test.go Test environment handling and invalid token-source settings.
internal/​config/​config.go Resolve adopted tokens before environment or saved credentials.
internal/​cmd/​connect/​connect.go Recognize adopted tokens in login checks.
internal/​cmd/​connect/​connect_test.go Cover connect refusals with adopted grants.
internal/​cmd/​auth/​auth_test.go Update expected grant-login guidance.
internal/​auth/​auth.go Mention descriptor input in grant-login guidance.
docs/​authentication.md Document descriptor input and grant error-code output.
cmd/​volcano/​main.go Adopt tokens at startup and render grant error codes.
cmd/​volcano/​grant_unix_test.go Verify descriptor grants authenticate command requests.
cmd/​volcano/​grant_test.go Test grant-only error-code output.

Review effort: Balanced

Comment thread cmd/volcano/main.go Resolved
Comment thread cmd/volcano/main.go Resolved
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