Skip to content

feature: prime cluster login and the k8s credential plugin - #808

Open
JannikSt wants to merge 4 commits into
mainfrom
feature/cluster-login-kubeconfig
Open

feature: prime cluster login and the k8s credential plugin#808
JannikSt wants to merge 4 commits into
mainfrom
feature/cluster-login-kubeconfig

Conversation

@JannikSt

@JannikSt JannikSt commented Jul 25, 2026

Copy link
Copy Markdown
Member

Targeting main because this repo does not use the develop-branch convention — it has no develop branch and merges PRs straight into main. (The platform-side PRs for this feature target develop as usual.)

Adds the researcher side of PrimeCluster node pools: a kubeconfig, and the credential plugin behind it.

  • prime cluster login <cluster> writes a kubeconfig with one context per pool the researcher has been granted, and an exec block instead of a token. Nothing credential-shaped is ever written to disk
  • prime auth k8s-token is the credential plugin kubectl invokes on every API call. It exchanges the platform API token for a short-lived ServiceAccount token scoped to the researcher's namespace

That indirection is what makes revocation mean something: revoking a grant deletes the namespace and its ServiceAccount, so the next refresh fails and any token already issued expires within the hour.

The plugin has a stricter contract than the rest of the CLI, because kubectl is the caller rather than a human:

  • stdout is protocol. Only the ExecCredential goes there; every message goes to stderr. Anything else on stdout and kubectl reports a confusing parse failure instead of the actual problem
  • Exit codes separate transient from permanent — 1 unreachable, 2 revoked, 3 rate limited, 4 platform auth expired, 5 ambiguous pool. Retrying a revoked grant will never work and callers shouldn't have to guess
  • Never prompts. The kubeconfig sets interactiveMode: Never; there may be no terminal at all

It talks to the platform with httpx directly rather than the shared APIClient. APIClient collapses every status into one APIError, and the entire failure contract here is a function of the status code.

Two things worth flagging:

The kubeconfig needs the apiserver URL and CA, which the mint endpoint doesn't return, so this depends on a new GET /api/v1/clusters/{name}/kubeconfig-info endpoint added in the platform PR. prime cluster login will fail against a platform that predates it.

A Typer app holding exactly one command promotes it to the group, which would have made prime auth k8s-token fail while prime auth silently ran the plugin — and that exact string is written into every kubeconfig we generate. Both groups now carry an explicit callback to prevent it, and the tests cover the wiring.


Note

Medium Risk
New authentication path invoked on every kubectl call; mistakes in stdout/exit-code contract or URL pinning would break cluster access or send users to the wrong platform.

Overview
Adds researcher Kubernetes access for granted Prime clusters: prime cluster login fetches cluster metadata from the platform and writes a per-cluster kubeconfig under ~/.prime/kube/ with one context per pool, each using an exec credential that calls prime auth k8s-token (no tokens on disk).

prime auth k8s-token implements the kubectl credential plugin contract: ExecCredential JSON only on stdout, errors on stderr, distinct exit codes for unreachable vs revoked vs rate-limited vs expired auth vs ambiguous pool, and direct httpx calls (not APIClient) so HTTP status drives behavior. Kubeconfig exec args/env pin --context and PRIME_API_BASE_URL so refreshes from kubectl use the same platform and API key as login.

Wires cluster and auth into the root CLI (with Typer group callbacks so prime auth k8s-token stays a real subcommand). login depends on GET …/kubeconfig-info on the platform; the plugin posts to …/kube-token.

Tests cover kubeconfig shape, context/base-URL pinning, plugin success path, and failure exit codes.

Reviewed by Cursor Bugbot for commit dbc59e4. Bugbot is set up for automated code reviews on this repo. Configure here.

JannikSt added 2 commits July 25, 2026 06:07
- `prime cluster login <cluster>` writes a kubeconfig with an exec block, one
  context per pool the researcher has been granted. No Kubernetes token is
  ever written to disk
- `prime auth k8s-token` is the credential plugin kubectl invokes on every
  call. It writes only the ExecCredential to stdout, messages to stderr, and
  uses distinct exit codes so callers can tell a transient failure from a
  permanent one
- Revoked access, expired platform auth, rate limits, an unreachable platform
  and an ambiguous pool each get their own exit code and message
- Talks to the platform with httpx directly rather than the shared APIClient,
  which collapses status codes into one error type and would lose the contract
transfer-bulk-failures.jsonl is written by the images-transfer-bulk test and
is not gitignored, so it got swept into the previous commit.
Comment thread packages/prime/src/prime_cli/commands/auth.py Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e0947ad575

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/prime/src/prime_cli/commands/auth.py Outdated
Comment thread packages/prime/src/prime_cli/commands/cluster.py Outdated
- the credential plugin now posts to /api/v1/clusters/{name}/kube-token;
  Config.base_url strips the prefix, so without it every call 404'd. A test
  pins the exact route string.
- prime --context X cluster login bakes --context X into the exec args, so
  refreshes from kubectl (where PRIME_CONTEXT is unset) hit the same
  platform the login did
@JannikSt

Copy link
Copy Markdown
Member Author

Review findings addressed (e550d3b):

  • the credential plugin now posts to /api/v1/clusters/{cluster}/kube-token — Config.base_url strips the /api/v1 suffix, so the previous URL 404'd on every call. Added a test asserting the exact route string
  • prime --context X cluster login now bakes --context X into the written exec args, so kubectl-triggered refreshes (which run without PRIME_CONTEXT) hit the same platform the login did. Tests cover both with and without a context

978 tests passing, ruff clean.

@cursor cursor Bot 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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e550d3b. Configure here.

Comment thread packages/prime/src/prime_cli/commands/cluster.py
Baking --context into the exec args regressed custom API URLs: with
PRIME_CONTEXT=production, every kubectl refresh reloads the built-in
production environment and forces base_url back to the public default,
ignoring a URL set via 'prime config set-base-url'. The login-time
resolved URL now rides in the exec block's env as PRIME_API_BASE_URL,
which outranks context resolution in Config.base_url — so refreshes hit
the same platform the login did, while --context still selects the
matching API key. Tests cover the custom-base-url + production-context
combination in both directions.
@JannikSt

Copy link
Copy Markdown
Member Author

Pushed dbc59e4 fixing the custom-base-url regression from the --context change:

  • The base URL resolved at login time is pinned into the kubeconfig exec env as PRIME_API_BASE_URL, which outranks context resolution in Config.base_url — so with --context production baked into the exec args, a refresh no longer snaps back to the public default when a custom URL was set via prime config set-base-url.
  • --context keeps working as before and still selects the matching API key at refresh time.
  • Tests cover the custom-base-url + production-context combination in both directions (context alone loses the URL; the exec env pins it).

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