mirror of
https://github.com/Sea-Haven-Industries/sh-mcp.git
synced 2026-10-05 10:42:02 +00:00
Fold in Gemini (round-3, third model family) auth findings
- Gemini-BLOCK-1: AllowedOAuthScopes strictly filtering a V2 pre-token Lambda's output is unverified -> fatal Phase-0a check (§6 #8a); if it fails, pre-token fail-closed becomes the primary boundary. - Gemini-BLOCK-2: Cognito access tokens carry client_id/scopes, not native aud -> align §1h + facade/server checks to client_id allow-list / scope-prefix audience proxy. - Gemini-Q: 0a spike must run on production-equivalent Enterprise Grid + real licenses. - Gemini-NIT (path-corrected): project memory is a private store at ~/.claude/.../memory/, not the repo and not Gemini's own ~/.gemini path. Three model families now converge: structural plan sound; only open risk is the auth token-mint mechanism, fully spike-gated in Phase 0a.
This commit is contained in:
parent
70987522b2
commit
9cf124a24b
1 changed files with 45 additions and 14 deletions
|
|
@ -144,8 +144,13 @@ credential that requests **only its tier's scopes**. Mechanism (specified, testa
|
|||
Finance client → `finance:read`; Lauren Exec client → `ops:read ops:tasks gmail:self calendar:self` (**never
|
||||
finance**). Cognito's token endpoint **cannot issue a scope outside a client's `AllowedOAuthScopes`** — so even
|
||||
though Lauren-the-person holds `finance:read` (via `-finance@`), the Exec client can never obtain a token
|
||||
carrying it. This is the boundary — it does NOT depend on the pre-token Lambda, and it is independent of
|
||||
design.md §2.3's group→scope union.
|
||||
carrying it. This is the intended boundary — independent of design.md §2.3's group→scope union.
|
||||
**CAVEAT (Gemini round-3 BLOCK — UNVERIFIED, fatal Phase-0a check):** this rests on Cognito **strictly
|
||||
filtering the issued token's scopes to the client's `AllowedOAuthScopes` even when a pre-token V2 Lambda
|
||||
runs**. In some Cognito configs a V2 pre-token Lambda can *return scopes exceeding* the client's allow-list — if
|
||||
so, the app-client control is soft and the pre-token Lambda becomes load-bearing after all. Verify "issued
|
||||
scopes ⊆ `AllowedOAuthScopes` regardless of Lambda output" as a **fatal** 0a gate item (§6 #8); if it does NOT
|
||||
hold, the pre-token fail-closed suppression below is promoted from backstop to primary and gets the heavier test.
|
||||
- **AMENDS design.md §2.3 (BLOCK-1 / F2).** §2.3 describes a plain **union** of a user's group-scopes (and even
|
||||
shows Lauren's token *with* `finance:read`); the substrate is ambiguous on per-audience subsetting. This plan
|
||||
**amends** §2.3: group→scope mapping still defines what a user *may* hold, but the **issued token is bounded by
|
||||
|
|
@ -219,6 +224,22 @@ and FIX is addressed below; this revision supersedes the pre-audit text wherever
|
|||
flip-point clarified as operational re-announce. **Q1** fallback-scope honesty + **Q2** freshness-bound
|
||||
mechanism documented.
|
||||
|
||||
**Round 3 (Gemini `scanner`, third model family — 2026-06-11).** Triangulated the auth nerve all three families
|
||||
flagged; two sharp BLOCKs folded in:
|
||||
- **Gemini-BLOCK-1:** `AllowedOAuthScopes` strictly filtering a V2 pre-token Lambda's output is **unverified** —
|
||||
added as a fatal Phase-0a check (§6 #8a); if it doesn't hold, pre-token fail-closed becomes the primary boundary.
|
||||
(Sharpens BLOCK-1: neither layer is *independently* guaranteed until this interaction is proven.)
|
||||
- **Gemini-BLOCK-2:** Cognito access tokens carry `client_id`/scopes, **not a native `aud`** — aligned §1h and the
|
||||
facade/server checks to a **`client_id` allow-list / scope-prefix audience proxy** (§0.1, §1h, §6 #8c).
|
||||
- **Gemini-Q:** the 0a spike must run on a **production-equivalent Enterprise Grid org with real licenses**, not a
|
||||
Dev/non-Grid Slack (false-positive risk) — §6 #6.
|
||||
- **Gemini-NIT (path-corrected):** project memory is a private store at `~/.claude/projects/.../memory/`, distinct
|
||||
from repo READMEs — §4. (Gemini cited its own `~/.gemini/...` path; corrected — a cross-family infra-fact
|
||||
assertion to verify, not adopt, per `feedback_fable_review_gates`.)
|
||||
Gemini APPROVED the rest: B1/B5 parallel-run dual-feed + Bolt fallback sound; §1a identity segregation coherently
|
||||
integrated with the token-layer mechanism. **All three families (Claude/Fable, GPT-4.1, Gemini) now converge: the
|
||||
structural plan is sound; the only open risk is the auth token-mint mechanism, fully spike-gated in Phase 0a.**
|
||||
|
||||
**Cross-family review (GPT-4.1 `cross_reviewer`, 2026-06-11) — auth/trifecta sections.** Run per the mandatory
|
||||
cross-review gate for auth/IAM design (Fable is Claude-family, not a substitute). Findings folded in:
|
||||
- **CR-1 (BLOCK):** validate `aud` at the edge **AND** server-side (defense in depth) — the per-tier authorizer
|
||||
|
|
@ -436,9 +457,11 @@ real home:
|
|||
deprecating each bot (design.md §6, §7.3 parity gate).
|
||||
|
||||
**Core security tests (authoritative, transport-agnostic, in `sh-mcp`, design.md §7.3):**
|
||||
**audience-binding rejection at the per-tier facade AND re-validated server-side** (an `aud=sh-mcp-ops` token
|
||||
rejected by the `sh-mcp-finance` gateway authorizer *and* by the finance server itself — B3/CR-1, defense in
|
||||
depth); per-tool **server-side** scope enforcement; **per-agent credential mints only its tier's scopes** (a
|
||||
**audience-binding rejection at the per-tier facade AND re-validated server-side** — bound on the chosen
|
||||
audience proxy (**`client_id` allow-list per gateway, or resource-server scope-prefix**, since Cognito access
|
||||
tokens carry `client_id`/scopes, **not a native `aud` claim** unless injected via pre-token V2 — Gemini round-3):
|
||||
an ops-tier token is rejected by the `sh-mcp-finance` gateway authorizer *and* by the finance server itself
|
||||
(B3/CR-1, defense in depth); per-tool **server-side** scope enforcement; **per-agent credential mints only its tier's scopes** (a
|
||||
token obtained via the Lauren Exec app client never contains `finance:read`, even though the person holds it —
|
||||
B4); **pre-token fails closed on a cross-audience scope** (CR-3); **a finance-audience token cannot reach a
|
||||
Gmail/Calendar tool** (CR-6); **backend rejects a token whose `sub` is not a valid Google Workspace user** (CR-2);
|
||||
|
|
@ -694,9 +717,12 @@ MCP layer) are unchanged — those stay locked.
|
|||
**Repo READMEs & memory (F6 — global-instruction obligations, were omitted):**
|
||||
- `sh-mcp` README updated to **OpenAPI-first** (servers expose OpenAPI; MCP adapter deferred).
|
||||
- `sh-agentforce` README created (agent metadata repo, `cd-sfdx`, scratch-org flow).
|
||||
- **Project memory:** create `project_sh_agentforce` before the repo-creating conversation ends; update
|
||||
`project_sh_mcp` for the transport/auth changes; add **cross-project references** `sh-mcp` ↔ `sh-agentforce`
|
||||
↔ `project_seahaven_slack_bot` ↔ `project_exec_aide` (each side links the other).
|
||||
- **Project memory (PRIVATE memory store, NOT repo files — Gemini round-3 NIT, path-corrected):** these live in
|
||||
`~/.claude/projects/-Users-adammoussa-Documents-repositories/memory/` (the Sea Haven memory location — **not**
|
||||
any repo, and not Gemini's own `~/.gemini/...` path, which it incorrectly cited). Create `project_sh_agentforce`
|
||||
before the repo-creating conversation ends; update `project_sh_mcp` for the transport/auth changes; add
|
||||
**cross-project references** `sh-mcp` ↔ `sh-agentforce` ↔ `project_seahaven_slack_bot` ↔ `project_exec_aide`.
|
||||
Keep this distinct from the repo-side READMEs above.
|
||||
|
||||
**Monitoring (N2 — ALARM-state-only convention, design.md alarm preferences):**
|
||||
- Each per-tier **API Gateway facade**: 5xx-rate, auth-failure-spike, and **wrong-audience-token** alarms (the
|
||||
|
|
@ -804,15 +830,20 @@ Groups to reconcile the two control planes (G11, recommend SCIM).
|
|||
must run as scripted per-user sessions instead of batch — decide before Phase 1.
|
||||
6. **(Slack plan + licensing, Q1/Q2/G15)** Confirm Sea Haven's Slack plan supports **Agentforce Employee Agents**,
|
||||
and whether the all-staff Ops agent needs a provisioned Agentforce **user + license per employee** (prices G9,
|
||||
feeds G11 SCIM scope).
|
||||
feeds G11 SCIM scope). **Run this on a production-equivalent Enterprise Grid org with real Agentforce licenses
|
||||
(Gemini round-3) — a Developer Org / non-Grid Slack can false-positive on Employee Agent support.**
|
||||
7. **(Agent variables, Q3/G15)** Confirm Agentforce exposes **`$User.GoogleGroups`** and **`$Session.Channel`** to
|
||||
agent instructions. If not, design an alternate enforcement for Lauren Exec's DM-only and per-scope gating
|
||||
(e.g. a context Apex action that returns channel + group facts) before Phase 1/3.
|
||||
8. **(Cognito `aud`/authorizer mechanism, BLOCK-1 — on the 0a/0b gate)** Confirm the **pre-token V2** access-token
|
||||
customization trigger is available on our Cognito plan, and pick + prove the concrete per-tier rejection
|
||||
mechanism: **scope-prefix check**, **`client_id` allow-list per gateway**, or **custom `aud` via pre-token V2**.
|
||||
The B3 edge rejection and B4 fail-closed both depend on this; Cognito access tokens do not carry a per-
|
||||
resource-server `aud` by default. Do this in the 0a throwaway kit before 0b builds the real facades.
|
||||
8. **(Cognito token-mint mechanism, BLOCK-1 + Gemini round-3 — FATAL on the 0a gate)** Three things to prove in
|
||||
the 0a throwaway kit before 0b builds real facades:
|
||||
(a) **Confirm `AllowedOAuthScopes` strictly filters the issued token** — i.e. issued scopes ⊆ the client's
|
||||
allow-list **even when a pre-token V2 Lambda runs** (Gemini BLOCK). If a V2 Lambda can widen beyond the
|
||||
allow-list, the app-client control is soft → promote pre-token fail-closed suppression to primary.
|
||||
(b) **Confirm the `pre-token V2` trigger is available** on our Cognito plan (it may be a paid feature).
|
||||
(c) **Pick + prove the per-tier rejection mechanism** — `client_id` allow-list per gateway, resource-server
|
||||
scope-prefix, or custom `aud` via V2 — since Cognito access tokens carry no native per-resource-server `aud`.
|
||||
The B3 edge rejection, B4 boundary, and §1h audience tests all depend on (a)–(c).
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue