@tideorg/mcp 1.4.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.
Files changed (76) hide show
  1. package/GAP_REGISTER.md +117 -0
  2. package/README.md +38 -0
  3. package/adapters/AGENTS.md +241 -0
  4. package/adapters/CLAUDE.md +146 -0
  5. package/adapters/replit.md +224 -0
  6. package/canon/anti-patterns.md +2133 -0
  7. package/canon/concepts.md +816 -0
  8. package/canon/custom-contracts.md +533 -0
  9. package/canon/delegation.md +195 -0
  10. package/canon/feature-mapping.md +637 -0
  11. package/canon/framework-matrix.md +1125 -0
  12. package/canon/invariants.md +851 -0
  13. package/canon/redirect-handler.md +254 -0
  14. package/canon/tidecloak-bootstrap.md +287 -0
  15. package/canon/tidecloak-endpoints.md +294 -0
  16. package/canon/troubleshooting.md +1494 -0
  17. package/canon/version-policy.md +89 -0
  18. package/mcp-server/dist/index.d.ts +2 -0
  19. package/mcp-server/dist/index.js +605 -0
  20. package/package.json +45 -0
  21. package/playbooks/add-auth-nextjs-existing.md +799 -0
  22. package/playbooks/add-auth-nextjs-fresh.md +654 -0
  23. package/playbooks/add-rbac-nextjs.md +190 -0
  24. package/playbooks/bootstrap-realm-from-template.md +170 -0
  25. package/playbooks/configure-e2ee-roles-and-policies.md +196 -0
  26. package/playbooks/deploy-tidecloak-docker.md +792 -0
  27. package/playbooks/diagnose-broken-login.md +234 -0
  28. package/playbooks/diagnose-missing-roles-or-claims.md +253 -0
  29. package/playbooks/initialize-admin-and-link-account.md +235 -0
  30. package/playbooks/migrate-from-existing-auth.md +198 -0
  31. package/playbooks/protect-api-nextjs.md +451 -0
  32. package/playbooks/protect-routes-nextjs.md +544 -0
  33. package/playbooks/setup-forseti-e2ee.md +756 -0
  34. package/playbooks/setup-iga-admin-panel.md +344 -0
  35. package/playbooks/setup-server-delegation.md +142 -0
  36. package/playbooks/start-tidecloak-dev.md +130 -0
  37. package/playbooks/verify-jwt-server-side.md +439 -0
  38. package/prompts/add-admin-approval-flow.md +50 -0
  39. package/prompts/build-private-customer-portal.md +85 -0
  40. package/prompts/migrate-generic-auth-to-tide.md +67 -0
  41. package/prompts/secure-existing-app.md +80 -0
  42. package/reference-apps/INDEX.md +87 -0
  43. package/reference-apps/encrypted-communication/anti-patterns.md +123 -0
  44. package/reference-apps/encrypted-communication/bootstrap-sequence.md +152 -0
  45. package/reference-apps/encrypted-communication/manifest.yaml +100 -0
  46. package/reference-apps/encrypted-communication/role-policy-matrix.md +80 -0
  47. package/reference-apps/encrypted-communication/scenario.md +134 -0
  48. package/reference-apps/git-pr-signing-service/anti-patterns.md +61 -0
  49. package/reference-apps/git-pr-signing-service/bootstrap-sequence.md +157 -0
  50. package/reference-apps/git-pr-signing-service/manifest.yaml +80 -0
  51. package/reference-apps/git-pr-signing-service/role-policy-matrix.md +99 -0
  52. package/reference-apps/git-pr-signing-service/scenario.md +169 -0
  53. package/reference-apps/iga-admin-governance/anti-patterns.md +133 -0
  54. package/reference-apps/iga-admin-governance/bootstrap-sequence.md +153 -0
  55. package/reference-apps/iga-admin-governance/manifest.yaml +87 -0
  56. package/reference-apps/iga-admin-governance/role-policy-matrix.md +67 -0
  57. package/reference-apps/iga-admin-governance/scenario.md +126 -0
  58. package/reference-apps/organisation-password-manager/anti-patterns.md +71 -0
  59. package/reference-apps/organisation-password-manager/bootstrap-sequence.md +127 -0
  60. package/reference-apps/organisation-password-manager/manifest.yaml +86 -0
  61. package/reference-apps/organisation-password-manager/role-policy-matrix.md +59 -0
  62. package/reference-apps/organisation-password-manager/scenario.md +107 -0
  63. package/reference-apps/policy-governed-signing/anti-patterns.md +67 -0
  64. package/reference-apps/policy-governed-signing/bootstrap-sequence.md +128 -0
  65. package/reference-apps/policy-governed-signing/manifest.yaml +78 -0
  66. package/reference-apps/policy-governed-signing/role-policy-matrix.md +62 -0
  67. package/reference-apps/policy-governed-signing/scenario.md +113 -0
  68. package/skills/tide-diagnostics/SKILL.md +99 -0
  69. package/skills/tide-integration/SKILL.md +136 -0
  70. package/skills/tide-learning-capture/SKILL.md +174 -0
  71. package/skills/tide-rbac-and-e2ee/SKILL.md +214 -0
  72. package/skills/tide-reviewer/SKILL.md +133 -0
  73. package/skills/tide-route-and-api-protection/SKILL.md +201 -0
  74. package/skills/tide-scenario-resolver/SKILL.md +81 -0
  75. package/skills/tide-setup/SKILL.md +218 -0
  76. package/skills/tide-solutions-architect/SKILL.md +130 -0
@@ -0,0 +1,169 @@
1
+ # Git PR Signing Service
2
+
3
+ ## What this is
4
+
5
+ A server-side service that threshold-signs git merge commits after admin approval. Developers push code and open pull requests as normal. The service receives GitHub webhooks, presents PRs for admin review in a web UI, and after Forseti-governed quorum approval, signs the merge commit using Tide ORK threshold cryptography. The signed commit appears on GitHub with a "Verified" badge.
6
+
7
+ No single entity holds the signing key. The key exists only as threshold shares across independent ORKs.
8
+
9
+ ## When to use this scenario
10
+
11
+ Use when the user describes:
12
+ - a service that signs git commits using threshold cryptography
13
+ - enterprise code signing with multi-admin approval
14
+ - GitHub verified commits without developer-held keys
15
+ - a PR approval workflow that produces signed merges
16
+ - removing GPG/SSH key management from individual developers
17
+ - organizational governance over code signing
18
+
19
+ Do NOT use when:
20
+ - the user needs local `git commit -S` signing at the developer's machine (no server-side service exists for this yet — see GAP-063, GAP-064)
21
+ - the user needs to sign container images (use cosign or standard `policy-governed-signing`)
22
+ - the user needs SSH challenge signing (use `policy-governed-signing` directly)
23
+ - the user needs only authentication with no signing
24
+
25
+ ## Core Tide capabilities used
26
+
27
+ 1. **TideCloak OIDC authentication** — zero-knowledge login via threshold PRISM (admins only; developers do not interact with Tide)
28
+ 2. **DPoP token binding** — access tokens bound to admin's device/session
29
+ 3. **Doken** — delegation token authorizing ORK-mediated signing operations
30
+ 4. **Forseti contracts** — C# contracts validate commit content, approver roles, and executor identity before ORKs produce signature
31
+ 5. **Policy:1 auth flow** — policy-based authorization; ORKs check contract before producing signature
32
+ 6. **IGA (Identity Governance)** — role and policy changes require multi-admin approval via change-sets
33
+ 7. **BasicCustomRequest** — request pattern for submitting commit bytes to ORKs for signing
34
+
35
+ ## Architecture
36
+
37
+ ```
38
+ Developer GitHub Signing Service Tide ORKs
39
+ | | (browser) (server) |
40
+ |-- git push / open PR | | | |
41
+ | |-- webhook: PR ------>| | |
42
+ | | |-- pending ->| |
43
+ | |<-- status check -----| | |
44
+ | | | | |
45
+ | | Admins log in via TideCloak OIDC |
46
+ | | (standard browser, SWE iframe, PRISM) |
47
+ | | | | |
48
+ | | Admin 1 reviews code, approves (doken collected) |
49
+ | | Admin 2 reviews code, approves (doken collected) |
50
+ | | | | |
51
+ | | Quorum met. Last approving admin triggers signing: |
52
+ | | | | |
53
+ | | |-- GET commit data -->| |
54
+ | | |<-- commit bytes ----| |
55
+ | | | | |
56
+ | | |-- ORK signing (browser) ------->|
57
+ | | | createTideRequest + execute |
58
+ | | | Forseti validates: |
59
+ | | | - commit (ValidateData) |
60
+ | | | - approvers (ValidateAppr) |
61
+ | | | - executor (ValidateExec) |
62
+ | | |<-- Ed25519 64-byte sig ---------|
63
+ | | | | |
64
+ | | |-- POST sig ------->| |
65
+ | | | (server wraps SSH + GitHub) |
66
+ | |<-- signed commit, update ref -------------| |
67
+ | | |-- set status: success |
68
+ | | | |
69
+ | |-- Verified badge shown |
70
+ ```
71
+
72
+ **Critical**: ORK signing happens in the admin's browser, not server-side. The JS SDK's `createTideRequest` + `executeSignRequest` require the authenticated TideCloak session (doken, PRISM state) which only exists in the browser context. The server receives the raw 64-byte signature and handles SSH wrapping + GitHub API calls. VERIFIED (LEARNINGS-ratidefy-batch-001 L-10).
73
+
74
+ ## GitHub integration components
75
+
76
+ | Component | GitHub feature | Purpose |
77
+ |-----------|---------------|---------|
78
+ | Webhook receiver | `pull_request` event webhook | Notifies service of new/updated PRs |
79
+ | Status check | Checks API (`POST /repos/{owner}/{repo}/check-runs`) | Blocks merge until service approves and signs |
80
+ | Commit signing | Git Data API (`POST /repos/{owner}/{repo}/git/commits` with `signature`) | Creates signed merge commit |
81
+ | Branch protection | Required status checks + required reviews | Enforces that all merges go through the service |
82
+ | Bot identity | GitHub App or bot account with Ed25519 SSH signing key | Public key for "Verified" badge verification |
83
+
84
+ ## Ed25519 to SSH signature format
85
+
86
+ Tide ORKs produce raw 64-byte Ed25519 signatures. GitHub requires SSH signature wire format for commit verification.
87
+
88
+ The wrapping is a non-cryptographic transformation:
89
+ 1. Take raw 64-byte Ed25519 signature from ORKs
90
+ 2. Wrap in SSH signature format: `BEGIN SSH SIGNATURE` block
91
+ 3. Namespace: `git`
92
+ 4. Hash algorithm: `sha512`
93
+ 5. Signature blob: SSH-encoded Ed25519 signature
94
+
95
+ The threshold Ed25519 public key is uploaded to the service's GitHub App (or bot account) as an SSH signing key. GitHub verifies the signature against that key.
96
+
97
+ VERIFIED — GitHub docs explicitly list `ssh-ed25519` as a supported key type for commit verification.
98
+
99
+ ## GitHub Verified Badge Requirements
100
+
101
+ For a signed commit to show the green "Verified" badge on GitHub, three things must align:
102
+
103
+ 1. **SSH signing key registered**: The threshold Ed25519 public key must be added to a GitHub account as a **Signing Key** (Settings → SSH and GPG Keys → type: Signing Key).
104
+ 2. **Committer email matches**: The commit's `committer.email` field must match the email of the GitHub account that has the signing key registered. A mismatch produces `unknown_signature_type` instead of "Verified".
105
+ 3. **SSH wire format correct**: The raw signature must be properly wrapped in `BEGIN SSH SIGNATURE` block with correct namespace and hash algorithm.
106
+
107
+ **SSH key derivation from tidecloak.json**:
108
+ The threshold Ed25519 public key is in the adapter JSON's `jwk.keys[0].x` field (base64url-encoded 32-byte key). Convert to SSH format: `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA<base64> <comment>`.
109
+
110
+ **GitHub App limitation**: GitHub App bot accounts (e.g., `ratidefy[bot]`) cannot have SSH keys added via the UI. Use a dedicated machine user account for the committer identity.
111
+
112
+ VERIFIED (LEARNINGS-ratidefy-batch-001 L-26).
113
+
114
+ ## What must exist before first use
115
+
116
+ 1. TideCloak running with a realm for the signing service
117
+ 2. Realm licensed (`setUpTideRealm`) and IGA enabled (`toggle-iga`)
118
+ 3. Admin user(s) created, Tide accounts linked, `tide-realm-admin` role assigned
119
+ 4. Initial change-sets approved and committed
120
+ 5. `sign-idp-settings` called after IDP config changes
121
+ 6. Adapter JSON exported with `jwk`, `vendorId`, `homeOrkUrl`, `client-origin-auth-*`
122
+ 7. At least one signing role created (e.g., `git-sign:main`) via admin UI
123
+ 8. Signing policy created, approved, and committed for each role
124
+ 9. GitHub App registered with webhook URL, permissions for checks + contents + pull_requests
125
+ 10. Threshold Ed25519 public key uploaded to GitHub App/bot as SSH signing key
126
+ 11. Branch protection rules configured: require signing service status check
127
+ 12. Service running with JWT + DPoP verification on protected endpoints
128
+
129
+ ## Key diagnostics
130
+
131
+ | Symptom | Likely cause |
132
+ |---------|-------------|
133
+ | No webhook received | GitHub App not installed on repo, webhook URL wrong, or service not reachable |
134
+ | Status check stays pending | Service received webhook but admin approval quorum not met |
135
+ | Signing fails with "No doken available" | Admin not authenticated or doken expired |
136
+ | Forseti contract rejects | ValidateData failed (check commit payload parsing), or executor lacks signing role |
137
+ | Merge commit not "Verified" | Public key not uploaded to GitHub, SSH wire format wrong, or wrong key used |
138
+ | 401 from GitHub API | GitHub App token expired or insufficient permissions |
139
+ | Webhook signature invalid | Webhook secret mismatch between GitHub App config and service |
140
+
141
+ ## Intentionally configurable
142
+
143
+ - **Signing role naming**: `git-sign:<branch>` is the default pattern. Apps may use `git-sign:<repo>`, `git-sign:*` (all branches), or other patterns.
144
+ - **Approval quorum**: Number of admin approvals before signing. Configurable in Forseti contract `threshold` parameter.
145
+ - **ValidateData logic**: What the contract validates about the commit. Apps may check: target branch, author identity, commit message format, modified file paths, PR metadata.
146
+ - **Approval type**: Implicit (doken-only) or explicit (requires operator approval popup).
147
+ - **Branch scope**: Which branches require signed merges. Configurable via GitHub branch protection rules.
148
+ - **GitHub identity**: GitHub App (preferred for organizations) or bot account (simpler for personal repos).
149
+
150
+ ## Relationship to policy-governed-signing
151
+
152
+ This scenario is a specialization of `policy-governed-signing` for the git/GitHub domain. It inherits all invariants, anti-patterns, and Forseti contract patterns from the parent scenario. The key differences:
153
+
154
+ | Aspect | policy-governed-signing | git-pr-signing-service |
155
+ |--------|------------------------|------------------------|
156
+ | Trigger | User action in app | GitHub webhook (PR event) |
157
+ | Data signed | App-specific (SSH challenge, document hash, etc.) | Git merge commit bytes |
158
+ | Signature format | Raw Ed25519 | Ed25519 wrapped in SSH wire format |
159
+ | Signature delivery | Returned to app/user | Pushed to GitHub via Git Data API |
160
+ | Developer interaction with Tide | Direct (signs in app) | None (developers push code normally) |
161
+ | External integration | None | GitHub webhooks, Checks API, Git Data API |
162
+ | UI | App-specific signing UI | PR review + approval dashboard |
163
+
164
+ ## What this scenario does NOT cover
165
+
166
+ - **Local git signing**: Developer-side `git commit -S` with Tide. Blocked by GAP-063 (no Go SDK) and GAP-064 (no CLI auth). The browser-bridge pattern (LEARNINGS-cosign-batch-001 L-08) is a potential future path.
167
+ - **Container image signing**: Use cosign or standard `policy-governed-signing`.
168
+ - **CI/CD pipeline signing**: The service IS the signer. No separate CI integration needed.
169
+ - **Tag signing**: Architecturally similar to commit signing. Same service can sign tags via GitHub Git Data API (`POST /repos/{owner}/{repo}/git/tags`). Not yet documented as a separate flow.
@@ -0,0 +1,133 @@
1
+ # IGA Admin Governance — Anti-Patterns
2
+
3
+ Scenario-specific mistakes for IGA admin governance panels. General Tide anti-patterns (I-01 through I-16, AP-01 through AP-42) still apply.
4
+
5
+ ---
6
+
7
+ ## AP-G01: Skipping IGA enablement
8
+
9
+ **Mistake**: Building the governance panel without enabling IGA on the realm. No change requests are created for admin mutations.
10
+
11
+ **Why it fails**: Without `toggle-iga`, admin actions execute immediately. The governance panel has nothing to review.
12
+
13
+ **Fix**: Enable IGA (`toggle-iga`) during bootstrap before building the panel.
14
+
15
+ ---
16
+
17
+ ## AP-G02: Using JSON for add-review or add-rejection
18
+
19
+ **Mistake**: Sending `application/json` to `/tideAdminResources/add-review` or `/tideAdminResources/add-rejection`.
20
+
21
+ **Why it fails**: These endpoints require `multipart/form-data`. JSON submissions return 415 or are silently ignored.
22
+
23
+ **Fix**: Use `FormData` for add-review and add-rejection. All other mutation endpoints (sign/batch, commit/batch, cancel/batch) use JSON.
24
+
25
+ ---
26
+
27
+ ## AP-G03: Treating sign as commit
28
+
29
+ **Mistake**: Calling only `sign/batch` and assuming the change is applied.
30
+
31
+ **Why it fails**: Signing records an approval. The change does not take effect until `commit/batch` is called after the quorum threshold is met.
32
+
33
+ **Fix**: After sign succeeds and approval count >= threshold, call `commit/batch`.
34
+
35
+ ---
36
+
37
+ ## AP-G04: Caching change-set counts across mutations
38
+
39
+ **Mistake**: Fetching counts once and not refreshing after sign, commit, or cancel.
40
+
41
+ **Why it fails**: Counts change after every mutation. Stale counts cause the UI to show incorrect badge numbers and confuse admins.
42
+
43
+ **Fix**: Refresh counts after every mutation (sign, commit, cancel, add-review, add-rejection).
44
+
45
+ ---
46
+
47
+ ## AP-G05: Ignoring enclave challenge in MultiAdmin mode
48
+
49
+ **Mistake**: Not handling the enclave approval popup when multiple admins exist. The sign response indicates `requiresApprovalPopup: true` but the app treats it as a normal success.
50
+
51
+ **Why it fails**: In MultiAdmin mode, `sign/batch` returns an enclave challenge (base64 `changeSetDraftRequests`). The admin must sign this in the enclave popup and submit via `add-review`. Without this, the approval is not recorded.
52
+
53
+ **Fix**: Check the sign response for `requiresApprovalPopup`. If true, present the enclave challenge to the admin and submit the result via `add-review` (FormData).
54
+
55
+ ---
56
+
57
+ ## AP-G06: Relying on client-side role checks for governance access
58
+
59
+ **Mistake**: Using `hasClientRole('tide-realm-admin', 'realm-management')` on the client side as the only access control for the governance panel.
60
+
61
+ **Why it fails**: Client-side role checks are UI gating only. An attacker can call governance API routes directly. The admin endpoints themselves are protected by TideCloak, but the app's proxy/API routes may not be.
62
+
63
+ **Fix**: Server-side JWT verification on every governance API route. Check `resource_access['realm-management'].roles` includes `tide-realm-admin` in the verified JWT payload.
64
+
65
+ ---
66
+
67
+ ## AP-G07: Calling TideCloak admin API directly from the browser
68
+
69
+ **Mistake**: Making browser-side `fetch` calls directly to TideCloak admin endpoints (e.g., `http://localhost:8080/admin/realms/...`).
70
+
71
+ **Why it fails**: CORS blocks cross-origin requests from the app domain to TideCloak. Even if CORS is configured, exposing the admin API directly to the browser is an unnecessary attack surface.
72
+
73
+ **Fix**: Create same-origin API routes in the app that proxy requests to TideCloak admin endpoints server-side. The proxy forwards the admin's token and returns the TideCloak response.
74
+
75
+ ---
76
+
77
+ ## AP-G08: Using master admin credentials in the governance app
78
+
79
+ **Mistake**: Calling TideCloak admin API with `grant_type=password&username=admin&password=password` from the governance app's API routes.
80
+
81
+ **Why it fails**: Master admin credentials are bootstrap-only. Using them in the app bypasses IGA (master realm is exempt from IGA). Actions performed with master credentials are not governed.
82
+
83
+ **Fix**: Forward the logged-in admin user's token to TideCloak admin API. The admin user must have `tide-realm-admin` on the governed realm.
84
+
85
+ ---
86
+
87
+ ## AP-G09: Treating `tide-realm-admin` as a realm role
88
+
89
+ **Mistake**: Checking `hasRealmRole('tide-realm-admin')` or looking in `realm_access.roles` for it.
90
+
91
+ **Why it fails**: `tide-realm-admin` is a **client role** on the `realm-management` client. It does not appear in `realm_access`.
92
+
93
+ **Fix**: Check `resource_access['realm-management'].roles` in the JWT payload. Client-side: use `hasClientRole('tide-realm-admin', 'realm-management')`.
94
+
95
+ ---
96
+
97
+ ## AP-G10: Not handling licensing and ragnarok request paths
98
+
99
+ **Mistake**: Assuming all change-set requests are under `/tide-admin/change-set/...`.
100
+
101
+ **Why it fails**: Licensing requests use `/tideAdminResources/change-set/licensing/requests`. Ragnarok requests use `/ragnarok/change-set/offboarding/requests`. These are under different path prefixes.
102
+
103
+ **Fix**: Fetch licensing and ragnarok requests from their specific endpoints if the governance panel supports those change-set types.
104
+
105
+ ---
106
+
107
+ ## AP-G11: Building policy management without IGA change-set support
108
+
109
+ **Mistake**: Adding realm policy or role-policy management UI without also building the change-set approval workflow for policy changes.
110
+
111
+ **Why it fails**: Policy mutations (create, delete) also generate IGA change requests that must be approved and committed. Without the change-set workflow, policies stay in pending state.
112
+
113
+ **Fix**: Implement the full change-set lifecycle (sign → commit) for policy change requests. The `POLICY` change-set type covers realm policy mutations.
114
+
115
+ ---
116
+
117
+ ## AP-G12: Omitting DPoP on admin API calls
118
+
119
+ **Mistake**: Using regular `fetch` with `Bearer` token for governance API calls when DPoP is enabled on the realm client.
120
+
121
+ **Why it fails**: DPoP-bound tokens require the DPoP proof header. Without it, TideCloak rejects the request with 400 "DPoP proof is missing".
122
+
123
+ **Fix**: Use `secureFetch` (or the DPoP-aware fetch wrapper) for all governance API calls. Ensure the admin user's token is DPoP-bound.
124
+
125
+ ---
126
+
127
+ ## AP-G13: Single admin assumes governance is complete
128
+
129
+ **Mistake**: Deploying with only one admin user and assuming the governance panel is fully operational.
130
+
131
+ **Why it fails**: With one admin, all changes are FirstAdmin-signed (immediate, no popup). This provides audit logging but not true multi-admin governance. If the goal is quorum enforcement, a single admin defeats the purpose.
132
+
133
+ **Fix**: For real governance, ensure at least two linked admin users. Document that FirstAdmin mode is bootstrap-only or single-admin-acceptable depending on the deployment's security requirements.
@@ -0,0 +1,153 @@
1
+ # IGA Admin Governance — Bootstrap Sequence
2
+
3
+ ---
4
+
5
+ ## Phase 1: TideCloak Infrastructure
6
+
7
+ 1. Start TideCloak container:
8
+ ```bash
9
+ docker run -d --name tidecloak -p 8080:8080 tideorg/tidecloak-dev:latest
10
+ ```
11
+ Wait until `http://localhost:8080` responds.
12
+
13
+ 2. Obtain master admin token:
14
+ ```bash
15
+ TOKEN=$(curl -s -X POST "http://localhost:8080/realms/master/protocol/openid-connect/token" \
16
+ -H "Content-Type: application/x-www-form-urlencoded" \
17
+ -d "grant_type=password&client_id=admin-cli&username=admin&password=password" \
18
+ | jq -r '.access_token')
19
+ ```
20
+
21
+ ---
22
+
23
+ ## Phase 2: Realm Setup
24
+
25
+ 3. Create realm from template:
26
+ ```bash
27
+ curl -s -X POST "http://localhost:8080/admin/realms" \
28
+ -H "Authorization: Bearer $TOKEN" \
29
+ -H "Content-Type: application/json" \
30
+ -d @realm.json
31
+ ```
32
+ **Fail-fast**: Check HTTP status. Abort on non-2xx.
33
+
34
+ Realm template must include: `_tide_enabled` in default composite, `tidebrowser` flow, `link-tide-account-action`, Tide protocol mappers (`tideUserKey`, `vuid`), `UPDATE_PASSWORD` disabled.
35
+
36
+ 4. License realm:
37
+ ```bash
38
+ curl -s -X POST "http://localhost:8080/admin/realms/$REALM/vendorResources/setUpTideRealm" \
39
+ -H "Authorization: Bearer $TOKEN" \
40
+ -H "Content-Type: application/x-www-form-urlencoded" \
41
+ -d "email=admin@example.com"
42
+ ```
43
+ **Content-Type**: `application/x-www-form-urlencoded`, NOT JSON.
44
+
45
+ 5. Enable IGA:
46
+ ```bash
47
+ curl -s -X POST "http://localhost:8080/admin/realms/$REALM/tide-admin/toggle-iga" \
48
+ -H "Authorization: Bearer $TOKEN" \
49
+ -H "Content-Type: application/x-www-form-urlencoded" \
50
+ -d "isIGAEnabled=true"
51
+ ```
52
+
53
+ 6. Approve/commit initial client change request:
54
+ ```bash
55
+ # Get pending client changes
56
+ CLIENTS=$(curl -s "http://localhost:8080/admin/realms/$REALM/tide-admin/change-set/clients/requests" \
57
+ -H "Authorization: Bearer $TOKEN")
58
+ # Extract changeSets array, then sign and commit
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Phase 3: First Admin User
64
+
65
+ 7. Create admin user (include `firstName` and `lastName` to avoid `VERIFY_PROFILE` block):
66
+ ```bash
67
+ curl -s -X POST "http://localhost:8080/admin/realms/$REALM/users" \
68
+ -H "Authorization: Bearer $TOKEN" \
69
+ -H "Content-Type: application/json" \
70
+ -d '{"username":"admin1","enabled":true,"firstName":"Admin","lastName":"One","email":"admin1@example.com"}'
71
+ ```
72
+
73
+ 8. Approve/commit user creation change request.
74
+
75
+ 9. Assign `tide-realm-admin` client role on `realm-management`:
76
+ - Look up user ID
77
+ - Look up `realm-management` client UUID
78
+ - Look up `tide-realm-admin` role within that client
79
+ - Assign the role to the user
80
+
81
+ 10. Approve/commit role assignment change request.
82
+
83
+ 11. Generate invite link:
84
+ ```bash
85
+ curl -s -X POST "http://localhost:8080/admin/realms/$REALM/tideAdminResources/get-required-action-link?userId=$USER_ID&lifespan=43200" \
86
+ -H "Authorization: Bearer $TOKEN" \
87
+ -H "Content-Type: application/json" \
88
+ -d '["link-tide-account-action"]'
89
+ ```
90
+
91
+ 12. First admin opens invite link and completes Tide account linking.
92
+
93
+ ---
94
+
95
+ ## Phase 4: IDP Settings
96
+
97
+ 13. If the governance panel is hosted on a separate domain from TideCloak:
98
+ - Update `CustomAdminUIDomain` on the Tide IDP instance
99
+ - Call `sign-idp-settings`:
100
+ ```bash
101
+ curl -s -X POST "http://localhost:8080/admin/realms/$REALM/vendorResources/sign-idp-settings" \
102
+ -H "Authorization: Bearer $TOKEN"
103
+ ```
104
+ `sign-idp-settings` is ALWAYS required after any Tide IDP config change.
105
+
106
+ ---
107
+
108
+ ## Phase 5: Second Admin (for quorum)
109
+
110
+ 14. Create second admin user (same as steps 7-12 but for admin2).
111
+
112
+ 15. Approve/commit second user creation and role assignment.
113
+ - If still in FirstAdmin mode (one linked admin), signing is immediate.
114
+ - Once second admin is linked, future approvals require MultiAdmin enclave flow.
115
+
116
+ ---
117
+
118
+ ## Phase 6: Adapter Export
119
+
120
+ 16. Export adapter JSON:
121
+ ```bash
122
+ curl -s "http://localhost:8080/admin/realms/$REALM/vendorResources/get-installations-provider?clientId=$CLIENT_UUID&providerId=keycloak-oidc-keycloak-json" \
123
+ -H "Authorization: Bearer $TOKEN" > data/tidecloak.json
124
+ ```
125
+ Verify `jwk` field is present (requires IGA to be enabled).
126
+
127
+ ---
128
+
129
+ ## Phase 7: App Readiness
130
+
131
+ 17. Install SDK, wire provider with DPoP, create redirect handler.
132
+ 18. Implement server-side JWT verification with `tide-realm-admin` role check on governance API routes.
133
+ 19. Build governance UI: change-set list, approve, commit, cancel.
134
+ 20. Optional: add policy management tabs (realm policy, Forseti contracts, role policies).
135
+
136
+ ---
137
+
138
+ ## Pre-User Checklist
139
+
140
+ Before any admin uses the governance panel:
141
+
142
+ - [ ] TideCloak running and reachable
143
+ - [ ] Realm created with `_tide_enabled`, `tidebrowser`, protocol mappers
144
+ - [ ] Realm licensed (`setUpTideRealm`)
145
+ - [ ] IGA enabled (`toggle-iga`)
146
+ - [ ] At least one admin user with `tide-realm-admin` linked
147
+ - [ ] All initial change requests (client, user, role) approved and committed
148
+ - [ ] IDP settings signed (`sign-idp-settings`)
149
+ - [ ] Adapter JSON exported with `jwk` field
150
+ - [ ] App deployed with DPoP-enabled provider
151
+ - [ ] Server-side JWT verification on governance API routes
152
+ - [ ] At least two linked admins for quorum governance (optional for FirstAdmin-only mode)
153
+ - [ ] Change-set list/approve/commit UI functional
@@ -0,0 +1,87 @@
1
+ # IGA Admin Governance Panel — Scenario Manifest
2
+
3
+ id: iga-admin-governance
4
+ title: IGA Admin Governance Panel
5
+ category: admin-governance
6
+ description: Admin dashboard for reviewing, approving, and committing IGA change requests with multi-admin quorum enforcement
7
+
8
+ frameworks:
9
+ - nextjs
10
+ - react-vite
11
+ - vanilla
12
+
13
+ core_patterns:
14
+ - iga
15
+ - change-set
16
+ - quorum
17
+ - multi-admin
18
+ - enclave-signing
19
+ - dpop
20
+ - oidc
21
+ - admin-panel
22
+ - governance
23
+ - approval-workflow
24
+ - policy-management
25
+ - forseti
26
+ - role-policy
27
+
28
+ match_keywords:
29
+ - admin panel
30
+ - admin dashboard
31
+ - admin governance
32
+ - iga panel
33
+ - iga dashboard
34
+ - iga admin
35
+ - change request
36
+ - change requests
37
+ - approval workflow
38
+ - approval dashboard
39
+ - governance panel
40
+ - governance dashboard
41
+ - review and approve
42
+ - multi-admin
43
+ - quorum approval
44
+ - admin approval
45
+ - change-set management
46
+ - change set management
47
+ - policy management panel
48
+ - manage change requests
49
+ - approve changes
50
+ - admin console
51
+
52
+ bootstrap_required: true
53
+ requires_admin_preapproval: true
54
+ requires_iga: true
55
+ requires_e2ee: false
56
+ governance_mode: multi-admin-quorum
57
+
58
+ default_roles:
59
+ - _tide_enabled
60
+ - tide-realm-admin
61
+
62
+ admin_role: tide-realm-admin
63
+ admin_role_type: client
64
+ admin_role_client: realm-management
65
+ min_admins_for_quorum: 2
66
+
67
+ default_playbooks:
68
+ - start-tidecloak-dev
69
+ - bootstrap-realm-from-template
70
+ - initialize-admin-and-link-account
71
+ - add-auth-nextjs-fresh
72
+ - protect-routes-nextjs
73
+ - protect-api-nextjs
74
+ - verify-jwt-server-side
75
+ - setup-iga-admin-panel
76
+ - add-rbac-nextjs
77
+
78
+ default_skills:
79
+ - tide-setup
80
+ - tide-integration
81
+ - tide-route-and-api-protection
82
+ - tide-rbac-and-e2ee
83
+
84
+ discriminating_question: Does the app need a custom admin UI for reviewing and approving IGA change requests (user/role/group/client mutations)? If the built-in TideCloak Admin Console is sufficient, this scenario is not needed.
85
+ valid_only_when: App requires a custom governance dashboard for IGA change request lifecycle management. Not needed if built-in TideCloak Admin Console handles all governance.
86
+
87
+ notes: No encryption layer. This is a governance/admin tool. At least two linked admin users required for quorum. Content-type asymmetry between endpoints (JSON for sign/commit, FormData for add-review/add-rejection). Enclave popup flow required for MultiAdmin signing mode.
@@ -0,0 +1,67 @@
1
+ # IGA Admin Governance — Role & Policy Matrix
2
+
3
+ ---
4
+
5
+ ## Tide Bootstrap Roles
6
+
7
+ | Role | Type | Purpose | Created by | Approved by | Required before first use | Default / optional | Notes |
8
+ |------|------|---------|-----------|-------------|--------------------------|-------------------|-------|
9
+ | `_tide_enabled` | Realm | Enables Tide voucher system for all users | Realm template | Auto (in default composite) | Yes | Default | Must be in `default-roles-{realm}` composite |
10
+ | `tide-realm-admin` | Client (`realm-management`) | Full admin access to TideCloak governance | Built-in | IGA quorum (after first admin) | Yes | Default for admins | This is a **client role**, not a realm role. Do not use `hasRealmRole('tide-realm-admin')`. |
11
+
12
+ ---
13
+
14
+ ## Application Roles
15
+
16
+ This scenario does not define app-specific roles beyond the admin role. The governance panel serves admins who already have `tide-realm-admin`.
17
+
18
+ Apps that embed the governance panel alongside user-facing features may add their own application roles (e.g., `admin`, `manager`). These are separate from `tide-realm-admin` and do not affect IGA governance behavior.
19
+
20
+ ---
21
+
22
+ ## Key rules
23
+
24
+ 1. **`tide-realm-admin` is a client role on `realm-management`**. Check it with `hasClientRole('tide-realm-admin', 'realm-management')` on the client side, or check `resource_access['realm-management'].roles` in the server-side JWT payload.
25
+
26
+ 2. **Quorum requires at least two linked admin users.** A single admin operates in FirstAdmin mode (VRK-signed, no popup). Two or more admins operate in MultiAdmin mode (enclave challenge popup).
27
+
28
+ 3. **All admin mutations in an IGA-enabled realm create draft change requests.** These must be signed and committed before they take effect. The governance panel is the tool for this.
29
+
30
+ 4. **Change-set types are fixed by TideCloak.** The app does not define new types. Known types: `USER`, `USER_ROLE`, `COMPOSITE_ROLE`, `CLIENT`, `GROUP_ROLE`, `GROUP_MEMBERSHIP`, `GROUP_MOVE`, `REALM_LICENSE`, `POLICY`, `DEFAULT_ROLES`, `REALM_SETTINGS`, `RAGNAROK`.
31
+
32
+ 5. **`DEFAULT_ROLES` and role creation are ACTIVE (auto-approved).** They appear in the change-set list for audit but do not require sign/commit. All other types require quorum approval.
33
+
34
+ 6. **Quorum threshold**: `max(1, floor(TotalAdmins * 0.7))`. Not configurable by the app.
35
+
36
+ ---
37
+
38
+ ## Policy Layer (optional features)
39
+
40
+ The governance panel may optionally include policy management. These are NOT required for the core change-request workflow.
41
+
42
+ | Feature | Endpoint pattern | Purpose | Notes |
43
+ |---------|-----------------|---------|-------|
44
+ | Realm policy | `GET/POST/DELETE /tide-admin/realm-policy/*` | View and manage the realm-level Forseti policy | Lifecycle: none → pending → committed. Requires sign/commit flow. |
45
+ | Policy templates | `GET/POST/PUT/DELETE /tide-admin/policy-templates/*` | CRUD for reusable policy templates | Templates are building blocks. Not policies themselves. |
46
+ | SSH/role policies | `GET/PUT/DELETE /tide-admin/ssh-policies` | Attach Forseti contracts to specific roles | Despite the name, not SSH-specific. Sets approval type, execution type, threshold. |
47
+ | Forseti contracts | `GET/PUT /tide-admin/forseti-contracts` | List and register Forseti contracts | Contracts are stored server-side. SDK signing flow deploys them to ORKs. |
48
+ | Role policies view | `GET /tide-admin/role-policies` | Combined view of all role-policy attachments | Read-only summary. Useful for auditing which roles have policies attached. |
49
+
50
+ ---
51
+
52
+ ## Change-Set Endpoints (core governance)
53
+
54
+ | Operation | Endpoint | Method | Content-Type | Notes |
55
+ |-----------|---------|--------|-------------|-------|
56
+ | List counts | `/tide-admin/change-set/counts` | GET | — | Returns per-type counts |
57
+ | List all requests | `/tide-admin/change-set/all/requests` | GET | — | Returns all pending changes grouped by type |
58
+ | List by type | `/tide-admin/change-set/{type}/requests` | GET | — | `{type}` = users, roles, clients, groups |
59
+ | Sign (approve) | `/tide-admin/change-set/sign/batch` | POST | `application/json` | Body: `{ changeSets: [...] }` |
60
+ | Commit | `/tide-admin/change-set/commit/batch` | POST | `application/json` | Body: `{ changeSets: [...] }` |
61
+ | Cancel | `/tide-admin/change-set/cancel/batch` | POST | `application/json` | Body: `{ changeSets: [...] }` |
62
+ | Add review (enclave) | `/tideAdminResources/add-review` | POST | **`multipart/form-data`** | Used after enclave challenge in MultiAdmin mode |
63
+ | Add rejection | `/tideAdminResources/add-rejection` | POST | **`multipart/form-data`** | Content-type asymmetry: NOT JSON |
64
+ | Activity | `/tide-admin/change-set/{id}/activity` | GET | — | Returns approvals, rejections, comments |
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 |