From f2a422b02f912f9d54aebeb3034c7c6a53df2367 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 18 Aug 2026 06:13:52 -0400 Subject: [PATCH] docs(auth): canonical scope strings in the two remaining stale lists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both lists predate the scope rename and would mislead anyone creating a key: CLAUDE.md's Authentication section still named the pre-rename scopes, and docs/Authentication.md's ops.alice example passed 'read,write', which GatewayScopes.ValidateScopes rejects outright. Same defect family as the Build/Test/Run sample fixed in a5f843c. Recorded as a follow-up: code review finding Server-012 claims it fixed the two CLAUDE.md lists on 2026-05-18, but neither correction was present — a Resolved finding is not re-examined, so the sibling Server-0xx doc resolutions want a spot-check for the same pattern. --- CLAUDE.md | 2 +- docs/Authentication.md | 2 +- docs/plans/2026-08-17-followup-closeout.md | 9 +++++++++ docs/plans/2026-08-17-followup-closeout.md.tasks.json | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 4cf30eb..898ab3f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -155,7 +155,7 @@ External analysis sources referenced by design docs: ## Authentication -Gateway gRPC clients authenticate with an API key in metadata: `authorization: Bearer mxgw__`. Keys are stored hashed (with a peppered SHA) in a gateway-owned SQLite DB (default `C:\ProgramData\MxGateway\gateway-auth.db`). Scopes (`session`, `invoke`, `event`, `metadata`, `admin`) gate specific RPCs; missing → `Unauthenticated`, insufficient → `PermissionDenied`. The `apikey` subcommand on the server exe manages keys; see `src/ZB.MOM.WW.MxGateway.Server/Security/Authentication/`. +Gateway gRPC clients authenticate with an API key in metadata: `authorization: Bearer mxgw__`. Keys are stored hashed (with a peppered SHA) in a gateway-owned SQLite DB (default `C:\ProgramData\MxGateway\gateway-auth.db`). Scopes (`session:open`, `session:close`, `invoke:read`, `invoke:write`, `invoke:secure`, `events:read`, `metadata:read`, `admin`) gate specific RPCs; missing → `Unauthenticated`, insufficient → `PermissionDenied`. The `apikey` subcommand on the server exe manages keys; see `src/ZB.MOM.WW.MxGateway.Server/Security/Authentication/`. Session event streaming is **owner-scoped**: the API key that opened a session is recorded on the session, and every `StreamEvents` attach/reattach is rejected with `PermissionDenied` unless the caller's key id matches the owner. Possessing the `event` scope and knowing a session id is not sufficient — this closes the reconnect/fan-out trust boundary (detach-grace and replay retention are on by default) so an `event`-scoped key cannot attach to another key's retained session. diff --git a/docs/Authentication.md b/docs/Authentication.md index bc59c3e..02c1206 100644 --- a/docs/Authentication.md +++ b/docs/Authentication.md @@ -260,7 +260,7 @@ Examples: ```bash mxgateway apikey init-db -mxgateway apikey create-key --key-id ops.alice --display-name "Alice (ops)" --scopes read,write +mxgateway apikey create-key --key-id ops.alice --display-name "Alice (ops)" --scopes invoke:read,invoke:write mxgateway apikey create-key --key-id area1.reader --display-name "Area 1 reader" --scopes invoke:read,metadata:read --read-subtree "Area1/*" --browse-subtree "Area1/*" mxgateway apikey create-key --key-id ops.temp --display-name "Temp contractor" --scopes invoke:read --expires 90d mxgateway apikey create-key --key-id team-a.svc --display-name "Team A service" --scopes session:open,invoke:read --dashboard-tags team-a diff --git a/docs/plans/2026-08-17-followup-closeout.md b/docs/plans/2026-08-17-followup-closeout.md index 8420480..4847a40 100644 --- a/docs/plans/2026-08-17-followup-closeout.md +++ b/docs/plans/2026-08-17-followup-closeout.md @@ -496,6 +496,15 @@ Follow-ups recorded, not started: - The ack-leg probe stays blocked; unblock paths are in `docs/AlarmProbeFindings.md`. - The dashboard `AlarmsPage` truncation banner is still poll-driven — it could consume the new `snapshot_status` feed frame instead. +- **A closed code-review finding regressed, or was never applied.** Server-012 + (`code-reviews/Server/findings.md:405-412`) is recorded *Resolved 2026-05-18* and claims + it corrected two scope lists to the canonical `*:*` strings — the `CLAUDE.md` + Build/Test/Run `apikey` sample and the `CLAUDE.md` Authentication-section scope list. + Neither correction was present when this branch looked; both were re-fixed here, along + with a third instance the finding never covered (`docs/Authentication.md`'s `ops.alice` + example). The bookkeeping is the follow-up: other `Server-0xx` entries marked Resolved + with documentation-only fixes should be spot-checked for the same pattern, since a + finding that reads Resolved is not otherwise re-examined. Explicitly decided, not an omission: **`../scadaproj/CLAUDE.md` needs no update.** The umbrella index records the *set* of `.proto` files this repo owns, and that set is diff --git a/docs/plans/2026-08-17-followup-closeout.md.tasks.json b/docs/plans/2026-08-17-followup-closeout.md.tasks.json index 3acff2d..91d83d9 100644 --- a/docs/plans/2026-08-17-followup-closeout.md.tasks.json +++ b/docs/plans/2026-08-17-followup-closeout.md.tasks.json @@ -9,7 +9,7 @@ {"id": 6, "subject": "Task 6: ApiKeysPage — DashboardTags in ConstraintText + create-form input", "status": "completed", "commits": ["c037d99", "fab600d"], "review": "Spec compliant; code review Approved after dedupe/help-text fix, re-review Approved"}, {"id": 7, "subject": "Task 7: Wnwrap alarm-probe retry — secured-write path (windev)", "status": "completed", "commits": ["90331b6", "540a118"], "review": "Approved after ack-comment fix; Q2 answered (@COUNT = records-in-reply, exact detection refuted), clear/re-raise GUID answered (new instance), ack leg re-blocked (accepted-but-inert)"}, {"id": 8, "subject": "Task 8: Windev full verification", "status": "completed", "verifiedAt": "90331b6", "result": "slnx 0W/0E; worker x86 523 pass + 1 pre-existing deterministic failure (reproduces on main); gateway 1151/1151 on rerun; live smoke 8/8; check-codegen 1-3 pass, Check 4 blocked by pre-existing Windows .exe pin bug (substance validated out-of-band); final comment-only tip re-check pending after bookkeeping", "residual": "pending-external: cheap windev tip re-build covering the comment/prose-only commits landed after 90331b6"}, - {"id": 9, "subject": "Task 9: Bookkeeping — follow-ups closure + plan record", "status": "completed", "commit": "self (this bookkeeping commit)", "review": "None (trivial classification); closes the prior plan's follow-up block, appends the as-built record, and corrects the CLAUDE.md apikey sample"} + {"id": 9, "subject": "Task 9: Bookkeeping — follow-ups closure + plan record", "status": "completed", "commits": ["a5f843c", "self (follow-up bookkeeping commit, immediately after a5f843c)"], "review": "None (trivial classification); a5f843c closes the prior plan's follow-up block, appends the as-built record, and corrects the CLAUDE.md apikey sample; the follow-up commit closes two adjacent stale scope lists (CLAUDE.md Authentication section, docs/Authentication.md ops.alice example) and records the regressed Server-012 resolution as a follow-up"} ], "lastUpdated": "2026-08-18" }