@tideorg/mcp 1.4.2 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +81 -0
- package/GAP_REGISTER.md +18 -8
- package/PRIVACY.md +41 -0
- package/README.md +204 -197
- package/adapters/AGENTS.md +3 -2
- package/adapters/CLAUDE.md +1 -1
- package/canon/anti-patterns.md +55 -62
- package/canon/concepts.md +46 -34
- package/canon/custom-contracts.md +12 -8
- package/canon/feature-mapping.md +27 -75
- package/canon/framework-matrix.md +69 -22
- package/canon/hosting-options.md +111 -0
- package/canon/iga-change-requests-api.md +211 -0
- package/canon/invariants.md +33 -35
- package/canon/security-gap-mapping.md +506 -0
- package/canon/security-runtime-probes.md +177 -0
- package/canon/tidecloak-bootstrap.md +21 -16
- package/canon/tidecloak-endpoints.md +60 -98
- package/canon/troubleshooting.md +115 -53
- package/canon/version-policy.md +8 -12
- package/mcp-server/dist/server.js +221 -19
- package/package.json +48 -45
- package/playbooks/add-auth-nextjs-existing.md +33 -17
- package/playbooks/add-auth-nextjs-fresh.md +1 -1
- package/playbooks/add-rbac-nextjs.md +7 -2
- package/playbooks/bootstrap-realm-from-template.md +33 -18
- package/playbooks/deploy-tidecloak-docker.md +31 -28
- package/playbooks/diagnose-missing-roles-or-claims.md +2 -2
- package/playbooks/initialize-admin-and-link-account.md +22 -19
- package/playbooks/protect-api-nextjs.md +40 -1
- package/playbooks/protect-aspnet-core-asgard.md +313 -0
- package/playbooks/protect-routes-nextjs.md +24 -10
- package/playbooks/provision-tidecloak-skycloak.md +213 -0
- package/playbooks/setup-forseti-e2ee.md +32 -50
- package/playbooks/setup-iga-admin-panel.md +113 -171
- package/playbooks/verify-jwt-server-side.md +20 -1
- package/prompts/build-private-customer-portal.md +1 -1
- package/prompts/security-gap-analysis.md +55 -0
- package/reference-apps/encrypted-communication/anti-patterns.md +3 -3
- package/reference-apps/encrypted-communication/bootstrap-sequence.md +2 -2
- package/reference-apps/encrypted-communication/scenario.md +2 -2
- package/reference-apps/git-pr-signing-service/bootstrap-sequence.md +8 -8
- package/reference-apps/iga-admin-governance/anti-patterns.md +18 -16
- package/reference-apps/iga-admin-governance/bootstrap-sequence.md +10 -5
- package/reference-apps/iga-admin-governance/role-policy-matrix.md +12 -13
- package/reference-apps/iga-admin-governance/scenario.md +15 -13
- package/reference-apps/organisation-password-manager/bootstrap-sequence.md +5 -6
- package/reference-apps/policy-governed-signing/bootstrap-sequence.md +9 -9
- package/skills/tide-diagnostics/SKILL.md +1 -1
- package/skills/tide-integration/SKILL.md +9 -18
- package/skills/tide-mcp-qa/SKILL.md +139 -0
- package/skills/tide-rbac-and-e2ee/SKILL.md +5 -5
- package/skills/tide-reviewer/SKILL.md +1 -1
- package/skills/tide-security-analyst/SKILL.md +182 -0
- package/skills/tide-setup/SKILL.md +1 -1
- package/canon/delegation.md +0 -195
- package/playbooks/setup-server-delegation.md +0 -142
|
@@ -14,43 +14,45 @@ Scenario-specific mistakes for IGA admin governance panels. General Tide anti-pa
|
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
> Endpoints use the current `/iga/change-requests/...` surface (GAP-065). Full spec: `canon/iga-change-requests-api.md`.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
## AP-G02: Treating authorize as commit
|
|
20
20
|
|
|
21
|
-
**
|
|
21
|
+
**Mistake**: Calling only `POST /iga/change-requests/{id}/authorize` and assuming the change is applied.
|
|
22
22
|
|
|
23
|
-
**
|
|
23
|
+
**Why it fails**: `authorize` records an approval. The change does not take effect until `POST /iga/change-requests/{id}/commit` is called, and commit returns **412** until `readyToCommit` (threshold met, dependencies committed).
|
|
24
|
+
|
|
25
|
+
**Fix**: After `authorize` succeeds, poll for `readyToCommit === true`, then `commit`. During bootstrap, `bulk-authorize` then commit ready CRs in dependency passes.
|
|
24
26
|
|
|
25
27
|
---
|
|
26
28
|
|
|
27
|
-
## AP-G03:
|
|
29
|
+
## AP-G03: Re-signing the same CR with the same admin
|
|
28
30
|
|
|
29
|
-
**Mistake**:
|
|
31
|
+
**Mistake**: Retrying `authorize` on a CR the same admin already signed.
|
|
30
32
|
|
|
31
|
-
**Why it fails**:
|
|
33
|
+
**Why it fails**: Four-eyes enforcement returns **409 Conflict** — one admin cannot count twice toward the threshold.
|
|
32
34
|
|
|
33
|
-
**Fix**:
|
|
35
|
+
**Fix**: Have a *different* admin authorize. If you get 409, refresh the CR (`GET /iga/change-requests/{id}`) — it may already be signed or no longer PENDING.
|
|
34
36
|
|
|
35
37
|
---
|
|
36
38
|
|
|
37
|
-
## AP-G04:
|
|
39
|
+
## AP-G04: Stale pending list across mutations
|
|
38
40
|
|
|
39
|
-
**Mistake**: Fetching
|
|
41
|
+
**Mistake**: Fetching the pending list once and not refreshing after authorize/commit/deny.
|
|
40
42
|
|
|
41
|
-
**Why it fails**:
|
|
43
|
+
**Why it fails**: `status` and `readyToCommit` change after every action. Stale data drives wrong badge counts and lets the UI offer commit on a CR that is not ready (→ 412).
|
|
42
44
|
|
|
43
|
-
**Fix**:
|
|
45
|
+
**Fix**: Re-fetch `GET /iga/change-requests?status=PENDING` after every mutation and recompute counts/badges from it.
|
|
44
46
|
|
|
45
47
|
---
|
|
46
48
|
|
|
47
|
-
## AP-G05:
|
|
49
|
+
## AP-G05: Skipping the enclave step in Tide MultiAdmin mode
|
|
48
50
|
|
|
49
|
-
**Mistake**:
|
|
51
|
+
**Mistake**: Calling a bare `authorize` in Tide MultiAdmin mode and treating the response as done.
|
|
50
52
|
|
|
51
|
-
**Why it fails**: In MultiAdmin mode
|
|
53
|
+
**Why it fails**: In Tide MultiAdmin mode the approval is cryptographic — a bare `authorize` does not record it. The admin must complete the two-phase enclave exchange: `GET /iga/change-requests/{id}/approval-model` → sign the `requestModel` in the enclave → `POST /iga/change-requests/{id}/approval-model` with `{ requestModel }`.
|
|
52
54
|
|
|
53
|
-
**Fix**:
|
|
55
|
+
**Fix**: In MultiAdmin mode, drive the `approval-model` exchange and confirm `recorded: true` / an increased `authCount`. FirstAdmin/Tideless mode signs server-side on `authorize` — no enclave step.
|
|
54
56
|
|
|
55
57
|
---
|
|
56
58
|
|
|
@@ -50,12 +50,17 @@
|
|
|
50
50
|
-d "isIGAEnabled=true"
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
6. Approve/commit initial
|
|
53
|
+
6. Approve/commit initial change requests (current `/iga/change-requests/...` surface; see `canon/iga-change-requests-api.md`):
|
|
54
54
|
```bash
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
-H "Authorization: Bearer $TOKEN"
|
|
58
|
-
|
|
55
|
+
# Authorize all pending, then commit ready ones (FirstAdmin bootstrap signs server-side)
|
|
56
|
+
curl -s -X POST "http://localhost:8080/admin/realms/$REALM/iga/change-requests/bulk-authorize" \
|
|
57
|
+
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
58
|
+
-d '{"actionTypeIn":["CREATE","DELETE"],"limit":100}'
|
|
59
|
+
for id in $(curl -s "http://localhost:8080/admin/realms/$REALM/iga/change-requests?status=PENDING" \
|
|
60
|
+
-H "Authorization: Bearer $TOKEN" | jq -r '.[] | select(.readyToCommit==true) | .id'); do
|
|
61
|
+
curl -s -X POST "http://localhost:8080/admin/realms/$REALM/iga/change-requests/$id/commit" \
|
|
62
|
+
-H "Authorization: Bearer $TOKEN"
|
|
63
|
+
done
|
|
59
64
|
```
|
|
60
65
|
|
|
61
66
|
---
|
|
@@ -49,19 +49,18 @@ The governance panel may optionally include policy management. These are NOT req
|
|
|
49
49
|
|
|
50
50
|
---
|
|
51
51
|
|
|
52
|
-
## Change-
|
|
52
|
+
## Change-Request Endpoints (core governance)
|
|
53
|
+
|
|
54
|
+
Current `/iga/change-requests/...` surface (replaces legacy `/tide-admin/change-set/...`, GAP-065). **Full spec: `canon/iga-change-requests-api.md`.**
|
|
53
55
|
|
|
54
56
|
| Operation | Endpoint | Method | Content-Type | Notes |
|
|
55
57
|
|-----------|---------|--------|-------------|-------|
|
|
56
|
-
| List
|
|
57
|
-
|
|
|
58
|
-
|
|
|
59
|
-
|
|
|
60
|
-
| Commit | `/
|
|
61
|
-
|
|
|
62
|
-
|
|
|
63
|
-
|
|
|
64
|
-
|
|
|
65
|
-
| Add comment | `/tide-admin/change-set/{id}/comments` | POST | `application/json` | |
|
|
66
|
-
| Licensing requests | `/tideAdminResources/change-set/licensing/requests` | GET | — | Different path prefix from other types |
|
|
67
|
-
| Ragnarok requests | `/ragnarok/change-set/offboarding/requests` | GET | — | Different path prefix |
|
|
58
|
+
| List | `/iga/change-requests?status=PENDING` | GET | — | Objects keyed by `id`; `status` = PENDING/APPROVED/DENIED/CANCELLED. Derive counts from the list. |
|
|
59
|
+
| Get one | `/iga/change-requests/{id}` | GET | — | Full CR (`entityType`, `readyToCommit`, `threshold`, `dependsOn`) |
|
|
60
|
+
| Authorize (approve) | `/iga/change-requests/{id}/authorize` | POST | `application/json` | Body `{}` optional. 409 = four-eyes re-sign |
|
|
61
|
+
| Bulk authorize | `/iga/change-requests/bulk-authorize` | POST | `application/json` | `{ "actionTypeIn": ["CREATE","DELETE"], "limit": 100 }`; 429 if a bulk run is active |
|
|
62
|
+
| Commit | `/iga/change-requests/{id}/commit` | POST | — | 412 if under threshold / unmet dependency |
|
|
63
|
+
| Deny (reject) | `/iga/change-requests/{id}/deny` | POST | — | → 204 |
|
|
64
|
+
| Enclave sign (Tide MultiAdmin) | `/iga/change-requests/{id}/approval-model` | GET/POST | `application/json` | Two-phase: GET challenge → POST `{ requestModel }` |
|
|
65
|
+
| Comments | `/iga/change-requests/{id}/comments` | GET/POST | `application/json` | `{ "comment": "..." }` (≤2000) |
|
|
66
|
+
| Manual ADOPT | `/iga/adopt` | POST | `application/json` | `{ "entityType": "USER", "entityId": "..." }` |
|
|
@@ -72,17 +72,18 @@ These happen before any admin uses the governance panel:
|
|
|
72
72
|
|
|
73
73
|
Once bootstrap is complete, the governance panel operates as follows:
|
|
74
74
|
|
|
75
|
+
Endpoints use the current `/iga/change-requests/...` surface (replaces legacy `/tide-admin/change-set/...`, GAP-065; full spec `canon/iga-change-requests-api.md`).
|
|
76
|
+
|
|
75
77
|
1. Admin logs in via TideCloak SSO (DPoP-bound)
|
|
76
|
-
2. Panel
|
|
77
|
-
3. Panel
|
|
78
|
+
2. Panel lists pending requests (`GET /iga/change-requests?status=PENDING`) and derives counts
|
|
79
|
+
3. Panel groups pending CRs by `entityType` (users, roles, groups, clients, settings, policies)
|
|
78
80
|
4. Admin reviews a change request's details, activity, and comments
|
|
79
|
-
5. Admin approves: `POST /
|
|
80
|
-
- If MultiAdmin:
|
|
81
|
-
- If FirstAdmin: signed immediately
|
|
82
|
-
6. When
|
|
83
|
-
7. Admin can
|
|
84
|
-
8. Admin can
|
|
85
|
-
9. Admin can add/edit/delete comments on change requests
|
|
81
|
+
5. Admin approves: `POST /iga/change-requests/{id}/authorize` (body `{}`; 409 = four-eyes)
|
|
82
|
+
- If Tide MultiAdmin: complete the two-phase `GET`/`POST /iga/change-requests/{id}/approval-model` enclave exchange
|
|
83
|
+
- If FirstAdmin/Tideless: signed server-side immediately
|
|
84
|
+
6. When `readyToCommit`: `POST /iga/change-requests/{id}/commit` (412 if under threshold)
|
|
85
|
+
7. Admin can reject: `POST /iga/change-requests/{id}/deny`
|
|
86
|
+
8. Admin can add/edit/delete comments on change requests
|
|
86
87
|
|
|
87
88
|
---
|
|
88
89
|
|
|
@@ -104,10 +105,11 @@ Once bootstrap is complete, the governance panel operates as follows:
|
|
|
104
105
|
|
|
105
106
|
| Symptom | Likely cause | Fix |
|
|
106
107
|
|---------|-------------|-----|
|
|
107
|
-
|
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
108
|
+
| Authorize returns 401 | Token expired or DPoP not attached | Re-login; ensure `secureFetch` with DPoP |
|
|
109
|
+
| Authorize returns 409 | Same admin re-signing (four-eyes) or CR not PENDING | Use a different admin; refresh the list |
|
|
110
|
+
| MultiAdmin: authorize does not record | Enclave step skipped | Complete `{id}/approval-model` two-phase exchange |
|
|
111
|
+
| Commit returns 412 | Under threshold / unmet dependency | Collect more approvals; commit `dependsOn` CR first |
|
|
112
|
+
| Change request stays PENDING after authorize | Missing commit step | Call `{id}/commit` once `readyToCommit` |
|
|
111
113
|
| add-review returns 415 | Wrong content-type | Use `multipart/form-data`, not JSON |
|
|
112
114
|
| Counts don't update after commit | Stale data | Refresh counts after every mutation |
|
|
113
115
|
| Policy change requests don't appear | Realm policy not in pending state | Create pending realm policy first via `/tide-admin/realm-policy/pending` |
|
|
@@ -48,12 +48,11 @@ All steps must complete before users can safely use the app. Order matters.
|
|
|
48
48
|
|
|
49
49
|
## Phase 4: Change-set approval
|
|
50
50
|
|
|
51
|
-
10. **Approve pending change-
|
|
52
|
-
- IGA creates draft change
|
|
53
|
-
- List: `GET /admin/realms/{realm}/
|
|
54
|
-
-
|
|
55
|
-
|
|
56
|
-
- Commit: `POST /admin/realms/{realm}/tide-admin/change-set/commit`.
|
|
51
|
+
10. **Approve pending change requests** (current `/iga/change-requests/...` surface — see `canon/iga-change-requests-api.md`)
|
|
52
|
+
- IGA creates draft change requests for client and user mutations made during setup (each mutating write returns 202).
|
|
53
|
+
- List: `GET /admin/realms/{realm}/iga/change-requests?status=PENDING` (objects keyed by `id`).
|
|
54
|
+
- Approve: `POST /admin/realms/{realm}/iga/change-requests/bulk-authorize` (`{"actionTypeIn":["CREATE","DELETE"],"limit":100}`; FirstAdmin signs server-side).
|
|
55
|
+
- Commit: `POST /admin/realms/{realm}/iga/change-requests/{id}/commit` for each `readyToCommit` CR.
|
|
57
56
|
- Without this step, client and user changes are in draft state and not active.
|
|
58
57
|
|
|
59
58
|
## Phase 5: IDP settings and adapter export
|
|
@@ -28,12 +28,12 @@ All steps must complete before users can safely use signing features. Order matt
|
|
|
28
28
|
- `POST /admin/realms/{realm}/tide-admin/toggle-iga` with form-urlencoded `isIGAEnabled=true`.
|
|
29
29
|
- Must happen after licensing. Enables change-set governance for role/user mutations.
|
|
30
30
|
|
|
31
|
-
## Phase 3: Approve initial change
|
|
31
|
+
## Phase 3: Approve initial change requests
|
|
32
32
|
|
|
33
|
-
6. **Approve
|
|
34
|
-
- IGA creates draft change
|
|
35
|
-
- List: `GET /admin/realms/{realm}/
|
|
36
|
-
-
|
|
33
|
+
6. **Approve initial change requests** (current `/iga/change-requests/...` surface — see `canon/iga-change-requests-api.md`)
|
|
34
|
+
- IGA creates draft change requests for client/role mutations during realm import (each mutating write returns 202).
|
|
35
|
+
- List: `GET /admin/realms/{realm}/iga/change-requests?status=PENDING` (objects keyed by `id`).
|
|
36
|
+
- Approve: `POST /admin/realms/{realm}/iga/change-requests/bulk-authorize` (`{"actionTypeIn":["CREATE","DELETE"],"limit":100}`), then `POST /admin/realms/{realm}/iga/change-requests/{id}/commit` for each `readyToCommit` CR. FirstAdmin bootstrap signs server-side.
|
|
37
37
|
|
|
38
38
|
## Phase 4: Admin user setup
|
|
39
39
|
|
|
@@ -52,11 +52,11 @@ All steps must complete before users can safely use signing features. Order matt
|
|
|
52
52
|
- Poll `GET /admin/realms/{realm}/users/{userId}` until `attributes.tideUserKey` and `attributes.vuid` are present.
|
|
53
53
|
- Do not proceed until both attributes exist.
|
|
54
54
|
|
|
55
|
-
## Phase 5: Approve user change
|
|
55
|
+
## Phase 5: Approve user change requests
|
|
56
56
|
|
|
57
|
-
11. **Approve user change
|
|
58
|
-
- List: `GET /admin/realms/{realm}/
|
|
59
|
-
-
|
|
57
|
+
11. **Approve user change requests**
|
|
58
|
+
- List: `GET /admin/realms/{realm}/iga/change-requests?status=PENDING`.
|
|
59
|
+
- Authorize then commit (see Phase 3 / `canon/iga-change-requests-api.md`).
|
|
60
60
|
|
|
61
61
|
## Phase 6: IDP settings and adapter export
|
|
62
62
|
|
|
@@ -54,7 +54,7 @@ Troubleshoot broken Tide integrations. Own login failures, missing roles/claims,
|
|
|
54
54
|
|---------|-------------|----------|
|
|
55
55
|
| Login hangs or blank screen | CSP missing `frame-src '*'`, redirect handler missing, DPoP auth page missing | `diagnose-broken-login` |
|
|
56
56
|
| Login redirect loop | `@tidecloak/react` ESM alias missing (AP-42), provider not wired | `diagnose-broken-login` |
|
|
57
|
-
| DPoP login fails | `tide_dpop_auth.html` missing or
|
|
57
|
+
| DPoP login fails | `tide_dpop_auth.html` missing, or its `app/tide_dpop/[...path]/route.ts` catch-all route handler / hash-pinned CSP / `Allow-CSP-From: *` header not configured (I-12, L-07) | `diagnose-broken-login` |
|
|
58
58
|
| 401 on all API calls | JWT verification not implemented, or DPoP proof missing | `diagnose-missing-roles-or-claims` |
|
|
59
59
|
| 403 on API calls | Role not assigned, IGA change-set not committed, or 120s refresh delay | `diagnose-missing-roles-or-claims` |
|
|
60
60
|
| Roles missing from JWT | IGA change-set not committed, token not refreshed (up to 120s) | `diagnose-missing-roles-or-claims` |
|
|
@@ -17,11 +17,11 @@ Wire the Tide SDK into the application. Own SDK installation, provider setup, co
|
|
|
17
17
|
| `tidecloak.json` placement and import | `tide-setup` if file doesn't exist and TideCloak not bootstrapped |
|
|
18
18
|
| `silent-check-sso.html` in `public/` | — |
|
|
19
19
|
| Post-auth redirect handler (`auth/redirect/page.tsx`) | — |
|
|
20
|
-
| `tide_dpop_auth.html`
|
|
20
|
+
| `tide_dpop_auth.html` served via a `app/tide_dpop/[...path]/route.ts` catch-all route handler + DPoP headers (I-12) | — |
|
|
21
21
|
| CSP (`frame-src '*'`) in `next.config` headers | — |
|
|
22
22
|
| Webpack workarounds (`strictExportPresence`, `@tidecloak/react` ESM alias) | — |
|
|
23
23
|
| Retrofit into existing apps | — |
|
|
24
|
-
|
|
|
24
|
+
| ASP.NET Core (.NET 10) backend via `Tide.Asgard.AspNetCore` SDK | Follow [playbooks/protect-aspnet-core-asgard.md](../../playbooks/protect-aspnet-core-asgard.md). Out of scope for the Next.js/React/Vanilla priority — do not invent OIDC wiring; route to that playbook. |
|
|
25
25
|
| Route/API protection | `tide-route-and-api-protection` |
|
|
26
26
|
| Roles, RBAC, encryption | `tide-rbac-and-e2ee` |
|
|
27
27
|
| TideCloak bootstrap, realm, licensing | `tide-setup` |
|
|
@@ -35,6 +35,7 @@ Wire the Tide SDK into the application. Own SDK installation, provider setup, co
|
|
|
35
35
|
- `tide-setup` detected hardening gaps (Path D)
|
|
36
36
|
- User asks to "add Tide to my app" or "add login"
|
|
37
37
|
- Orchestrator routed here after bootstrap is confirmed
|
|
38
|
+
- User asks about adding Tide auth to an **ASP.NET Core / C# / .NET** API. Route directly to [playbooks/protect-aspnet-core-asgard.md](../../playbooks/protect-aspnet-core-asgard.md) — do not attempt to retrofit Node-side guidance.
|
|
38
39
|
|
|
39
40
|
### Scenario-disambiguation gate (I-17)
|
|
40
41
|
|
|
@@ -71,8 +72,8 @@ Follow playbook `add-auth-nextjs-fresh`:
|
|
|
71
72
|
3. Place `tidecloak.json` at correct path (`data/` for Next.js, `public/` for React/Vite)
|
|
72
73
|
4. Create `public/silent-check-sso.html`
|
|
73
74
|
5. Create post-auth redirect handler at `auth/redirect/page.tsx`
|
|
74
|
-
6. Copy `tide_dpop_auth.html` to `public/` and
|
|
75
|
-
7.
|
|
75
|
+
6. Copy `tide_dpop_auth.html` to `public/` and serve it via a catch-all route handler at `app/tide_dpop/[...path]/route.ts` (matches the shipped `@tidecloak/create-nextjs` scaffold; I-12). The handler reads the single bundled `public/tide_dpop_auth.html` and returns it for any `/tide_dpop/...` path. Do NOT use `next.config.ts` rewrites for this.
|
|
76
|
+
7. On that route handler's response, set a **sha256 hash-pinned** CSP (pin the file's inline `script`/`style` via `sha256-...` hashes — NOT `script-src 'unsafe-inline'`) plus an `Allow-CSP-From: *` header (lets the ORK embed the page cross-origin). Global CSP stays `frame-src '*'` in `next.config` headers.
|
|
76
77
|
8. Add webpack workarounds to `next.config.ts`: `strictExportPresence = false` + `@tidecloak/react` ESM alias
|
|
77
78
|
|
|
78
79
|
### Existing app (has other auth)
|
|
@@ -82,16 +83,6 @@ Follow playbook `add-auth-nextjs-existing`:
|
|
|
82
83
|
2. Replace existing auth provider with `TideCloakProvider`
|
|
83
84
|
3. Remove old auth (NextAuth, Clerk, etc.) after Tide is working
|
|
84
85
|
|
|
85
|
-
### Server-side delegation
|
|
86
|
-
|
|
87
|
-
Follow playbook `setup-server-delegation`:
|
|
88
|
-
1. Install `@tidecloak/server`
|
|
89
|
-
2. Create `TideDelegation` singleton with TideCloak config
|
|
90
|
-
3. Wire `/api/delegation` POST endpoint with `handleDelegation()`
|
|
91
|
-
4. Add `requireDelegation()` middleware to admin routes
|
|
92
|
-
5. Wrap browser fetch with `createTideFetch` from `@tidecloak/js`
|
|
93
|
-
6. Optionally scope delegation roles via `requireDelegation({ roles: { ... } })`
|
|
94
|
-
|
|
95
86
|
### Hardening gaps (from tide-setup Path D)
|
|
96
87
|
|
|
97
88
|
Fix each missing item per the table in `tide-setup`.
|
|
@@ -105,11 +96,10 @@ Fix each missing item per the table in `tide-setup`.
|
|
|
105
96
|
- [ ] `tidecloak.json` exists with `jwk`, `vendorId`, `homeOrkUrl`
|
|
106
97
|
- [ ] `public/silent-check-sso.html` exists
|
|
107
98
|
- [ ] Post-auth redirect handler exists at configured `redirectUri`
|
|
108
|
-
- [ ] `public/tide_dpop_auth.html` exists + `
|
|
99
|
+
- [ ] `public/tide_dpop_auth.html` exists + `app/tide_dpop/[...path]/route.ts` catch-all route handler serves it with a sha256 hash-pinned CSP and `Allow-CSP-From: *`
|
|
109
100
|
- [ ] CSP includes `frame-src '*'`
|
|
110
101
|
- [ ] Webpack config has `strictExportPresence = false` + `@tidecloak/react` ESM alias
|
|
111
102
|
- [ ] Login flow completes: redirect to Tide IdP -> auth -> callback -> app
|
|
112
|
-
- [ ] If server-side admin calls needed: `@tidecloak/server` installed, delegation endpoints wired
|
|
113
103
|
|
|
114
104
|
---
|
|
115
105
|
|
|
@@ -132,5 +122,6 @@ Next: Security Engineer | STOP if integration incomplete
|
|
|
132
122
|
- Do not create ad hoc auth wiring. Follow the playbook.
|
|
133
123
|
- Do not use `NEXT_PUBLIC_TIDECLOAK_*` env vars. Use `tidecloak.json` directly. (AP-38)
|
|
134
124
|
- Do not pass `useDPoP` as a JSX prop. It goes inside the config object. (AP-42, session-002)
|
|
135
|
-
- Do not modify `tide_dpop_auth.html`. It is integrity-checked. (I-12, L-07)
|
|
136
|
-
- Do not
|
|
125
|
+
- Do not modify `tide_dpop_auth.html`. It is integrity-checked and its inline script/style are sha256-pinned in the route handler's CSP. (I-12, L-07)
|
|
126
|
+
- Do not serve the DPoP auth page with `script-src 'unsafe-inline'`. Pin its inline script/style with `sha256-...` hashes in the route handler's CSP instead. (L-07)
|
|
127
|
+
- Do not use `next.config.ts` `rewrites()` to serve the DPoP auth page. Use the `app/tide_dpop/[...path]/route.ts` catch-all route handler (the shipped `@tidecloak/create-nextjs` approach). (I-12)
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Role: MCP QA Engineer (Pre-Release Gate)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Decide whether the Tide MCP pack is safe to release. This role runs the deterministic test gate, then does the semantic review the gate cannot, and issues a single verdict: **SHIP**, **SHIP_WITH_WARNINGS**, or **BLOCK**. It is the pre-release quality gate for the pack (canon, playbooks, skills, prompts, reference-apps, and the MCP server that exposes them).
|
|
8
|
+
|
|
9
|
+
This role is **read-only and advisory about the release**. It runs tests and reads content; it does not fix defects it finds. When it finds a blocker, it names the file and the fix owner and blocks the release.
|
|
10
|
+
|
|
11
|
+
## Two layers, one verdict
|
|
12
|
+
|
|
13
|
+
1. **Deterministic gate (objective, must be green).** `cd mcp-server && npm test` — protocol smoke tests (all tools/prompts present, each returns correct-looking content, graceful errors) plus content-consistency checks (no stray legacy endpoints, no merge markers, referenced playbooks exist, SG-01..SG-18 present, GAP counts sum, honesty guards present). **Any red here is an automatic BLOCK.**
|
|
14
|
+
2. **Semantic review (judgment, gate can't see it).** Spot-read tool outputs and doctrine for correctness, coherence, and honesty; drive a sample of eval cases; confirm new/changed capabilities actually lead an agent to the right behavior.
|
|
15
|
+
|
|
16
|
+
A release is **SHIP** only when the gate is green *and* semantic review finds no correctness/honesty blocker.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Boundary
|
|
21
|
+
|
|
22
|
+
| This role owns | Does NOT own |
|
|
23
|
+
|----------------|--------------|
|
|
24
|
+
| Running `npm test` and interpreting it | Fixing failing tests or defects |
|
|
25
|
+
| Semantic/coherence review of tool outputs & doctrine | Writing new pack content |
|
|
26
|
+
| Driving sample eval cases | Building features |
|
|
27
|
+
| Honesty/overclaim audit | Changing doctrine to make a test pass |
|
|
28
|
+
| The release verdict (SHIP / WARN / BLOCK) | Publishing/releasing (that's the human's call after the verdict) |
|
|
29
|
+
|
|
30
|
+
**Hard rule:** never weaken a check or edit doctrine to turn a gate green. If a test is wrong, report it as a test defect; do not silence it.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## When to Trigger
|
|
35
|
+
|
|
36
|
+
- Before publishing/releasing the MCP pack or the npm package.
|
|
37
|
+
- After a substantial doctrine change (a reconciliation like the IGA API migration, a new capability, a merge of feature branches).
|
|
38
|
+
- On demand: "QA the MCP", "is the pack ready to release", "run the release gate".
|
|
39
|
+
|
|
40
|
+
## When NOT to Trigger
|
|
41
|
+
|
|
42
|
+
- Building or editing pack content (that's the authoring roles).
|
|
43
|
+
- Diagnosing a live TideCloak app (that's `tide-diagnostics`).
|
|
44
|
+
- Security-analysing a customer system (that's `tide-security-analyst`).
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Execution
|
|
49
|
+
|
|
50
|
+
### Step 1 — Run the deterministic gate
|
|
51
|
+
```bash
|
|
52
|
+
cd mcp-server && npm test
|
|
53
|
+
```
|
|
54
|
+
Record the summary line and every failing check verbatim. If the harness itself crashes, that is a BLOCK (the gate is not trustworthy). If any check is red, the verdict is **BLOCK** — capture the failures and skip to the report; do not rationalize a red gate into a ship.
|
|
55
|
+
|
|
56
|
+
### Step 2 — Semantic review (only meaningful once the gate is green)
|
|
57
|
+
Call the tools through the MCP server (or read the assets directly) and judge what the grep-level gate cannot:
|
|
58
|
+
|
|
59
|
+
- **Correctness of guidance.** Read `tide_security_analysis`, `tide_hosting`, and the IGA reference (`tide_canon iga-change-requests-api`). Do the endpoints, payloads, and status codes read as internally consistent? Would an agent following them do the right thing?
|
|
60
|
+
- **Coherence after change.** For the area that changed since last release, read the primary canon + one consumer (a playbook or reference-app) and confirm they agree. (E.g. after the IGA migration: `canon/iga-change-requests-api.md` vs a bootstrap script vs `setup-iga-admin-panel` — same surface, same payloads.)
|
|
61
|
+
- **Routing.** `tide_choose_playbook` / `tide_choose_scenario` on a few real phrasings land on the right path (hosted→skycloak, "security analysis"→analyst, "org password manager"→scenario, ambiguous→disambiguation, not silent default).
|
|
62
|
+
- **Honesty audit (load-bearing).** Confirm the pack does NOT overclaim:
|
|
63
|
+
- Security analysis keeps the out-of-scope section and never claims Tide fixes injection/XSS/deps (AP-SEC-1).
|
|
64
|
+
- Hosting is not sold as fully turnkey before GAP-066 (AP-HOST-2); the Tideless-IGA caveat is present.
|
|
65
|
+
- IGA "no single bypass / tamper-evident" claims are scoped to Tide mode, not Tideless.
|
|
66
|
+
- Anything marked REQUIRES_RUNTIME_VALIDATION (e.g. the IGA bootstrap loop) is flagged as such, not asserted as verified.
|
|
67
|
+
|
|
68
|
+
### Step 3 — Drive sample eval cases
|
|
69
|
+
Pick a representative spread from `evals/cases.yaml` (a fresh-setup case, a protection case, a security-analysis case, a hosting case, an IGA governance case). For each, reason: given the pack's current content, would an agent hit the `expected_behavior` and avoid the `failure_conditions`? Note any case the pack would now fail. (This is judgment, not execution — say so.)
|
|
70
|
+
|
|
71
|
+
### Step 4 — Verdict + report
|
|
72
|
+
Emit the Release Readiness Report. One verdict:
|
|
73
|
+
- **SHIP** — gate green, no semantic blocker, no unmanaged overclaim.
|
|
74
|
+
- **SHIP_WITH_WARNINGS** — gate green; only non-blocking issues (cosmetic, low-risk doc gaps, known REQUIRES_RUNTIME_VALIDATION items that are correctly labelled). List them.
|
|
75
|
+
- **BLOCK** — any red gate check, any harness crash, any correctness or honesty defect, or a sample eval the pack would now fail. Name each blocker + the file + the fix owner (which authoring role).
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Release Readiness Report (required format)
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
# Tide MCP — Release Readiness Report
|
|
83
|
+
Verdict: SHIP | SHIP_WITH_WARNINGS | BLOCK
|
|
84
|
+
Scope: <what changed since last release / full pack>
|
|
85
|
+
|
|
86
|
+
## Deterministic gate
|
|
87
|
+
Command: cd mcp-server && npm test
|
|
88
|
+
Result: <N/M passed> (PASS/FAIL)
|
|
89
|
+
Failures: <each red check verbatim, or "none">
|
|
90
|
+
|
|
91
|
+
## Semantic review
|
|
92
|
+
- Correctness: <observations, or "no issues">
|
|
93
|
+
- Coherence (changed area): <what you cross-checked → verdict>
|
|
94
|
+
- Routing: <phrasings tried → where they landed>
|
|
95
|
+
- Honesty audit: <overclaim checks → pass/fail with evidence>
|
|
96
|
+
|
|
97
|
+
## Sample eval cases
|
|
98
|
+
<case id → would-pass / would-fail (why)>
|
|
99
|
+
|
|
100
|
+
## Blockers (if any)
|
|
101
|
+
1. <defect> — <file:line> — fix owner: <authoring role/skill>
|
|
102
|
+
|
|
103
|
+
## Warnings (non-blocking)
|
|
104
|
+
- <item, why it's acceptable to ship>
|
|
105
|
+
|
|
106
|
+
## Recommendation
|
|
107
|
+
<one line: release, or fix blockers then re-run the gate>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Verification (of the QA pass itself)
|
|
113
|
+
|
|
114
|
+
- [ ] `npm test` was actually run this pass; its summary is quoted.
|
|
115
|
+
- [ ] A red gate or harness crash was reported as BLOCK (never rationalized).
|
|
116
|
+
- [ ] The honesty audit ran and its results are in the report.
|
|
117
|
+
- [ ] Every blocker names a file and a fix owner.
|
|
118
|
+
- [ ] No check was weakened and no doctrine was edited to pass the gate.
|
|
119
|
+
|
|
120
|
+
## Anti-Patterns
|
|
121
|
+
|
|
122
|
+
- **AP-QA-1** — Shipping on a red or crashed gate. The deterministic gate is a hard floor.
|
|
123
|
+
- **AP-QA-2** — Editing a test or doctrine to turn a check green instead of reporting the defect. QA reports; it does not launder failures.
|
|
124
|
+
- **AP-QA-3** — Skipping the honesty audit. Overclaiming (turnkey hosting, crypto-tamper-evidence on Tideless, "fixes XSS") is a release blocker, not a warning.
|
|
125
|
+
- **AP-QA-4** — Reporting a green gate as SHIP without semantic review. Grep-green is necessary, not sufficient.
|
|
126
|
+
- **AP-QA-5** — Treating a correctly-labelled REQUIRES_RUNTIME_VALIDATION item as a blocker. It ships as a warning; an *unlabelled* one is the blocker.
|
|
127
|
+
|
|
128
|
+
## Handoff Trace
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
[TRACE]
|
|
132
|
+
Scenario: pre-release QA of the Tide MCP pack
|
|
133
|
+
Role: MCP QA Engineer
|
|
134
|
+
Reason: <release / post-change gate>
|
|
135
|
+
Preconditions: mcp-server builds; npm test runnable
|
|
136
|
+
Verdict: <SHIP | SHIP_WITH_WARNINGS | BLOCK>
|
|
137
|
+
Next: <release, or route blockers to named authoring roles>
|
|
138
|
+
[/TRACE]
|
|
139
|
+
```
|
|
@@ -43,7 +43,7 @@ Self-encryption (this skill) is **permanently user-bound**. It cannot be upgrade
|
|
|
43
43
|
- App is not Tide-enabled. Route to `tide-setup` skill.
|
|
44
44
|
- API routes do not verify JWT yet. Route to `tide-route-and-api-protection` skill first. RBAC on unverified tokens is meaningless.
|
|
45
45
|
- User needs shared/group encryption (policy-governed VVK encryption with Forseti contracts). That is covered by playbook `setup-forseti-e2ee`, not this skill. This skill covers self-encryption only.
|
|
46
|
-
- User asks about Keycloak-to-TideCloak migration.
|
|
46
|
+
- User asks about a **direct Keycloak-to-TideCloak** migration. That specific path is not yet documented (GAP-023). (Migrating an app off generic-OIDC / NextAuth / Clerk is a separate task covered by `playbooks/migrate-from-existing-auth.md`; the open gap is the KC→TideCloak realm/data migration itself.)
|
|
47
47
|
|
|
48
48
|
**Early sharing detection**: If the user request mentions any of: "sharing", "share encrypted", "chosen recipients", "other users can decrypt", "cross-user decryption", "encrypt for others", "selective sharing" — route directly to `setup-forseti-e2ee`. Do NOT start with self-encryption and attempt to add sharing later. Self-encryption cannot be upgraded to shared encryption by renaming roles or changing parameters. The SDK call path must be different from the start. VERIFIED (session-001, F-07).
|
|
49
49
|
|
|
@@ -139,8 +139,8 @@ Self-encryption is user-bound. Only the encrypting user can decrypt their own da
|
|
|
139
139
|
- [ ] Bypassing UI (direct curl) still enforces role server-side
|
|
140
140
|
|
|
141
141
|
### Self-Encryption (if applicable)
|
|
142
|
-
- [ ] `doEncrypt('tag'
|
|
143
|
-
- [ ] `doDecrypt('tag'
|
|
142
|
+
- [ ] `doEncrypt([{ data, tags: ['tag'] }])` succeeds for user with `_tide_{tag}.selfencrypt` role
|
|
143
|
+
- [ ] `doDecrypt([{ data: ciphertext, tags: ['tag'] }])` returns original data for same user
|
|
144
144
|
- [ ] `doEncrypt` fails for user without the selfencrypt role
|
|
145
145
|
- [ ] `doDecrypt` by a different user fails (expected behavior — self-encryption is user-bound; A-27 INFERRED, not runtime-confirmed)
|
|
146
146
|
- [ ] Ciphertext stored in DB is not plaintext
|
|
@@ -181,8 +181,8 @@ Self-encryption is user-bound. Only the encrypting user can decrypt their own da
|
|
|
181
181
|
|
|
182
182
|
This is a policy-flow failure, not a role issue. See T-14.
|
|
183
183
|
|
|
184
|
-
1. Check admin policy was fetched from `GET /realms/{realm}/tide-policy-resources/admin-policy`
|
|
185
|
-
2. Check admin policy bytes were base64-decoded before use
|
|
184
|
+
1. Check admin policy was fetched (admin bearer) from `GET /admin/realms/{realm}/iga/role-policies`, reading the signed bytes from the `policy` field (the public `tide-policy-resources/admin-policy` endpoint does not exist on main)
|
|
185
|
+
2. Check admin policy bytes were base64-decoded from the `policy` field before use
|
|
186
186
|
3. Check `addPolicy(adminPolicyBytes)` was called after approval, not during request construction
|
|
187
187
|
4. Check URL construction has no double slashes (strip trailing slash from `auth-server-url`)
|
|
188
188
|
|
|
@@ -65,7 +65,7 @@ The Reviewer is optional per-step but **mandatory before handing the app to the
|
|
|
65
65
|
- [ ] Does `next.config.ts` have `strictExportPresence = false`? (not `reexportExportsPresence`)
|
|
66
66
|
- [ ] Does `next.config.ts` have the `@tidecloak/react` ESM alias? (AP-42)
|
|
67
67
|
- [ ] Does `public/tide_dpop_auth.html` exist? (I-12, L-07)
|
|
68
|
-
- [ ]
|
|
68
|
+
- [ ] Is the DPoP auth page served by a `app/tide_dpop/[...path]/route.ts` catch-all route handler (NOT `next.config.ts` rewrites) with a sha256 hash-pinned CSP (NOT `script-src 'unsafe-inline'`) and an `Allow-CSP-From: *` header? (I-12)
|
|
69
69
|
- [ ] Does `public/silent-check-sso.html` exist? (I-07)
|
|
70
70
|
- [ ] Does the redirect handler exist at the configured `redirectUri`? (I-16)
|
|
71
71
|
- [ ] Is CSP set to `frame-src '*'`? (I-06)
|