Skip to content

fix(auth): read with a personal access token; refuse a grid key that can only send telemetry - #13

Closed
dankoverride wants to merge 5 commits into
mainfrom
fix/accept-personal-access-token
Closed

dankoverride wants to merge 5 commits into
mainfrom
fix/accept-personal-access-token

Conversation

@dankoverride

@dankoverride dankoverride commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Read with a personal access token; refuse a grid key that can only send telemetry.

Fixes Bug 3702; PBI 3703 (ADO, Feature 2232 API Security). The token screen it depends on is PBI 3704. All three precede CR-1's release (3679) and SP-065 PBI 4 (3242).

Why

DeepCube's CR-1 (App.Http PR 4556) makes grid API keys created or rotated from its release on otlp-only: they can send telemetry and nothing else. This server exchanges a grid key for a token at startup and makes every read with it, so with a new or rotated key all 25 read calls return 403. Keys created before CR-1 carry member and keep working until rotated; the planned key renewal (SP-065) would convert every key to otlp at once.

What changes

  • IF_Token: a personal access token bound to one grid (scp=member, gsid), used as it is, with no exchange. The credential to use from now on.
  • IF_ApiKey still works for a key made before CR-1.
  • A token that names its scopes without member is refused at startup with what to use instead, not left to fail every tool call. A token not bound to a grid is refused the same way; one that names no scopes is left to the API.
  • Both or neither set: refused, naming IF_Token.
  • README and the dev .vscode/mcp.json use IF_Token.

Draft: do not merge or release yet

The README tells users to create the token on the grid's page in the portal. That screen does not exist yet: the API can mint a grid-bound PAT (POST tokens/personal-access), but the web app has no way to create one. It is being built in App.Http. This PR merges and releases with it, and both before App.Http releases CR-1 (3.188.0 or later, held until then).

dck_p_ handles (SP-126) are not here: there is nothing to exchange them against until that spike is approved.

Tests

Eight new bootstrapper cases, written first. The old "throws" tests never awaited their assertion, so they could not fail; they are now one awaited case per blank value. With the scope check removed, the three refusal tests fail; restored, all 94 pass.

🤖 Generated with Claude Code

dankoverride and others added 2 commits October 12, 2026 23:59
…can only send telemetry

DeepCube's CR-1 (App.Http PR 4556) makes grid API keys created or rotated from now on otlp-only: they
may send telemetry and nothing else. This server exchanged a grid key for a token at startup and made
every read with it, so with a new or rotated key all 25 read calls would return 403.

- IF_Token: a personal access token bound to one grid (scope member, claim gsid), used as it is with
  no exchange. This is the credential to use from now on.
- IF_ApiKey still works for keys created before CR-1, which carry member, until they are rotated.
- A token that names its scopes without member is refused at startup, with what to use instead,
  rather than failing every tool call later. A token not bound to a grid is refused the same way. A
  token that names no scopes is left to the API.
- Setting both, or neither, is refused with a message naming IF_Token.
- README and the dev .vscode/mcp.json use IF_Token.

Tests first: eight new bootstrapper cases. The old "throws" tests never awaited their assertion and
so could not fail; they are now one awaited case per blank value. With the scope check removed, the
three refusal tests fail; restored, all 94 pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… of a stack trace

api-azure.deepcube.ai no longer resolves (retired 2026-11-04), so every client on
the defaults crashed at start and the MCP client only showed "connection closed".
web.deepcube.ai is the single API host. IF_BaseUrl still overrides it; a blank
value now means unset, and a trailing slash is trimmed.

A missing or unusable credential, or an unreachable API, now prints one line on
stderr naming the host or the fix, and exits 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ETWOYA
ETWOYA previously approved these changes Nov 4, 2026
The package gate grepped for "API Key was not provided", which this branch
reworded to "No credential was provided", so the gate failed from the first
commit. It now also checks exit code 1 and that the failure is one plain line,
not a stack trace.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dankoverride and others added 2 commits November 4, 2026 16:52
The portal has no screen for personal access tokens yet (PBI 3704), so step 1
pointed at something that does not exist. It now shows the interim route: sign
in on the API help page and call POST /tokens/personal-access with scope
member, the grid's ID and a 30-day lifetime (90 days is the most allowed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The API help page has no sign-in (no security scheme, empty OAuth config), so
the route added in 8c9d17d could not be followed. Say what is true until the
portal token screen ships (PBI 3704): a grid key created before October 2026
still reads through IF_ApiKey; otherwise ask support for a token. Also drop
the last em dash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants