Skip to content

feat(lightning_cloud): read the credential per request and add a PKCE login behind a switch - #234

Merged
fnwoke-lightning merged 12 commits into
mainfrom
fnwoke/auth-m4-9-10-vendor
Nov 6, 2026
Merged

fnwoke-lightning merged 12 commits into
mainfrom
fnwoke/auth-m4-9-10-vendor

Conversation

@fnwoke-lightning

@fnwoke-lightning fnwoke-lightning commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Why

The SDK picks its credential once, when the client is built, so a rotated token file or a refreshed login never reaches a running process, and it still sends Basic auth and legacy API keys. This PR moves the vendored lightning_cloud to one credential source read on every request, and adds a PKCE login with keychain storage beside the current browser login, behind LIGHTNING_CLI_OIDC_LOGIN. The current login stays the default, so a release from main logs in as today.

lightning_cloud is vendored into the SDK, and these files are edited here directly.

Based on SDK main at 572b60da (#233).

What

  • cli_login.py, credentials.py, and updated env.py, login.py, rest_client.py in python/lightning_sdk/lightning_cloud/. keyring added to the dependencies.
  • One credential source, read per request, in this order: LIGHTNING_AUTH_TOKEN_FILE (re-read each request), LIGHTNING_AUTH_TOKEN, the new login, then the saved interim sess_. Bearer only.
  • LIGHTNING_API_KEY is gone from the credential path: neither an environment key nor an api_key saved in credentials.json is ever sent. Auth loses its api_key field, the "api_key" header override and Keys.API_KEY. Auth.save still accepts and ignores token= and api_key=, because main's interim monkeypatch passes them; feat(cli): ship the PKCE login and auth commands #235 removes both with the patch.
  • LIGHTNING_CLI_OIDC_LOGIN unset (the default): the interim sess_ browser login stays the login, with a state check and a 5-minute timeout. Set: the PKCE login through the lightning-cli client, storing the login in the OS keychain, or with --no-keychain in a file only the user can read, refresh-token rotation under a cross-process lock, and the exact reuse message. No org or project hints on the authorize URL; those come in a follow-up.
  • A replaced login is revoked only after the new one is saved, whichever kind it was, and a failed revoke is reported on stderr. Logout revokes each kind independently, always forgets local state (including a login whose keychain entry can't be read), and reports what failed.
  • A 401 refreshes and resends once. User-Agent is lightning-sdk/<version>.
  • A LIGHTNING_AUTH_TOKEN_FILE that exists but can't be read (a directory, no read permission) raises a LoginError naming the variable and the path, instead of a bare OSError. A missing file still falls through to the next credential.
  • The token, revoke and logout calls and the interim login's /sign-in check pass verify=env.SSL_CA_CERT, the CA bundle the generated client uses, so login and logout work where only SSL_CERT_FILE is set.
  • AuthServer and logger stay importable, so main's interim monkeypatch in cli/utils/auth.py keeps working until feat(cli): ship the PKCE login and auth commands #235 removes it. Four main CLI checks that read Auth.api_key now read auth_token only.
  • CI's "Login passthrough" step checks that lightning login is a no-op with a dummy LIGHTNING_AUTH_TOKEN instead of LIGHTNING_API_KEY, which is now ignored. The interim login's no-browser error points at LIGHTNING_AUTH_TOKEN too.
  • Tests: a login test harness in python/tests/lightning_cloud/ (fake platform, keyrings, multi-process worker), with cases for both switch states, the per-request source, refresh, logout and replaced logins. Other test changes only move mock targets.

Notes

@fnwoke-lightning fnwoke-lightning added the vendoring Intentionally updates vendored files and bypasses the vendored Cloud guard label Nov 4, 2026
Copy the per-request credential source and PKCE login from grid's lightning-cloud package into the SDK's vendored copy, and switch the CLI to the vendored login.
@fnwoke-lightning
fnwoke-lightning force-pushed the fnwoke/auth-m4-9-10-vendor branch from 385e971 to 5867dfa Compare November 4, 2026 19:03
fnwoke-lightning and others added 3 commits November 4, 2026 18:01
A release from main must keep logging in on production, which serves only
the interim login until relaunch. A new login is the interim one unless
LIGHTNING_CLI_OIDC_LOGIN is set, read when the login starts.

- Restore AuthServer with get_auth_url(port) and login_with_browser(auth).
  It sends state on the /sign-in redirectTo, adds caller sign-in params,
  refuses a callback whose state doesn't match, saves the sess_ as
  auth_token with Auth.save, and redirects with no credential in the URL.
- Auth.save accepts and ignores token again, writes a 0600 file.
- credentials: CredentialKind, Credential, resolve(), refresh(token) for
  the token a request sent, start_login() dispatching on the switch with
  LoginUnavailable for options the interim login can't honour, and
  logout() that revokes each saved kind and reports which revokes failed.
- A login that saves revokes the login it replaced, after the save:
  /oidc/revoke for a new login, /v1/auth/logout for a sess_.
- Both browser logins stop after five minutes with no callback.
- Reuse is detected only from the exact error_description.
- The source's own login goes through Auth.authenticate, so main's
  browser_authentication(False) still keeps resource commands from
  opening a browser.
- Restore llm_api.py, cli/entrypoint.py, cli/legacy/entrypoint.py and
  cli/utils/auth.py to main. Their changes belong to sdk#235.

Co-authored-by: Cursor <cursoragent@cursor.com>
Port grid's fake platform, fake browser, keyrings and login worker under
tests.lightning_cloud, and extend the fake platform with the interim
/sign-in to /login-complete flow and POST /v1/auth/logout.

The conftest overrides the SDK's autouse threading.Thread mock, clears the
SDK's dummy LIGHTNING_API_KEY and LIGHTNING_AUTH_TOKEN, and puts back the
vendored interim login that main's CLI replaces when imported.

New cases cover the interim login, the switch at every entry point, the
options only the new login has, replacing either kind of login with
either kind, logout of both kinds, the five minute stop, and the exact
reuse text.

Co-authored-by: Cursor <cursoragent@cursor.com>
…n is switched on

Co-authored-by: Cursor <cursoragent@cursor.com>
fnwoke-lightning and others added 5 commits November 4, 2026 22:16
Co-authored-by: Cursor <cursoragent@cursor.com>
… failed revokes on login

Co-authored-by: Cursor <cursoragent@cursor.com>
…g OSError

Co-authored-by: Cursor <cursoragent@cursor.com>
…sign-in calls

Also applies ruff-format to test_replaced_login.py, which failed pre-commit.

Co-authored-by: Cursor <cursoragent@cursor.com>
@fnwoke-lightning
fnwoke-lightning marked this pull request as ready for review November 5, 2026 15:13
@fnwoke-lightning fnwoke-lightning changed the title chore: vendor the M4-9/M4-10 lightning_cloud changes feat(lightning_cloud): read the credential per request and add a PKCE login behind a switch Nov 5, 2026
…he API key is ignored

The interim login's headless error now points at LIGHTNING_AUTH_TOKEN too.

Co-authored-by: Cursor <cursoragent@cursor.com>
@fnwoke-lightning fnwoke-lightning self-assigned this Nov 5, 2026
The flag keeps the login in a file only the user can read instead of the OS
keychain; the new name says that without alarming users.

Co-authored-by: Cursor <cursoragent@cursor.com>
@fnwoke-lightning
fnwoke-lightning merged commit 485ecc9 into main Nov 6, 2026
26 checks passed
@fnwoke-lightning
fnwoke-lightning deleted the fnwoke/auth-m4-9-10-vendor branch November 6, 2026 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

vendoring Intentionally updates vendored files and bypasses the vendored Cloud guard

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants