Skip to content

PRO-1042: route Cursor plugin login through typed CLI auth - #9

Merged
rares04 merged 3 commits into
mainfrom
pro-1042-typed-cli-auth
Aug 30, 2026
Merged

PRO-1042: route Cursor plugin login through typed CLI auth#9
rares04 merged 3 commits into
mainfrom
pro-1042-typed-cli-auth

Conversation

@rares04

@rares04 rares04 commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Keep working credentials from LUA_API_KEY, ~/.lua-cli/credentials, and .env unchanged. This includes non-dotted legacy keys.
  • Send new login to lua auth configure in a private terminal. lua-cli 3.28.0 and later issue a typed personal credential after the user selects an organization, one or more agents, and a role. Builder remains the default role.
  • Stop collecting email addresses, OTPs, and raw credentials in the Cursor conversation. The shell hook denies model-run lua auth configure, and lua auth key* remains denied.
  • Remove the unsupported literal ${env:LUA_API_KEY} from both Cursor MCP registration paths. The MCP process inherits the real environment and can fall back to the CLI credentials file or .env.
  • Identify direct MCP HTTP requests as cursor-plugin/1.1.0. Calls that spawn lua-cli use the CLI's own versioned identity.
  • Update the setup guide, tester guide, security contract, and MCP examples. Lints reject both the old secret-bearing auth commands and the literal MCP environment interpolation.
  • Release Cursor plugin 1.1.0 on merge. A consistency lint keeps the package, manifest, MCP, and telemetry versions aligned.

Source-derived caller inventory

The inventory came from a repository-wide rg before editing.

  • skills/lua-auth/SKILL.md, skills/lua-doctor/SKILL.md, and the auth preflight in skills/lua-init/SKILL.md own setup.
  • lib/credentials.mjs and mcp/lua-platform/src/auth.mjs resolve LUA_API_KEY, the CLI credentials file, and .env. This PR does not change their order or formats.
  • scripts/install.mjs and mcp.json both register the bundled MCP server. Both now omit the unsupported credential placeholder.
  • mcp/lua-platform/src/tools/list-agents.mjs and get-agent.mjs spawn lua agents --json. Those requests use cli/<version>.
  • mcp/lua-platform/src/api-client.mjs owns direct Lua API requests for deployment status, primitive versions, and logs. Those requests now use cursor-plugin/1.1.0, which lua-core-services #2183 recognizes as a bounded family.

Merge gate

Merge only after npm view lua-cli version reports 3.28.0 or later. The current PR head must also have green CI and current-head approval.

This PR does not rotate, revoke, rewrite, or invalidate an existing credential. It does not use work from the closed #2008 prototype.

Verification

  • npm run lint
  • npm test -- --coverage (249 tests)
  • node scripts/check-coverage.mjs
  • MCP npm test (83 tests)
  • MCP npm run build
  • node scripts/check-bundle-size.mjs

Linear: PRO-1042

@rares04

rares04 commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

Dependency update: lua-core-services #2183 must merge and deploy before this draft can release. Direct api-client.mjs requests now identify as cursor-plugin/<package version>; Lua CLI subprocesses keep cli/<lua-cli version>. Focused tests also fail if a new raw HTTP caller bypasses the identified wrapper.

@rares04
rares04 marked this pull request as ready for review August 30, 2026 12:38
@rares04
rares04 requested review from richard-lua August 30, 2026 12:38

@richard-lua richard-lua 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.

Code review — MEDIUM risk

The security direction is solid: this PR removes credential/OTP collection from the model conversation, routes new logins to lua auth configure in a private terminal, denies model-run lua auth configure in before-shell-execution.mjs (with matching tests and lint guards), removes the unsupported ${env:LUA_API_KEY} MCP literal, and adds structural lints so the old secret-bearing flows can't regress. The permission-template, hook, doc, and lint changes are internally consistent and well-tested. Two things keep this at medium: a hardcoded client-version header that diverges from the value the new test derives, and the fact that the added X-Lua-Client header ships ahead of the backend per the PR's own release gate. Respect the draft/release gate before merge.

Major

  • mcp/lua-platform/src/api-client.mjs:38X-Lua-Client is hardcoded to 'cursor-plugin/1.0.0', but tests/api-client.test.mjs asserts it equals cursor-plugin/${package.json.version}. This only passes while the version is exactly 1.0.0; the release gate calls for a version bump, which will both break the test and mislabel traffic as 1.0.0. Derive the version from package.json (a build-time constant) so header and test stay in lockstep.

Minor

  • mcp/lua-platform/src/api-client.mjs:38 — The header is now sent unconditionally, but the PR body says direct api-client traffic should stay unlabeled until the backend (lua-core-services #2171) accepts the cursor-plugin family. Confirm the backend ignores unknown X-Lua-Client values and keep this blocked behind the stated release gate; otherwise every MCP tool call could fail until #2171 deploys.
  • mcp/lua-platform/tests/api-client.test.mjs:70 — The "all direct API calls behind the wrapper" test greps for fetch(/fetchFn(. A future tool using undici, node:http, or an aliased fetch would evade the regex and silently pass. Note the limitation in a comment or extend it to flag http/https/undici imports under src/tools/.

Otherwise the change looks well-scoped and safe once the release gate clears.


PR Risk Reviewer — automated senior review of 37046a4 · risk: medium · confidence: 0.78

richard-lua
richard-lua previously approved these changes Aug 30, 2026

@richard-lua richard-lua 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.

Code review — MEDIUM risk

Solid security-hardening change: login now runs lua auth configure in a private terminal, the model is blocked from running it via both the permission template and the before-shell-execution hook, and email/OTP/raw-key collection is removed from the conversation surface. Lint and test coverage back the new invariants, and the docs are updated consistently. The findings below are advisory — the main one is a hardcoded client-version string that will drift the moment the plugin version is bumped (which the release gate requires).

Major

  • mcp/lua-platform/src/api-client.mjs:38X-Lua-Client is the literal 'cursor-plugin/1.0.0', but api-client.test.mjs asserts it equals cursor-plugin/${package.json version}. They match only because the root package is at 1.0.0; the required pre-release version bump will break the test and ship a stale client version to the backend that's being taught to accept the cursor-plugin family. Derive the version from package.json (runtime read or build-time constant) instead of freezing it.

Minor

  • scripts/lint-cli-flags.mjs:31 — the new lua auth configure --email / --api-key denylist entries are only self-excluded for lint-cli-flags.mjs. With scripts now in SCAN_DIRS, any future lint/doc that must name these forbidden patterns will trip the denylist. Exclude all scripts/lint-*.mjs or encode the literals non-matchingly.
  • mcp/lua-platform/tests/api-client.test.mjs:70 — the "single choke point" guard greps src for /\b(?:fetch|fetchFn)\s*\(/. A comment, a prefetch( helper, or an aliased fetch could produce false results either way. Assert the structural invariant (every tool imports apiRequest) rather than token-scanning.
  • mcp.json:4 — dropping the MCP env block silently changes how the spawned server obtains credentials; it now relies on Cursor passing through the parent environment plus the credentials-file/.env fallbacks. Verify Cursor inherits the shell env (or document that LUA_API_KEY-only users need the credentials file), and have a tester validate the env-only path before release.

Note: the PR body's own instruction to keep this in draft until the CLI/backend dependencies ship is respected here — do not merge ahead of those gates.


PR Risk Reviewer — automated senior review of 37046a4 · risk: medium · confidence: 0.80

@richard-lua richard-lua 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.

Code review — LOW risk (re-review of 48870ed)

Previously flagged

  • X-Lua-Client version hardcoded, drifts from package.json — resolved. The header is now cursor-plugin/1.1.0 matching the root version bump, and the new scripts/lint-release-version.mjs enforces that api-client.mjs, server.mjs (name + plugin_version ×2), .cursor-plugin/plugin.json, and the MCP package.json all agree with package.json's version. The test derives the expected header from package.json, so header and test now move in lockstep and future bumps fail loudly if any file lags.
  • X-Lua-Client sent before backend accepts it — resolved (as a process gate). Still sent unconditionally, but the thread now names lua-core-services #2183 as a hard release-gate dependency and the PR remains draft. Confirm the backend ignores unknown X-Lua-Client values before release.
  • Directory-scan test is brittle — still open. The wrapper-coverage test continues to token-scan src/ for fetch(/fetchFn(; a future node:http/undici/aliased-fetch caller would evade it silently. Minor, non-blocking.

Assessment

The security direction remains solid and the new commits are clean: version metadata is now consistent and lint-enforced, the hook/permission/doc/lint changes are internally coherent and well-tested, and the release gate is explicit. Nothing new raises the risk. The remaining items are advisory test-robustness and env-passthrough notes.

Minor

  • mcp/lua-platform/tests/api-client.test.mjs:70 — the "every direct Lua API call behind the identified wrapper" guard token-scans for fetch(/fetchFn(. A future tool using node:http, undici, or an aliased fetch evades the regex. Assert the structural invariant (every src/tools/*.mjs imports apiRequest; no http/https/undici import under src/) or document the limitation.
  • scripts/lint-cli-flags.mjs:30scripts is now scanned and the auth-flow deny patterns are literals, but only lint-cli-flags.mjs is self-excluded. A future guard script that must name lua auth configure --email/--api-key would trip the denylist. Exclude all scripts/lint-*.mjs or encode the literals non-matchingly.
  • mcp.json:4 — dropping the env block means the spawned MCP server relies on Cursor passing through the parent environment plus the credentials-file/.env fallbacks. Verify Cursor inherits the shell env for spawned servers (or document that LUA_API_KEY-only users need the credentials file/.env), and have a tester validate the env-only path.

Respect the PR's own release gate (lua-core-services #2183 + published lua-cli 3.28.0) — do not merge ahead of those dependencies.


PR Risk Reviewer — automated senior review of 48870ed · risk: low · confidence: 0.82


PR Risk Reviewer — automated senior review of 48870ed · risk: low · confidence: 0.82 · re-review

@rares04
rares04 merged commit 02dda80 into main Aug 30, 2026
7 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