@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.
- package/GAP_REGISTER.md +117 -0
- package/README.md +38 -0
- package/adapters/AGENTS.md +241 -0
- package/adapters/CLAUDE.md +146 -0
- package/adapters/replit.md +224 -0
- package/canon/anti-patterns.md +2133 -0
- package/canon/concepts.md +816 -0
- package/canon/custom-contracts.md +533 -0
- package/canon/delegation.md +195 -0
- package/canon/feature-mapping.md +637 -0
- package/canon/framework-matrix.md +1125 -0
- package/canon/invariants.md +851 -0
- package/canon/redirect-handler.md +254 -0
- package/canon/tidecloak-bootstrap.md +287 -0
- package/canon/tidecloak-endpoints.md +294 -0
- package/canon/troubleshooting.md +1494 -0
- package/canon/version-policy.md +89 -0
- package/mcp-server/dist/index.d.ts +2 -0
- package/mcp-server/dist/index.js +605 -0
- package/package.json +45 -0
- package/playbooks/add-auth-nextjs-existing.md +799 -0
- package/playbooks/add-auth-nextjs-fresh.md +654 -0
- package/playbooks/add-rbac-nextjs.md +190 -0
- package/playbooks/bootstrap-realm-from-template.md +170 -0
- package/playbooks/configure-e2ee-roles-and-policies.md +196 -0
- package/playbooks/deploy-tidecloak-docker.md +792 -0
- package/playbooks/diagnose-broken-login.md +234 -0
- package/playbooks/diagnose-missing-roles-or-claims.md +253 -0
- package/playbooks/initialize-admin-and-link-account.md +235 -0
- package/playbooks/migrate-from-existing-auth.md +198 -0
- package/playbooks/protect-api-nextjs.md +451 -0
- package/playbooks/protect-routes-nextjs.md +544 -0
- package/playbooks/setup-forseti-e2ee.md +756 -0
- package/playbooks/setup-iga-admin-panel.md +344 -0
- package/playbooks/setup-server-delegation.md +142 -0
- package/playbooks/start-tidecloak-dev.md +130 -0
- package/playbooks/verify-jwt-server-side.md +439 -0
- package/prompts/add-admin-approval-flow.md +50 -0
- package/prompts/build-private-customer-portal.md +85 -0
- package/prompts/migrate-generic-auth-to-tide.md +67 -0
- package/prompts/secure-existing-app.md +80 -0
- package/reference-apps/INDEX.md +87 -0
- package/reference-apps/encrypted-communication/anti-patterns.md +123 -0
- package/reference-apps/encrypted-communication/bootstrap-sequence.md +152 -0
- package/reference-apps/encrypted-communication/manifest.yaml +100 -0
- package/reference-apps/encrypted-communication/role-policy-matrix.md +80 -0
- package/reference-apps/encrypted-communication/scenario.md +134 -0
- package/reference-apps/git-pr-signing-service/anti-patterns.md +61 -0
- package/reference-apps/git-pr-signing-service/bootstrap-sequence.md +157 -0
- package/reference-apps/git-pr-signing-service/manifest.yaml +80 -0
- package/reference-apps/git-pr-signing-service/role-policy-matrix.md +99 -0
- package/reference-apps/git-pr-signing-service/scenario.md +169 -0
- package/reference-apps/iga-admin-governance/anti-patterns.md +133 -0
- package/reference-apps/iga-admin-governance/bootstrap-sequence.md +153 -0
- package/reference-apps/iga-admin-governance/manifest.yaml +87 -0
- package/reference-apps/iga-admin-governance/role-policy-matrix.md +67 -0
- package/reference-apps/iga-admin-governance/scenario.md +126 -0
- package/reference-apps/organisation-password-manager/anti-patterns.md +71 -0
- package/reference-apps/organisation-password-manager/bootstrap-sequence.md +127 -0
- package/reference-apps/organisation-password-manager/manifest.yaml +86 -0
- package/reference-apps/organisation-password-manager/role-policy-matrix.md +59 -0
- package/reference-apps/organisation-password-manager/scenario.md +107 -0
- package/reference-apps/policy-governed-signing/anti-patterns.md +67 -0
- package/reference-apps/policy-governed-signing/bootstrap-sequence.md +128 -0
- package/reference-apps/policy-governed-signing/manifest.yaml +78 -0
- package/reference-apps/policy-governed-signing/role-policy-matrix.md +62 -0
- package/reference-apps/policy-governed-signing/scenario.md +113 -0
- package/skills/tide-diagnostics/SKILL.md +99 -0
- package/skills/tide-integration/SKILL.md +136 -0
- package/skills/tide-learning-capture/SKILL.md +174 -0
- package/skills/tide-rbac-and-e2ee/SKILL.md +214 -0
- package/skills/tide-reviewer/SKILL.md +133 -0
- package/skills/tide-route-and-api-protection/SKILL.md +201 -0
- package/skills/tide-scenario-resolver/SKILL.md +81 -0
- package/skills/tide-setup/SKILL.md +218 -0
- 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 |
|