@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
package/GAP_REGISTER.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Gap Register
|
|
2
|
+
|
|
3
|
+
Uncertainties, missing information, and open questions from source audit.
|
|
4
|
+
Updated: 2026-04-13 (full sync pass: status count corrected, no new gaps)
|
|
5
|
+
|
|
6
|
+
Controlled status set:
|
|
7
|
+
- `RESOLVED_BY_KEYLESSH` — fully answered by exemplar evidence; no runtime confirmation needed
|
|
8
|
+
- `RESOLVED_BY_VENDOR` — answered by vendor clarification; suitable for operational drafting
|
|
9
|
+
- `RESOLVED_BY_NORMATIVE_DOC` — answered by normative documentation (e.g., CHANGE_REQUEST_API.md)
|
|
10
|
+
- `RESOLVED_BY_MULTI_EXEMPLAR` — answered by consistent evidence across two or more exemplars
|
|
11
|
+
- `PARTIALLY_RESOLVED_BY_KEYLESSH` — exemplar provides partial evidence; gaps remain
|
|
12
|
+
- `PARTIALLY_RESOLVED_BY_MULTI_EXEMPLAR` — multiple exemplars provide partial evidence; gaps remain
|
|
13
|
+
- `STILL_UNRESOLVED` — no evidence from any source
|
|
14
|
+
- `DOCS_ONLY_CONTRADICTION` — docs say one thing, implementation says another
|
|
15
|
+
- `REQUIRES_RUNTIME_VALIDATION` — exemplar suggests an answer but single-app evidence is insufficient to generalize
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Gap Table
|
|
20
|
+
|
|
21
|
+
| Gap ID | Description | Status | Evidence Source | Next Action |
|
|
22
|
+
|--------|------------|--------|-----------------|-------------|
|
|
23
|
+
| GAP-001 | Authentication API omits all Tide-specific flows | RESOLVED_BY_VENDOR | `init-tidecloak.sh` reveals undocumented admin endpoints. `server/auth.ts` shows DPoP verification. `canon/tidecloak-endpoints.md` now documents 94 endpoints across 8 resource classes. `canon/delegation.md` documents token exchange flow. | Resolved. All Tide-specific auth endpoints documented in `canon/tidecloak-endpoints.md`. Source API docs remain incomplete but pack has full operational coverage. |
|
|
24
|
+
| GAP-002 | Management API omits IGA endpoints | RESOLVED_BY_NORMATIVE_DOC | CHANGE_REQUEST_API.md provides complete REST API with request/response schemas for all change-set operations, policy management, TS client. | Resolved. Canon updated. |
|
|
25
|
+
| GAP-003 | Quorum threshold formula inconsistency | PARTIALLY_RESOLVED_BY_KEYLESSH | `start.sh`: threshold is deployment-configurable. Three distinct concepts: admin quorum (70%), Fabric operational threshold (T/N), SSH policy threshold (per-role). | Document the three-layer distinction. CHANGE_REQUEST_API.md confirms SSH policy `threshold` is distinct from IGA admin quorum. |
|
|
26
|
+
| GAP-004 | Error handling undocumented across all SDKs | RESOLVED_BY_VENDOR | No formal error code taxonomy. One custom class: `NetworkError` (extends `Error`, includes `.response`). All other errors are plain `Error` with string messages. Retryable: `NetworkError`, `enclave.networkFailure`, `enclave.throttled`, `enclave.thresholdTimeoutFailure`, `authRefreshError` (once). Fatal: init errors, input validation, missing roles (`"User has not been given any access to '${tag}'"`), policy violations (`BadPolicy.*`, `OutOfGasException`, `PolicyDecision.Deny()`), mode restrictions. Token/auth errors require re-login. Event listeners (`authError`, `authRefreshError`, `initError`) are the primary async error channel. No built-in retry logic in SDK. | Resolved. Canon updated with error catalog. Adapters pending. |
|
|
27
|
+
| GAP-005 | `npm init @tidecloak/nextjs@latest` behavior undocumented | RESOLVED_BY_VENDOR | Vendor clarification provided complete workflow. forseti-crypto-quickstart confirms `create-forseti-nextjs` scaffolding pattern. | Resolved. |
|
|
28
|
+
| GAP-006 | Token lifetime and session timeout defaults | RESOLVED_BY_VENDOR | `accessTokenLifespan: 600` confirmed in all four exemplar realm.json files. | Resolved. |
|
|
29
|
+
| GAP-007 | Forseti gas metering undefined | RESOLVED_BY_VENDOR | Gas metering documented as part of GAP-008 five-layer sandbox model: default 50,000 gas limit. `Claim(key)` = 5 gas, `Log(message)` = 25-30 gas, `ChargeTime()` = units per ms. Throws `OutOfGasException` when exhausted. OS-level CPU/memory limits also enforced via VmHost rlimits. | Resolved. Already incorporated into canon Forseti section. |
|
|
30
|
+
| GAP-008 | Forseti sandbox namespace blocklist incomplete | RESOLVED_BY_VENDOR | Five-layer sandbox: Roslyn compilation, IL vetting (block-list: `System.IO`, `System.Net`, `System.Diagnostics`, `System.Threading`, `System.Reflection`, `System.Runtime.InteropServices`, `System.Reflection.Emit`, `Microsoft.Win32`; hard-blocked: `System.Console`, `System.Runtime.CompilerServices.Unsafe`; non-determinism blocked by default), AssemblyLoadContext isolation, VmHost process isolation (OS rlimits), gas metering (default 50k). Compile succeeds but IL vetting rejects with `BadPolicy.ForbiddenCall`. Optional allow-list mode; forbidden always wins. | Resolved. Canon updated. |
|
|
31
|
+
| GAP-009 | Session key lifecycle undocumented | RESOLVED_BY_VENDOR | Two distinct concepts: (1) Data encryption key — fresh per `doEncrypt()` call, no reuse. <32B: fresh ElGamal random scalar. >=32B: fresh 32-byte AES key via `crypto.getRandomValues()`, used once, discarded. No key state persists after call returns. (2) Session key (`t.ssk`) — Ed25519 key pair in doken, private component lives in ORK enclave iframe. Created at login, destroyed on tab close/logout. Authenticates user to ORKs but does NOT encrypt data. Enclave is singleton on `TideCloak` instance, created lazily or eagerly at init. Multi-tab: each tab has independent enclave. Session key mismatch triggers full re-login. Tidewarden `tide_encrypted_key` is app-specific, not SDK standard. | Resolved. Canon updated. Adapters have no encryption key state to manage. |
|
|
32
|
+
| GAP-010 | AzureAD integration incomplete | STILL_UNRESOLVED | No exemplar uses AzureAD. | Still needs TideCloak-side federation setup. |
|
|
33
|
+
| GAP-011 | Grafana integration incomplete | STILL_UNRESOLVED | No exemplar uses Grafana. | Still needs complete procedure. |
|
|
34
|
+
| GAP-012 | Silent SSO failure behavior | PARTIALLY_RESOLVED_BY_KEYLESSH | `AuthContext.tsx`: corrupted state detection, `?reset=true`, 10s timeout. | Document defensive startup pattern. Iframe-specific failure modes still undocumented. |
|
|
35
|
+
| GAP-013 | E2EE payload size limits | RESOLVED_BY_VENDOR | No application-level max. Payloads <32 bytes use ElGamal directly; >=32 bytes use hybrid AES-256-GCM + ElGamal. Both `Uint8Array` (binary) and strings supported. Practical ceiling is ASP.NET Core Kestrel default (~28.6 MB request body). Self-encryption and policy-based encryption share the same size characteristics. | Resolved. Canon updated. Recommend boundary eval test (e.g., 10 MB payload). |
|
|
36
|
+
| GAP-014 | Disaster recovery procedures | STILL_UNRESOLVED | No exemplar has DR procedures. | Still needs recovery runbook. |
|
|
37
|
+
| GAP-015 | "BEd25531" curve name typo | RESOLVED_BY_WHITEPAPER | Whitepaper consistently uses "BEd255475" across 6+ files. Architecture.md had a typo ("BEd25531"). Corrected. | Resolved. Architecture.md fixed. |
|
|
38
|
+
| GAP-016 | PRISM throttling thresholds | STILL_UNRESOLVED | No exemplar configures PRISM throttling. | Still needs throttle configuration docs. |
|
|
39
|
+
| GAP-017 | Doken lifecycle | RESOLVED_BY_VENDOR | Doken `exp` copied directly from SSO access token `exp` at issuance — they share the same expiration. Auto-reissued on token refresh; SDK handles transparently including mid-operation refresh via `dokenRefreshCallback`. No independent TTL config. Revocation operates at signature level: EdDSA signature added to per-user blocklist in `RevokedAuthorizerService`. Role claims (`realm_access`, `resource_access`) are snapshot at issuance, only update on next refresh — explains 120s delay in F6. Fully-expired doken cannot be refreshed (must reauthenticate). Structure: `{ alg: "EdDSA", typ: "doken" }`, payload includes `t.ssk`, `tideuserkey`, `vuid`, `t.uho`, `exp`, `aud` (VVKID), `realm_access`, `resource_access`. | Resolved. Canon updated. |
|
|
40
|
+
| GAP-018 | Contract debugging and error propagation | RESOLVED_FOR_EVALS | keylessh: errors thrown on failed sign. CHANGE_REQUEST_API.md: Forseti contract CRUD documented; `contractHash` as SHA512. forseti-crypto-quickstart: `PolicyDecision.Deny("message")` as error surface. test-cases F11: denial messages propagated to client. Batch-02 Q-01 documented ORK error codes that propagate to client: `BadPolicy.ForbiddenCall:{target}`, `BadPolicy.EntryTypeNotFound`, `BadPolicy.BudgetExceeded`, `VmHost.Timeout`, `OutOfGasException`. These arrive as opaque strings, not structured errors. | Client-visible error catalog sufficient for eval pass/fail criteria. Roslyn/IL diagnostics never surface to client — compilation-error evals are stretch goals asserting failure-to-sign only. See `notes/eval-blocker-resolution.md`. |
|
|
41
|
+
| GAP-019 | Key healing limits | STILL_UNRESOLVED | No exemplar configures key healing. | Still needs staleness threshold docs. |
|
|
42
|
+
| GAP-020 | Account recovery email details | STILL_UNRESOLVED | No exemplar implements account recovery. | Still needs email delivery docs. |
|
|
43
|
+
| GAP-021 | Ragnarok post-transition details | STILL_UNRESOLVED | No exemplar implements Ragnarok. | Still needs transition plan. |
|
|
44
|
+
| GAP-022 | C# SDK lacks Tide-specific content | PARTIALLY_RESOLVED_BY_MULTI_EXEMPLAR | Three contracts across two exemplars demonstrate comprehensive C# API surface: `IAccessPolicy`, `DataContext`, `ExecutorContext`, `ApproversContext`, `PolicyDecision`, `DokenDto`, `DokenDto.WrapAll()`, `Decision.*`, `TideKey.From()`, `Utils.GetEpochSeconds()`, `ExecutionType`, `ApprovalType`. | Not a standalone SDK package — types are available only within Forseti contract context. |
|
|
45
|
+
| GAP-023 | Keycloak-to-TideCloak migration path | STILL_UNRESOLVED | No exemplar is a migration. All are greenfield. | Still needs migration guide. |
|
|
46
|
+
| GAP-024 | Multi-tenant / multi-realm Fabric interaction | STILL_UNRESOLVED | All exemplars use single realm. tidewarden uses org-scoped roles (`org:{uuid}:role`) but still single realm. | Still needs multi-tenancy docs. |
|
|
47
|
+
| GAP-025 | VVK ORK 12-gate verification details | STILL_UNRESOLVED | No exemplar reveals gate list. | Still needs full gate list and error behavior. |
|
|
48
|
+
| GAP-026 | Adapter JSON field documentation | RESOLVED_BY_KEYLESSH | `tidecloakConfig.ts` TypeScript interface. forseti-crypto-quickstart provides additional field: `client-origin-auth-*` (signed origin binding). | Record as canon. Additional field `client-origin-auth-*` noted (GAP-048). |
|
|
49
|
+
| GAP-027 | Production deployment guide | PARTIALLY_RESOLVED_BY_KEYLESSH | keylessh `DEPLOYMENT.md` shows container patterns. tidewarden shows Docker multi-stage builds + Dockerfile.acr for ACR. | Extract reusable patterns. Full checklist still needed. |
|
|
50
|
+
| GAP-028 | CSP requirements for Tide SWE undocumented | RESOLVED_BY_VENDOR | Vendor clarification: `frame-src '*'` required for ORK re-homing. | Resolved. |
|
|
51
|
+
| GAP-029 | Tide-specific admin endpoints not in API docs | RESOLVED_BY_VENDOR | keylessh: `setUpTideRealm`, `toggle-iga`, `get-required-action-link`, `get-installations-provider`. forseti-crypto-quickstart: `sign-idp-settings`, `identity-provider/instances/tide` GET/PUT. tidewarden: `init-cert` accepts `initCertSig` + `doken`; voucher path `tidevouchers/fromUserSession?sessionId={sid}`. CHANGE_REQUEST_API.md: change-set schemas now documented. `setUpTideRealm` fully documented (vendor confirmation, batch-02 Q-03). `get-required-action-link` documented in `canon/tidecloak-endpoints.md`: `POST .../tideAdminResources/get-required-action-link?userId={id}&lifespan=43200`, body `["link-tide-account-action"]`. | Resolved. All admin endpoints documented in `canon/tidecloak-endpoints.md`. |
|
|
52
|
+
| GAP-030 | Account linking onboarding step undocumented | RESOLVED_BY_VENDOR | Vendor clarification confirmed scope. test-cases F2 provides full E2E account linking test. | Resolved. |
|
|
53
|
+
| GAP-031 | `_tide_enabled` role requirement undocumented | RESOLVED_BY_VENDOR | Vendor clarification: `setUpTideRealm` runs after realm import and does not auto-create `_tide_enabled`. Declare `_tide_enabled` in the `realm.json` template so the role already exists when setup continues. If omitted, it must be created and assigned manually afterward. Exemplars that omit it may rely on post-import setup, a different provisioning path, or incomplete checked-in realm templates. | Resolved. Update canon and templates to declare `_tide_enabled` in realm.json. |
|
|
54
|
+
| GAP-032 | DPoP server-side verification pattern undocumented | RESOLVED_BY_VENDOR | Both ES256 and EdDSA supported. ES256 is the default. Algorithm negotiated at runtime via server's `dpop_signing_alg_values_supported` OIDC metadata. Apps may override with `useDPoP.alg`. EdDSA has automatic fallback logic if Ed25519 key generation fails. ES384/ES512 declared in types but not implemented (would throw). | Resolved. Update canon DPoP section with canonical guidance: ES256 default, EdDSA supported. |
|
|
55
|
+
| GAP-033 | Adapter JSON JWKS embedding undocumented | RESOLVED_BY_VENDOR | `jwk` field present when IGA is enabled on the realm (`isIGAEnabled == true` and `tide-vendor-key` component exists). Confirmed across all exemplar adapter JSON files. Corrected by batch-02 Q-04: jwk injection is conditional on IGA. | Resolved. Canon updated. |
|
|
56
|
+
| GAP-034 | Threshold is deployment-configurable (not fixed 14/20) | RESOLVED_FOR_TEMPLATES | All exemplars use T=3/N=5 for test. Docs/whitepaper present 14/20 as if fixed. Canon (I-02) and deploy playbook already document `THRESHOLD_T`/`THRESHOLD_N` env vars. Template guidance settled in `notes/template-blocker-resolution.md`. | Resolved for template purposes. Docs-only contradiction remains in whitepaper but does not block code generation. |
|
|
57
|
+
| GAP-035 | Change-set API workflow undocumented | RESOLVED_BY_NORMATIVE_DOC | CHANGE_REQUEST_API.md provides full lifecycle (DRAFT->PENDING->APPROVED->ACTIVE), all endpoints, all types, TypeScript client. | Resolved. Canon updated. |
|
|
58
|
+
| GAP-036 | Tide protocol mappers not documented for realm setup | RESOLVED_BY_VENDOR | Vendor confirmed auto-creation. All exemplar realm.json files include mappers. | Resolved. |
|
|
59
|
+
| GAP-037 | Corrupted auth state recovery pattern undocumented | PARTIALLY_RESOLVED_BY_KEYLESSH | keylessh `AuthContext.tsx` localStorage scan, `?reset=true`. | Document as recommended SPA pattern, not Tide requirement. |
|
|
60
|
+
| GAP-038 | `add-rejection` uses multipart/form-data while sign/commit/cancel use JSON | RESOLVED_BY_NORMATIVE_DOC | CHANGE_REQUEST_API.md documents the asymmetry. tidecloakApi.ts (forseti-crypto-quickstart) confirms `addApproval` uses FormData. Both `add-review` and `add-rejection` use `multipart/form-data`, all other mutation endpoints use JSON. | Resolved. Canon and playbooks already document the content-type constraint. Adapters pending. LOW severity. |
|
|
61
|
+
| GAP-039 | `initCert` format and generation procedure undocumented | RESOLVED_BY_VENDOR | Endpoint: `POST /admin/realms/{realm}/tide-iga-provider/role-policy/{roleId}/init-cert`. JSON body: `initCert` (required, base64-encoded signed policy bytes) and `initCertSig` (optional, base64-encoded VVK signature). No `doken` field — endpoint is pure storage, persists to `TideRoleDraftEntity`. Returns 200 `{"message":"initCert updated for role <roleId>"}`, 404 if role not found, 400 if initCert missing. Consumed downstream during multi-admin change-set signing to produce vendor-signed access proofs. Note: path is `tide-iga-provider`, not `tide-admin`. JS admin client does not have this wired up — must use raw HTTP. | Resolved. Canon updated. Adapters pending. |
|
|
62
|
+
| GAP-040 | SSH policy `threshold` vs IGA admin quorum are distinct concepts | PARTIALLY_RESOLVED_BY_MULTI_EXEMPLAR | CHANGE_REQUEST_API.md: SSH policy `threshold` is per-role approval count. SetupIGA.md: admin quorum is `max(1, floor(N*0.7))`. test-cases F4 confirms admin policy threshold=1 for creating new policies, while new policy has threshold=2 for later use. | Canon must clarify these are independent. |
|
|
63
|
+
| GAP-041 | Which admin actions trigger draft creation vs immediate execution | RESOLVED_BY_VENDOR | 18 specific admin API actions create drafts when IGA is enabled on a non-master realm. Not all mutating endpoints — a finite set via custom JPA Model Provider SPIs. Two categories: DRAFT (requires quorum sign/commit) and ACTIVE (auto-approved, audit-only). DRAFT actions: create user, grant/revoke role to user, add/remove user from group, delete role (if has users), add/remove composite role, grant/revoke role to group, move group, create client (when users exist), toggle client full-scope, update client scope mappings, trigger license rotation, policy changes from user-role mappings. ACTIVE actions: create realm role, create client role. Master realm and IGA-disabled realms are exempt. | Resolved. Canon updated with full list. |
|
|
64
|
+
| GAP-042 | `@tideorg/js` vs `@tidecloak/js` for Models/Contracts imports | RESOLVED_BY_MULTI_EXEMPLAR | forseti-crypto-quickstart and tidewarden both import `Models` and `Contracts` from `@tideorg/js`, not `@tidecloak/js`. Webpack workaround in forseti-crypto-quickstart explicitly notes re-export mismatch. Canon is wrong. | Fix canon SDK Internals section. |
|
|
65
|
+
| GAP-043 | Two encryption role naming patterns: `self*` vs non-self | RESOLVED_BY_MULTI_EXEMPLAR | test-cases F7: `_tide_<tag>.selfencrypt`/`selfdecrypt` for self-encryption (user-bound, no policy bytes). test-cases F9: `_tide_<tag>.encrypt`/`decrypt` for policy-based encryption (shared, requires policy bytes). Canon only documents the self-variant. | Add non-self pattern to canon Voucher Gates and E2EE sections. |
|
|
66
|
+
| GAP-044 | `providerId` discrepancy for adapter export | RESOLVED_BY_VENDOR | Only one valid provider ID: `keycloak-oidc-keycloak-json`. The string `tidecloak-oidc-keycloak-json` does not exist in the codebase. TideCloak post-processes the standard provider output via the vendor endpoint (`get-installations-provider`) to inject Tide fields (`vendorId`, `jwk`, `homeOrkUrl`, `client-origin-auth-*`). The `jwk` field is only added when IGA is enabled. Any reference to `tidecloak-oidc-keycloak-json` is a typo or outdated. | Resolved. Fix keylessh reference in canon and templates. Use `keycloak-oidc-keycloak-json` everywhere. |
|
|
67
|
+
| GAP-045 | `_tide_enabled` absent from all new exemplar realm.json files | RESOLVED_BY_VENDOR | Vendor clarification: declare `_tide_enabled` in realm.json template. Exemplars that omit it may rely on post-import provisioning or have incomplete checked-in templates. See GAP-031. | Resolved. Aligned with GAP-031. |
|
|
68
|
+
| GAP-046 | `GenericResourceAccessThresholdRoleContract` undocumented | RESOLVED_BY_VENDOR | Built-in default contract (ID: `GenericResourceAccessThresholdRole:1`). One of four pre-registered contracts in the ORK factory. Policy params: `role` (string, client role name), `resource` (string, client/resource ID), `threshold` (number, min approvers). Only implements `ValidateApprovers` — iterates approver dokens checking `resource_access[resource].roles.includes(role)`, throws if count < threshold. `ValidateData` is no-op. `ValidateExecutor` not implemented (inherited stub throws). Checks **client roles** (not realm roles) — for realm roles use sibling `GenericRealmAccessThresholdRoleContract`. Use for simple role-gated multi-approval. Write custom contract for executor validation, data validation, or complex logic. | Resolved. Canon updated with default contract table. |
|
|
69
|
+
| GAP-047 | `CustomAdminUIDomain` + `sign-idp-settings` endpoint undocumented | RESOLVED_BY_VENDOR | `sign-idp-settings` is ALWAYS required after any Tide IDP config change (logo, background, backup toggle, custom admin domain, client origin changes). Signs all IDP settings with vendor key via ORK network. Without it, enclave rejects settings as unsigned. `CustomAdminUIDomain` is APP-SPECIFIC: only needed when a separate app (not built-in Admin Console) hosts the change-set approval UI or needs post-LinkTideAccount redirects. Signs 6 items: loginURL, linkTideURL, changeSetURL, CustomAdminUIDomain (if set), all client web origins, vendor settings. Requires active VRK/license. | Resolved. Update init playbook: `sign-idp-settings` is required step; `CustomAdminUIDomain` is conditional. |
|
|
70
|
+
| GAP-048 | `client-origin-auth-*` adapter JSON field undocumented | RESOLVED_BY_VENDOR | ORK-network-produced signature attesting a web origin is authorized for a client. Generated during `sign-idp-settings`: each client's allowed origins are included in the signing draft sent to ORKs via `Midgard.SignModel`; a per-origin signature is returned. Key format: `client-origin-auth-{full origin URL}`, value: base64-encoded signature. SDK requires it as `clientOriginAuth` for `RequestEnclave`/`ApprovalEnclave` initialization — without it, enclave init fails. Config loader must select entry matching `window.location.origin`. One entry per allowed origin per client; no browser-specific variants in TideCloak codebase. Internal storage key: `clientAuth:{clientId}{origin}`, stripped to `client-origin-auth-{origin}` in adapter JSON. | Resolved. Canon updated. |
|
|
71
|
+
| GAP-049 | DPoP algorithm: EdDSA vs ES256 | RESOLVED_BY_VENDOR | Both supported. ES256 is default. See GAP-032 for full details. Algorithm negotiated via `dpop_signing_alg_values_supported`; overridable with `useDPoP.alg`. EdDSA has fallback logic. ES384/ES512 not implemented. | Resolved. Aligned with GAP-032. |
|
|
72
|
+
| GAP-050 | DPoP verification uses `createRemoteJWKSet` in test-cases | RESOLVED_BY_VENDOR | Three distinct verification targets: (1) Access token JWT — use `createLocalJWKSet(config.jwk)` only. (2) DPoP proof — verified against ephemeral `jwk` embedded in the proof header per RFC 9449. (3) DPoP binding — `cnf.jkt` thumbprint comparison. **Pack policy**: `createRemoteJWKSet` is forbidden for this pack. If `jwk` is missing from adapter JSON, this is a setup/bootstrap failure — re-export adapter with IGA enabled. Do not fall back to remote JWKS. The test-cases exemplar uses `createRemoteJWKSet` but this pack treats it as an anti-pattern. | Resolved. I-04 updated to local-only (no remote fallback). |
|
|
73
|
+
| GAP-051 | Voucher endpoint `tidevouchers/fromUserSession` undocumented | RESOLVED_BY_VENDOR | TideCloak-specific endpoint from `tidecloak-key-provider` extension. For `@tidecloak/js` apps, SDK constructs voucher URL internally (`#getVoucherUrl()` reads `sid` from access token, builds `{realmUrl}/tidevouchers/fromUserSession?sessionId={sid}`). App developers do NOT need to construct this URL. Non-TideCloak integrations must provide `voucherURL` to Heimdall SDK directly. Endpoint does role-based voucher authorization: `signin`/`updateaccount` always allowed; `vendorsign` requires `_tide_*` or authorizer or `tide-realm-admin` role; `vendordecrypt` requires `_tide_*.selfdecrypt` role. Two sub-endpoints: `fromUserSession` (post-login operations) and `fromAuthSession` (login flows). | Resolved. Canon updated. Voucher concept is universal but this endpoint is TideCloak-specific. |
|
|
74
|
+
| GAP-052 | `tide_encrypted_key` rotation lifecycle undocumented | PARTIALLY_RESOLVED_BY_MULTI_EXEMPLAR | tidewarden stores per-user `tide_encrypted_key` (vault key encrypted by Tide). Client POSTs it on first setup, server returns it on every login/sync. | Key rotation, re-encryption after password change, and multi-device scenarios undocumented. |
|
|
75
|
+
| GAP-053 | Browser-specific `signedClientOrigin` variants | RESOLVED_BY_VENDOR | The `signedClientOriginChrome`/`signedClientOriginFirefox` pattern does NOT appear in the TideCloak codebase. TideCloak adapter JSON uses a single unified `client-origin-auth-{origin}` per origin with no browser-specific variants. The Tidewarden browser-specific fields are a Tidewarden-specific concern, not a TideCloak/ORK behavior. | Resolved. Tidewarden-specific; do not generalize. |
|
|
76
|
+
| GAP-054 | `TIDE_VOUCHER_BASE_URL` override for PNA tunneling | RESOLVED_BY_VENDOR | Tidewarden-specific deployment concern for Chrome Private Network Access (PNA) workaround. Not a universal Tide concept. Standard `@tidecloak/js` apps do not need this — SDK constructs voucher URLs automatically. | Resolved. Tidewarden-specific; do not include in canon or general skills. |
|
|
77
|
+
| GAP-055 | `oauth2-dpop` npm package for DPoP verification | PARTIALLY_RESOLVED_BY_MULTI_EXEMPLAR | test-cases `dpop-protected/route.ts` uses `oauth2-dpop` package for server-side DPoP proof verification. Simpler than manual verification. | Document as alternative to manual DPoP verification in canon. |
|
|
78
|
+
| GAP-056 | `deleteStatus` semantics for ACTIVE change-set records | STILL_UNRESOLVED | CHANGE_REQUEST_API.md: ACTIVE records have a `deleteStatus` field tracking pending deletion. Does deletion require the same quorum? | Needs vendor clarification. |
|
|
79
|
+
| GAP-057 | Licensing change requests use different path prefix | STILL_UNRESOLVED | CHANGE_REQUEST_API.md: `GET /tideAdminResources/change-set/licensing/requests` vs `GET /tide-admin/change-set/users/requests`. Path inconsistency suggests separate implementations. | Needs clarification on whether licensing requests follow the same sign/commit flow. |
|
|
80
|
+
| GAP-058 | Server-side delegation flow undocumented in pack | RESOLVED_BY_VENDOR | `@tidecloak/server` TideDelegation class, `createTideFetch`, 419 interrupt pattern, `requireDelegation()`/`handleDelegation()` middleware. Token exchange via `/protocol/openid-connect/token` with grant_type=token-exchange. Two-hop chain of trust validated by TideChainOfTrustAuthenticator (Java) and DelegationTokenSignRequest (C#). | Resolved. Canon `delegation.md` and playbook `setup-server-delegation.md` created. |
|
|
81
|
+
| GAP-059 | TideCloak extension endpoints not comprehensively documented | RESOLVED_BY_VENDOR | 94 endpoints across 8 resource classes (VendorResource, VoucherResource, PublicResource, TideIdpResource, TideIdpAdminRealmResource, IGARealmResource, TideAdminRealmResource, PolicyResourceProvider). | Resolved. Canon `tidecloak-endpoints.md` created with full endpoint reference. |
|
|
82
|
+
| GAP-060 | `@tidecloak/server` package not documented in pack | RESOLVED_BY_VENDOR | Server-side SDK for delegation exchange. Exports TideDelegation class with packRequest, exchange, generateDpopProof, requireDelegation, handleDelegation. | Resolved. Canon and playbook updated. |
|
|
83
|
+
| GAP-061 | Scoped delegation (requested_roles) undocumented | RESOLVED_BY_VENDOR | `requireDelegation({ roles: { realm: [...], clients: { ... } } })` filters delegation token roles. Specified via actor_token payload. Exchange provider intersects with user's actual roles. Unlisted = excluded when roles specified. | Resolved. Canon `delegation.md` documents scoped delegation. |
|
|
84
|
+
| GAP-062 | Custom Forseti contract creation guide missing from pack | RESOLVED_BY_VENDOR | Ork.Forseti.Sdk README, IAccessPolicy interface, DecisionBuilder, DokenDto, PolicyParam, ForsetiSdk runtime, sandbox restrictions, deployment, policy signing. | Resolved. Canon `custom-contracts.md` created. |
|
|
85
|
+
| GAP-063 | No Go/REST SDK for ORK threshold signing operations | STILL_UNRESOLVED | LEARNINGS-cosign-batch-001 L-01: ORK signing (`createTideRequest` → `executeSignRequest`) only available via JS SDK. No Go, Python, or REST API for direct ORK interaction. Resolved for web apps (JS SDK); blocks CLI tools and non-JS server-side signing. | Needs vendor clarification on ORK REST API or multi-language SDK plans. |
|
|
86
|
+
| GAP-064 | No CLI/terminal authentication flow (PRISM requires browser SWE iframe) | STILL_UNRESOLVED | LEARNINGS-cosign-batch-001 L-02: all TideCloak auth flows require browser context for PRISM zero-knowledge proof via SWE iframe. No device auth grant, service account, or headless flow exists. Browser-bridge (localhost page) is a workaround, not a native flow. | Needs vendor clarification on device auth grant or service account model. |
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Status Summary
|
|
91
|
+
|
|
92
|
+
| Status | Count |
|
|
93
|
+
|--------|-------|
|
|
94
|
+
| RESOLVED_BY_KEYLESSH | 1 |
|
|
95
|
+
| RESOLVED_BY_VENDOR | 33 |
|
|
96
|
+
| RESOLVED_BY_NORMATIVE_DOC | 3 |
|
|
97
|
+
| RESOLVED_BY_MULTI_EXEMPLAR | 2 |
|
|
98
|
+
| PARTIALLY_RESOLVED_BY_KEYLESSH | 4 |
|
|
99
|
+
| PARTIALLY_RESOLVED_BY_MULTI_EXEMPLAR | 4 |
|
|
100
|
+
| RESOLVED_FOR_EVALS | 1 |
|
|
101
|
+
| RESOLVED_BY_WHITEPAPER | 1 |
|
|
102
|
+
| STILL_UNRESOLVED | 14 |
|
|
103
|
+
| DOCS_ONLY_CONTRADICTION | 0 |
|
|
104
|
+
| RESOLVED_FOR_TEMPLATES | 1 |
|
|
105
|
+
| REQUIRES_RUNTIME_VALIDATION | 0 |
|
|
106
|
+
| **Total** | **64** |
|
|
107
|
+
|
|
108
|
+
Full sync pass (2026-04-13): GAP-001 upgraded from PARTIALLY_RESOLVED_BY_KEYLESSH to RESOLVED_BY_VENDOR (all auth endpoints now documented in `canon/tidecloak-endpoints.md`). GAP-029 upgraded from PARTIALLY_RESOLVED_BY_MULTI_EXEMPLAR to RESOLVED_BY_VENDOR (`get-required-action-link` schema now documented). RESOLVED_BY_VENDOR count corrected to 32. No new gaps.
|
|
109
|
+
|
|
110
|
+
Integration-focus sync (2026-04-13): 4 new gaps added (GAP-058 through GAP-061) for server-side delegation, endpoint documentation, @tidecloak/server SDK, and scoped delegation. Canon updated with `delegation.md` and `tidecloak-endpoints.md`. Playbook `setup-server-delegation.md` added. See `notes/test-findings/tidecloak-integration-focus.md`.
|
|
111
|
+
|
|
112
|
+
Batch-01 adjudication (2026-03-25): 14 gaps resolved by vendor answers.
|
|
113
|
+
Batch-02 adjudication (2026-03-25): 5 gaps resolved by vendor answers. GAP-029 strengthened. 5 assumptions resolved (A-21, A-22, A-25, A-26, A-28).
|
|
114
|
+
Post-adjudication sync (2026-03-25): GAP-007 reclassified (gas metering covered by GAP-008 resolution). GAP-033 corrected (jwk conditional on IGA). GAP-018 strengthened (ORK error codes now documented). GAP-038 reclassified (content-type asymmetry is documented behavior). Stale "Incorporate into canon" next actions updated to "Canon updated". Total resolved: 32 of 57.
|
|
115
|
+
Whitepaper review (2026-03-30): GAP-015 reclassified from STILL_UNRESOLVED to RESOLVED_BY_WHITEPAPER. Correct curve name is BEd255475; Architecture.md had a typo. Total resolved: 35 of 57.
|
|
116
|
+
Template-blocker resolution (2026-03-25): GAP-034 reclassified from DOCS_ONLY_CONTRADICTION to RESOLVED_FOR_TEMPLATES. Template guidance for threshold, image, proxy, HTTPS settled in `notes/template-blocker-resolution.md`.
|
|
117
|
+
Eval-blocker resolution (2026-03-25): GAP-018 reclassified from PARTIALLY_RESOLVED_BY_MULTI_EXEMPLAR to RESOLVED_FOR_EVALS. Client-visible error catalog sufficient for eval pass/fail. A-27 resolved for eval purposes (assume independent, soft assertions). See `notes/eval-blocker-resolution.md`.
|
package/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Tide Agent Pack
|
|
2
|
+
|
|
3
|
+
This repo turns Tide source material into operational assets for AI coding agents.
|
|
4
|
+
|
|
5
|
+
## Goal
|
|
6
|
+
|
|
7
|
+
Help coding agents implement Tide correctly for low-experience builders.
|
|
8
|
+
|
|
9
|
+
## Primary outputs
|
|
10
|
+
|
|
11
|
+
- canon doctrine
|
|
12
|
+
- implementation playbooks
|
|
13
|
+
- agent adapters
|
|
14
|
+
- skills
|
|
15
|
+
- starter prompts
|
|
16
|
+
- starter templates
|
|
17
|
+
- eval cases
|
|
18
|
+
|
|
19
|
+
## Source policy
|
|
20
|
+
|
|
21
|
+
Put copied authoritative material in `sources/`.
|
|
22
|
+
Do not rely on drifting live docs during drafting.
|
|
23
|
+
Mark content as:
|
|
24
|
+
- `VERIFIED`
|
|
25
|
+
- `INFERRED`
|
|
26
|
+
- `ASSUMED`
|
|
27
|
+
|
|
28
|
+
## Drafting order
|
|
29
|
+
|
|
30
|
+
1. `notes/source-audit.md`
|
|
31
|
+
2. `canon/*`
|
|
32
|
+
3. `playbooks/*`
|
|
33
|
+
4. `adapters/*`
|
|
34
|
+
5. `skills/*`
|
|
35
|
+
6. `prompts/*`
|
|
36
|
+
7. `templates/*`
|
|
37
|
+
8. `evals/cases.yaml`
|
|
38
|
+
9. `GAP_REGISTER.md`
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# Tide Agent Adapter — Canonical
|
|
2
|
+
|
|
3
|
+
Operational instructions for AI coding agents implementing Tide in application projects.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Mission
|
|
8
|
+
|
|
9
|
+
Help builders add Tide authentication, authorization, and encryption to their applications correctly. Do not reduce Tide to generic auth. Do not invent security shortcuts.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Source Authority Order
|
|
14
|
+
|
|
15
|
+
1. `canon/invariants.md` — security rules that must never be violated
|
|
16
|
+
2. `canon/anti-patterns.md` — mistakes that defeat Tide's security properties
|
|
17
|
+
3. `canon/feature-mapping.md` — what each SDK feature actually does (and does not do)
|
|
18
|
+
4. `canon/framework-matrix.md` — framework-specific implementation patterns
|
|
19
|
+
5. `playbooks/` — step-by-step task execution
|
|
20
|
+
6. `GAP_REGISTER.md` — what is still uncertain
|
|
21
|
+
|
|
22
|
+
If canon and a playbook disagree, prefer the playbook wording only if it does not conflict with canon invariants. If uncertain, say so.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Tide-Specific Invariants
|
|
27
|
+
|
|
28
|
+
These are not recommendations. Violating any of these defeats Tide's security model.
|
|
29
|
+
|
|
30
|
+
1. **Never-whole-key**: Cryptographic keys never exist in complete form. Do not generate, assemble, store, or export complete keys. (I-01)
|
|
31
|
+
2. **Threshold enforcement**: All crypto operations require T-of-N ORK participation. Do not hardcode 14/20. (I-02)
|
|
32
|
+
3. **Server-side JWT verification required**: Protected APIs must verify JWT signature and claims server-side. Client-side checks are UI gating only. (I-03, I-08)
|
|
33
|
+
4. **Embedded JWKS only**: Use adapter JSON `jwk` field for JWT verification. Do not use `createRemoteJWKSet`. Do not add remote JWKS as a fallback. If `jwk` is missing, fix the adapter export — do not fetch keys remotely. (I-04)
|
|
34
|
+
5. **Adapter JSON with Tide extensions**: Adapter must include `jwk`, `vendorId`, `homeOrkUrl`. Generic Keycloak adapter is insufficient. (I-05, I-13)
|
|
35
|
+
6. **CSP for SWE iframe**: `frame-src '*'` required. Without it, login and E2EE silently fail. (I-06)
|
|
36
|
+
7. **DPoP is a bidirectional lockstep**: Server-side (`dpop.bound.access.tokens: true` in realm template) and client-side (`useDPoP` inside config object, not as JSX prop) must be enabled simultaneously. Use `IAMService.secureFetch` with `await IAMService.getToken()` for API calls (async — must be awaited). The SDK detects the Bearer header and upgrades it to DPoP scheme with proof attached. Absolute URLs required. See `canon/anti-patterns.md` for the `appFetch` wrapper pattern. (I-12)
|
|
37
|
+
8. **No single point of bypass**: No admin, server, or ORK can unilaterally bypass threshold enforcement. (I-09)
|
|
38
|
+
9. **E2EE requires online Fabric**: No offline decryption. No server-side decryption. (I-11)
|
|
39
|
+
10. **`_tide_enabled` role required**: All Tide users need a `_tide_*` role for the voucher system. Declare `_tide_enabled` in realm.json. (I-14)
|
|
40
|
+
11. **Post-auth redirect handler required**: A real page must exist at the configured `redirectUri` path. Without it, login completes at TideCloak but the user lands on a 404. See `canon/redirect-handler.md`. (I-16)
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Forbidden Shortcuts
|
|
45
|
+
|
|
46
|
+
Do not do these. Each defeats a specific invariant or creates a real vulnerability. See `canon/anti-patterns.md` for full explanations.
|
|
47
|
+
|
|
48
|
+
- **Do not** rely on `hasRealmRole()` / `hasClientRole()` or route guards for API authorization. They are UI gating only. The SDK hook exports `hasRealmRole(role)` and `hasClientRole(role, client?)` — there is no generic `hasRole()` on the hook. (AP-02)
|
|
49
|
+
- **Do not** use `createRemoteJWKSet` or fetch JWKS from the remote Keycloak certs endpoint. Use `createLocalJWKSet(config.jwk)` only. If `jwk` is missing, route to setup/bootstrap — do not add remote fallback. (AP-01, I-04)
|
|
50
|
+
- **Do not** generate cryptographic keys locally for Tide operations. (AP-03)
|
|
51
|
+
- **Do not** implement custom password verification. Tide uses threshold PRISM. (AP-01)
|
|
52
|
+
- **Do not** implement offline E2EE fallback or cache session keys. (AP-04)
|
|
53
|
+
- **Do not** create single-admin bypass paths around IGA. (AP-05)
|
|
54
|
+
- **Do not** skip DPoP verification on protected APIs. (AP-06)
|
|
55
|
+
- **Do not** store plain-text role cookies, ad hoc local auth logic, or fake auth helpers.
|
|
56
|
+
- **Do not** use `IAMService` for DPoP flows — use the `TideCloak` class with `enableDpop: true`.
|
|
57
|
+
- **Do not** use named ESM imports from `@tidecloak/verify` — it is CJS. Use default import with defensive interop.
|
|
58
|
+
- **Do not** import `Models`, `PolicySignRequest`, `BaseTideRequest`, `ApprovalType`, or `ExecutionType` from `@tidecloak/nextjs`. That package is the Next.js integration layer only. Import `Models` from `@tideorg/js` and `PolicySignRequest` from `heimdall-tide`. Importing from `@tidecloak/nextjs` returns `undefined` at runtime.
|
|
59
|
+
- **Do not** call `createTideRequest()`, `requestTideOperatorApproval()`, or `executeSignRequest()` on `IAMService`. These methods live on the underlying TideCloak instance at `IAMService._tc`. Calling them on `IAMService` throws `is not a function`.
|
|
60
|
+
- **Do not** hide UI elements and call it "authorization". Hiding a button is not protecting an API.
|
|
61
|
+
- **Do not** rename `selfencrypt`/`selfdecrypt` to `encrypt`/`decrypt` to enable shared decryption. Role suffix does not change the encryption model. Self-encryption uses `doEncrypt`/`doDecrypt` (identity-bound). Shared encryption requires `IAMService.doEncrypt(data, policyBytes)` with a Forseti contract. (AP-26)
|
|
62
|
+
- **Do not** use master admin credentials (`admin`/`password`, `grant_type=password`, `admin-cli`) in generated app code. These are bootstrap-only — they belong in `scripts/init*.sh`. Generated app API routes must forward the logged-in user's token to TideCloak admin APIs. (AP-41)
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Development Team Model
|
|
67
|
+
|
|
68
|
+
This agent operates as a virtual development team. The **Tech Lead** decides routing. Specialist roles do scoped work. The **Reviewer** checks before handoff. The **Pack Curator** turns lessons into pack updates.
|
|
69
|
+
|
|
70
|
+
### Team Roster
|
|
71
|
+
|
|
72
|
+
| Role | Skill directory | Owns |
|
|
73
|
+
|------|----------------|------|
|
|
74
|
+
| **Tech Lead** | (this adapter) | Request inspection, repo inspection, sequencing, stopping if ambiguity is unresolved |
|
|
75
|
+
| **Scenario Resolver** | `tide-scenario-resolver` | Determining what kind of problem this is before build work begins |
|
|
76
|
+
| **Setup / Platform Engineer** | `tide-setup` | TideCloak bootstrap, realm, licensing, IGA, admin user, adapter export, init script path |
|
|
77
|
+
| **Application Engineer** | `tide-integration` | SDK install, provider wiring, config loading, redirect handler, CSP, DPoP auth page, webpack, retrofit |
|
|
78
|
+
| **Security Engineer** | `tide-route-and-api-protection` | Route guards, API protection, JWT/DPoP verification, same-origin proxy patterns |
|
|
79
|
+
| **IAM / Policy Engineer** | `tide-rbac-and-e2ee` | Roles, hasRealmRole vs hasClientRole, self vs shared encryption, policy signing, Forseti, IGA governance |
|
|
80
|
+
| **Solutions Architect** | `tide-solutions-architect` | Pattern exploration when no existing scenario/playbook covers the request |
|
|
81
|
+
| **Reviewer / QA Engineer** | `tide-reviewer` | Compliance checking, invariant validation, anti-pattern detection, scenario correctness |
|
|
82
|
+
| **Learnings / Pack Curator** | `tide-diagnostics` | Troubleshooting, finding extraction, learnings, regression proposals |
|
|
83
|
+
|
|
84
|
+
### How the Tech Lead works
|
|
85
|
+
|
|
86
|
+
**Step 1: Inspect** — Check repo state and user request.
|
|
87
|
+
|
|
88
|
+
**Step 2: Resolve scenario** — Hand to the **Scenario Resolver**. If unresolved, stop and ask. Do not guess.
|
|
89
|
+
|
|
90
|
+
**Step 3: Emit trace** — Before routing to the first specialist, emit a `[TRACE]` block showing the resolved scenario, first role, and why.
|
|
91
|
+
|
|
92
|
+
**Step 4: Sequence specialists** — Route to specialists in order. Each specialist emits its own `[TRACE]` on entry.
|
|
93
|
+
|
|
94
|
+
### Handoff tracing (required)
|
|
95
|
+
|
|
96
|
+
Every role must emit a `[TRACE]` block on entry. The Reviewer must emit a `[REVIEW]` block with its verdict. Missing traces on multi-role tasks are a process failure. See `notes/handoff-trace-format.md` for the format.
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
[TRACE]
|
|
100
|
+
Scenario: <scenario>
|
|
101
|
+
Role: <role>
|
|
102
|
+
Reason: <why>
|
|
103
|
+
Preconditions: <checked>
|
|
104
|
+
Next: <next role or STOP>
|
|
105
|
+
[/TRACE]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Handoff rules
|
|
109
|
+
|
|
110
|
+
| # | Rule |
|
|
111
|
+
|---|------|
|
|
112
|
+
| 1 | **Scenario Resolver** runs before any specialist. No implementation without a resolved scenario. |
|
|
113
|
+
| 2 | **Setup / Platform Engineer** runs before **Application Engineer** (TideCloak must be running). |
|
|
114
|
+
| 3 | **Application Engineer** runs before **Security Engineer** (SDK/provider must be wired). |
|
|
115
|
+
| 4 | **Security Engineer** runs before **IAM / Policy Engineer** (JWT verification must exist). |
|
|
116
|
+
| 5 | **Reviewer / QA Engineer** is **mandatory** before handing the app to the user. No implementation is delivered without a review pass. Concludes with ACCEPT, ACCEPT_WITH_WARNINGS, or REJECT_AND_REROUTE. If rejected, the named specialist fixes the issue, then Reviewer runs again. |
|
|
117
|
+
| 6 | **Solutions Architect** runs only when no existing path covers the request. Proposes within pack constraints. Does not override doctrine. |
|
|
118
|
+
| 7 | **Learnings / Pack Curator** runs after meaningful builds to extract reusable findings and propose regressions. |
|
|
119
|
+
|
|
120
|
+
### Generated app shortcut
|
|
121
|
+
|
|
122
|
+
If the project has an init script (`npm run init` in package.json):
|
|
123
|
+
1. Run `npm run init` — completes the **Setup / Platform Engineer's** work automatically
|
|
124
|
+
2. Proceed directly to **Application Engineer**
|
|
125
|
+
|
|
126
|
+
### Scenario-pattern matching
|
|
127
|
+
|
|
128
|
+
Before choosing a specialist, the **Scenario Resolver** checks `reference-apps/INDEX.md`. If a scenario matches, its manifest provides the specialist sequence and playbook ordering. Scenario match takes precedence over generic routing.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Scenario-Pattern Matching
|
|
133
|
+
|
|
134
|
+
When a user describes an app to build, check `reference-apps/INDEX.md` before starting. If the description matches a known scenario:
|
|
135
|
+
|
|
136
|
+
1. Read the scenario's `manifest.yaml` for roles, policies, and playbook sequence.
|
|
137
|
+
2. Use the manifest to drive realm template generation and bootstrap ordering.
|
|
138
|
+
3. Follow the scenario's `bootstrap-sequence.md` for pre-user admin setup.
|
|
139
|
+
4. Check the scenario's `anti-patterns.md` for scenario-specific mistakes.
|
|
140
|
+
|
|
141
|
+
If no scenario matches, fall back to the standard `tide-setup` skill detection.
|
|
142
|
+
|
|
143
|
+
**Current scenarios**: `organisation-password-manager` (shared credential vault with Forseti-governed VVK encryption).
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Encryption Model Decision
|
|
148
|
+
|
|
149
|
+
When a user asks to encrypt data, determine the model BEFORE suggesting roles:
|
|
150
|
+
|
|
151
|
+
1. **Only the encrypting user decrypts?** → Self-encryption. Use `doEncrypt`/`doDecrypt` from `useTideCloak()`. Roles: `_tide_{tag}.selfencrypt`/`.selfdecrypt`.
|
|
152
|
+
2. **Multiple users decrypt the same ciphertext?** → Policy-governed VVK. Use `IAMService.doEncrypt(data, signedPolicyBytes)`. Requires Forseti contract + policy signing + voucher gates + contract role. Route to `setup-forseti-e2ee`.
|
|
153
|
+
|
|
154
|
+
**If self-encryption fails**, fix the self-encryption setup (roles, IGA approval, re-login). Do NOT rename roles to `encrypt`/`decrypt`. Do NOT jump to shared encryption as a "fix". See T-13, AP-26.
|
|
155
|
+
|
|
156
|
+
**If policy commit fails** with "Policy supplied has not been signed", this is a policy-flow failure (missing admin policy attachment). Do NOT treat as a role issue. See T-14.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## How to Handle Uncertainty
|
|
161
|
+
|
|
162
|
+
1. **Use settled doctrine** where available. Canon invariants and verified playbook steps are authoritative.
|
|
163
|
+
2. **Use playbook caveats** where the playbook notes something as partially resolved or deployment-specific.
|
|
164
|
+
3. **Do not overclaim**. If a gap is marked STILL_UNRESOLVED or PARTIALLY_RESOLVED in GAP_REGISTER.md, do not present it as settled. Say "this behavior is not yet fully documented" and link to the relevant gap.
|
|
165
|
+
4. **Do not silently resolve open gaps**. If you are unsure whether something is correct, say so. Prefer an explicit caveat over a confident wrong answer.
|
|
166
|
+
5. **Deferred gaps** (migration procedures, multi-tenant config, disaster recovery, Ragnarok details) are intentionally excluded from adapters. Do not encode them as if they are resolved.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Distinguishing Client-Side, Route, and Server-Side Protection
|
|
171
|
+
|
|
172
|
+
This is the single most common source of insecure Tide implementations. Full details in `canon/feature-mapping.md` (Protected Routes vs Protected APIs).
|
|
173
|
+
|
|
174
|
+
| Layer | Examples | Security value |
|
|
175
|
+
|-------|----------|----------------|
|
|
176
|
+
| Client-side UI checks | `hasRealmRole()` / `hasClientRole()`, conditional rendering | **None.** UX only. |
|
|
177
|
+
| Route protection | Next.js `proxy.ts` (16+) or `middleware.ts` (≤15), React Router guards | **None for APIs.** Redirect only. |
|
|
178
|
+
| Server-side API auth | `verifyTideJWT()` + role check + DPoP | **Real.** This is authorization. |
|
|
179
|
+
|
|
180
|
+
**Rule**: Every protected API route must include server-side JWT verification. Client-side checks and route guards are optional UX, never substitutes.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## When the App Is Not Tide-Enabled
|
|
185
|
+
|
|
186
|
+
Before diagnosing Tide-specific issues, verify Tide is actually installed:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# 1. SDK package installed?
|
|
190
|
+
grep '@tidecloak' package.json
|
|
191
|
+
|
|
192
|
+
# 2. Provider in layout?
|
|
193
|
+
grep 'TideCloakProvider\|TideCloakContextProvider' app/layout.tsx app/providers.tsx 2>/dev/null
|
|
194
|
+
|
|
195
|
+
# 3. Adapter JSON present? (filename must be tidecloak.json, not adapter.json)
|
|
196
|
+
# Next.js: check data/
|
|
197
|
+
test -f data/tidecloak.json || echo "Missing data/tidecloak.json"
|
|
198
|
+
# React/Vite/Vanilla: check public/
|
|
199
|
+
test -f public/tidecloak.json || echo "Missing public/tidecloak.json"
|
|
200
|
+
# Wrong filename?
|
|
201
|
+
ls data/adapter.json public/adapter.json data/keycloak.json public/keycloak.json 2>/dev/null && echo "WRONG FILENAME"
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**If checks 1 or 2 fail**: Stop diagnosis. The app does not have a Tide integration. Route the builder to `add-auth-nextjs-fresh` (or `add-auth-nextjs-existing`) first. Do not attempt to diagnose Tide login issues on an app without Tide installed.
|
|
205
|
+
|
|
206
|
+
**If check 3 fails**: The app has SDK code but no configuration. Route to adapter JSON export from TideCloak admin console.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Config Artifact Rule
|
|
211
|
+
|
|
212
|
+
`tidecloak.json` is the canonical client-side config artifact. It contains auth-server-url, realm, resource (clientId), jwk, vendorId, homeOrkUrl, and client-origin-auth fields.
|
|
213
|
+
|
|
214
|
+
- **Client-side**: The `TideCloakProvider` imports `data/tidecloak.json` directly via the `config` prop. No `NEXT_PUBLIC_TIDECLOAK_*` env vars needed.
|
|
215
|
+
- **Server-side**: `loadTideConfig()` reads `data/tidecloak.json` (or `CLIENT_ADAPTER` env var for deployment).
|
|
216
|
+
- **Do not** create `NEXT_PUBLIC_TIDECLOAK_URL`, `NEXT_PUBLIC_TIDECLOAK_REALM`, `NEXT_PUBLIC_TIDECLOAK_CLIENT_ID`, or `NEXT_PUBLIC_TIDECLOAK_REDIRECT_URI` env vars. These duplicate values already in `tidecloak.json`.
|
|
217
|
+
- **Exception**: `CLIENT_ADAPTER` env var is acceptable for deployment environments where a file import is not practical (e.g., containerized deployments, Vercel). It contains the full adapter JSON as a string.
|
|
218
|
+
|
|
219
|
+
If an app uses `NEXT_PUBLIC_TIDECLOAK_*` env vars for provider config, fix it to import `tidecloak.json` instead.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Key Technical Facts for Agents
|
|
224
|
+
|
|
225
|
+
These are implementation pitfalls not covered by invariants or anti-patterns. For code patterns, see `canon/framework-matrix.md`.
|
|
226
|
+
|
|
227
|
+
- **Adapter JSON provider ID**: `keycloak-oidc-keycloak-json` only. `tidecloak-oidc-keycloak-json` does not exist.
|
|
228
|
+
- **`jwk` in adapter**: Only present when IGA is enabled. Validate at startup.
|
|
229
|
+
- **`client-origin-auth-*`**: Required for enclave init. Config loader must select entry matching `window.location.origin`.
|
|
230
|
+
- **`@tidecloak/verify`**: CJS package. Named ESM imports fail. See `canon/framework-matrix.md` for interop pattern.
|
|
231
|
+
- **`@tideorg/js`**: Correct source for `Models` / `Contracts` imports. `@tidecloak/nextjs` does NOT export these — importing them from `@tidecloak/nextjs` returns `undefined` at runtime. `PolicySignRequest` comes from `heimdall-tide`.
|
|
232
|
+
- **Webpack workarounds**: Two fixes required in `next.config.ts`: (1) `config.module.strictExportPresence = false` for `@tidecloak/js` re-exports (NOT `reexportExportsPresence` which is invalid), (2) `@tidecloak/react` ESM alias via `path.resolve()` to `dist/esm/index.js` (AP-42). Next.js 16+: use `next dev --webpack` in package.json scripts.
|
|
233
|
+
- **DPoP auth page**: `public/tide_dpop_auth.html` + `next.config.ts` `rewrites()` (`/tide_dpop/:path*` → `/tide_dpop_auth.html`). Do NOT use a route handler (`app/tide_dpop/[...path]/route.ts`) — Next.js 16 dev overrides CSP on route handler responses, blocking the inline script. Set CSP via `headers()` config. Do not modify the HTML — integrity-checked. HTML must match SDK version. See I-12.
|
|
234
|
+
- **Staging image differences**: `tide-roles-mapper` provider only exists on `tidecloak-dev` (production), not `tidecloak-stg-dev`. Realm import silently drops it on staging. Include standard role mappers as fallback.
|
|
235
|
+
- **Canonical setup ordering**: License (`setUpTideRealm`) → IGA (`toggle-iga`) → E2EE. Only valid sequence. See `canon/tidecloak-bootstrap.md`.
|
|
236
|
+
- **Docker images**: `tidecloak-dev` for development (no ORK env vars needed — built-in defaults). `tidecloak-stg-dev` for staging (requires ORK, threshold, payer env vars).
|
|
237
|
+
- **Bootstrap vs app integration**: TideCloak bootstrap (start, realm, admin, adapter export) is separate from app integration (SDK, provider, JWT). Bootstrap must complete first.
|
|
238
|
+
- **Token refresh delay**: After IGA commit, roles appear in JWT/doken after next token refresh (up to 120s).
|
|
239
|
+
- **`tide-realm-admin`**: Client role on `realm-management`, not a realm role.
|
|
240
|
+
- **Post-auth redirect handler**: Must exist at configured `redirectUri` path. Missing handler = login appears to fail (404 after auth). See `canon/redirect-handler.md`.
|
|
241
|
+
- **Version policy**: All `@tidecloak/*` packages pin to `0.13.26`. No 0.99.x. See `canon/version-policy.md`.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Tide Agent Adapter — Claude Code
|
|
2
|
+
|
|
3
|
+
Compact instructions for Claude Code when working on Tide-enabled applications.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Disambiguate First (I-17)
|
|
8
|
+
|
|
9
|
+
Before writing code, check whether the request maps to more than one valid path. If multiple scenarios are plausible, resolve the branch before proceeding. Do not silently default to one path.
|
|
10
|
+
|
|
11
|
+
Key branches: fresh vs existing app, self-encryption vs shared encryption, bootstrap vs app integration, diagnosis vs setup, simple RBAC vs policy governance. If unclear, ask. See `canon/invariants.md` I-17.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Inspect First
|
|
16
|
+
|
|
17
|
+
Before writing or modifying code, check:
|
|
18
|
+
|
|
19
|
+
1. `package.json` — is `@tidecloak/nextjs` (or `@tidecloak/react`, `@tidecloak/js`) installed?
|
|
20
|
+
2. `app/layout.tsx` (or equivalent) — is `TideCloakProvider` (Next.js) or `TideCloakContextProvider` (React/Vite) present?
|
|
21
|
+
3. `tidecloak.json` — does it exist with `jwk`, `vendorId`, `homeOrkUrl` fields?
|
|
22
|
+
- Next.js: `data/tidecloak.json` (or `CLIENT_ADAPTER` / `TIDECLOAK_CONFIG_B64` env var)
|
|
23
|
+
- React/Vite / Vanilla JS: `public/tidecloak.json`
|
|
24
|
+
- Wrong filename (`adapter.json`, `keycloak.json`)? Rename to `tidecloak.json`.
|
|
25
|
+
|
|
26
|
+
If 1 or 2 is missing: the app is not Tide-enabled. Stop diagnosis. Use playbook `add-auth-nextjs-fresh` or `add-auth-nextjs-existing`.
|
|
27
|
+
|
|
28
|
+
If 3 is missing: adapter JSON not exported. Direct user to TideCloak admin console. If present but wrong filename, rename to `tidecloak.json`.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Source Authority
|
|
33
|
+
|
|
34
|
+
1. `canon/invariants.md` — absolute rules
|
|
35
|
+
2. `canon/anti-patterns.md` — what not to do
|
|
36
|
+
3. `playbooks/` — step-by-step procedures
|
|
37
|
+
4. `GAP_REGISTER.md` — remaining uncertainty
|
|
38
|
+
|
|
39
|
+
Do not guess when uncertain. Say so and cite the gap.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Do Not
|
|
44
|
+
|
|
45
|
+
- Treat `hasRealmRole()` / `hasClientRole()` or route guards as authorization. They are UI gating only. The SDK hook does not export a generic `hasRole()` — use `hasRealmRole(role)` for realm roles and `hasClientRole(role, client?)` for client roles.
|
|
46
|
+
- Use `createRemoteJWKSet` or fetch JWKS remotely. Use embedded `config.jwk` only. If `jwk` is missing, fix the adapter export — do not fall back to remote.
|
|
47
|
+
- Generate local cryptographic keys for Tide operations.
|
|
48
|
+
- Import `Models`, `PolicySignRequest`, or other policy/model helpers from `@tidecloak/nextjs`. That package is Next.js hooks/provider only. Use `@tideorg/js` for `Models` and `heimdall-tide` for `PolicySignRequest`. Importing from `@tidecloak/nextjs` returns `undefined` at runtime.
|
|
49
|
+
- Call `createTideRequest()`, `requestTideOperatorApproval()`, or `executeSignRequest()` on `IAMService`. These live on `IAMService._tc` (TideCloak instance). Direct calls on `IAMService` throw `is not a function`.
|
|
50
|
+
- Use named ESM imports from `@tidecloak/verify` — it is CJS. Use default import with defensive interop.
|
|
51
|
+
- Pass `useDPoP` as a JSX prop on `TideCloakProvider` — it goes inside the config object: `config={{ ...tcConfig, useDPoP: { mode: 'strict', alg: 'ES256' } }}`. (session-002)
|
|
52
|
+
- Call `IAMService.secureFetch` with a relative URL — it throws. Use absolute URLs with `window.location.origin`. (session-002)
|
|
53
|
+
- Call `IAMService.secureFetch` without pre-setting `Authorization: Bearer <token>` — SDK only attaches DPoP proof when it detects an existing Bearer header to upgrade. Use `await IAMService.getToken()` for the managed token (async — must be awaited). (session-002, LEARNINGS-batch-005 L-07)
|
|
54
|
+
- Use regular `fetch` with `Bearer` header when `useDPoP` is enabled — DPoP-bound tokens require `IAMService.secureFetch` which upgrades Bearer to DPoP scheme and attaches the proof.
|
|
55
|
+
- Implement custom password logic. Tide uses threshold PRISM.
|
|
56
|
+
- Write plain-text role cookies, ad hoc auth helpers, or fake local auth.
|
|
57
|
+
- Skip DPoP verification on protected APIs.
|
|
58
|
+
- Present hidden UI as real authorization.
|
|
59
|
+
- Rename `selfencrypt`/`selfdecrypt` to `encrypt`/`decrypt` to enable shared decryption. Role suffix does not change the encryption model. Self-encryption is identity-bound. Shared encryption requires `IAMService.doEncrypt(data, policyBytes)` with a Forseti contract. (AP-26)
|
|
60
|
+
- Use master admin credentials (`admin`/`password`, `grant_type=password`, `admin-cli`) in generated app code. These are bootstrap-only — they belong in `scripts/init*.sh`, never in API routes or app code. Forward the logged-in user's token instead. (AP-41)
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Development Team Model
|
|
65
|
+
|
|
66
|
+
Route first, then act. Do NOT bundle all work into one pass.
|
|
67
|
+
|
|
68
|
+
**Step 1**: Inspect repo and request.
|
|
69
|
+
**Step 2**: **Scenario Resolver** (`tide-scenario-resolver`) determines what kind of problem this is. If ambiguous, stop and ask.
|
|
70
|
+
**Step 3**: Route to specialists in order:
|
|
71
|
+
|
|
72
|
+
| Role | Skill | When |
|
|
73
|
+
|------|-------|------|
|
|
74
|
+
| **Setup / Platform Engineer** | `tide-setup` | TideCloak not running or not configured |
|
|
75
|
+
| **Application Engineer** | `tide-integration` | SDK/provider not wired |
|
|
76
|
+
| **Security Engineer** | `tide-route-and-api-protection` | Routes/APIs need protection |
|
|
77
|
+
| **IAM / Policy Engineer** | `tide-rbac-and-e2ee` | Roles, encryption, or policy governance needed |
|
|
78
|
+
| **Learnings / Pack Curator** | `tide-diagnostics` | Something is broken, or learnings need extraction |
|
|
79
|
+
| **Reviewer / QA Engineer** | `tide-reviewer` | **Mandatory** before handing app to user |
|
|
80
|
+
| **Solutions Architect** | `tide-solutions-architect` | No existing path covers the request |
|
|
81
|
+
|
|
82
|
+
**Ordering**: Scenario Resolver → Setup → Application → Security → IAM/Policy → Reviewer. Pack Curator at any time. Solutions Architect when no existing path fits.
|
|
83
|
+
|
|
84
|
+
**Tracing**: Every role emits a `[TRACE]` block on entry. Reviewer emits a `[REVIEW]` block with verdict. Missing traces on multi-role tasks are a process failure. Format: `notes/handoff-trace-format.md`.
|
|
85
|
+
|
|
86
|
+
**Scenario match**: Check `reference-apps/INDEX.md` first. Scenario Resolver does this before any specialist runs.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Three Layers of Protection
|
|
91
|
+
|
|
92
|
+
| Layer | Mechanism | Security value |
|
|
93
|
+
|-------|-----------|----------------|
|
|
94
|
+
| UI gating | `hasRealmRole()` / `hasClientRole()`, conditional render | None — bypass trivial |
|
|
95
|
+
| Route guard | `proxy.ts` (Next.js 16+) or `middleware.ts` (≤15), React Router | None for APIs — redirect only |
|
|
96
|
+
| API auth | `verifyTideJWT()` + role check + DPoP | Real — threshold-signed JWT |
|
|
97
|
+
|
|
98
|
+
Every protected API must have layer 3. Layers 1 and 2 are optional UX.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Encryption Model Decision — CHECK THIS FIRST
|
|
103
|
+
|
|
104
|
+
**Mandatory sharing gate**: If the user's request mentions sharing, recipients, other users decrypting, cross-user access, or any indication that someone other than the encrypting user should decrypt — use policy-governed VVK encryption (`setup-forseti-e2ee`). Do NOT start with self-encryption. Self-encryption is permanently user-bound and CANNOT be upgraded to shared encryption later. The SDK call path is fundamentally different.
|
|
105
|
+
|
|
106
|
+
- **Only encrypting user decrypts?** Self-encryption. `doEncrypt`/`doDecrypt`. Roles: `_tide_{tag}.selfencrypt`/`.selfdecrypt`.
|
|
107
|
+
- **Multiple users decrypt same ciphertext?** Policy-governed VVK. `IAMService.doEncrypt(data, policyBytes)`. Requires Forseti + policy signing. Route to `setup-forseti-e2ee`.
|
|
108
|
+
- **Self-encryption fails?** Fix roles/IGA/re-login. Do NOT rename roles. See T-13, AP-26.
|
|
109
|
+
- **Policy commit fails?** Fix admin policy attachment. See T-14. Not a role issue.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Config Artifact Rule
|
|
114
|
+
|
|
115
|
+
`tidecloak.json` is the canonical config. Provider imports it directly. Do not create `NEXT_PUBLIC_TIDECLOAK_URL` / `REALM` / `CLIENT_ID` / `REDIRECT_URI` env vars — these values are in `tidecloak.json`. Exception: `CLIENT_ADAPTER` env var for deployment.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Quick Technical Reference
|
|
120
|
+
|
|
121
|
+
For code patterns and full details, see `canon/framework-matrix.md`.
|
|
122
|
+
|
|
123
|
+
- **Adapter provider ID**: `keycloak-oidc-keycloak-json` only. `tidecloak-oidc-keycloak-json` does not exist.
|
|
124
|
+
- **JWT verification**: `createLocalJWKSet(config.jwk)` only. `createRemoteJWKSet` is forbidden. If `jwk` is missing, re-export adapter with IGA enabled.
|
|
125
|
+
- **DPoP**: ES256 default, EdDSA supported. Per-request `jti` replay cache with 2-min TTL.
|
|
126
|
+
- **`jwk` in adapter**: Only present when IGA is enabled. Validate at startup.
|
|
127
|
+
- **Webpack**: Two fixes required: (1) `config.module.strictExportPresence = false` for `@tidecloak/js` re-exports (NOT `reexportExportsPresence` which is invalid), (2) `@tidecloak/react` ESM alias (`path.resolve()` to `dist/esm/index.js`). Next.js 16+: use `next dev --webpack`. (AP-42)
|
|
128
|
+
- **CSP**: `frame-src '*'` required globally. For DPoP, set `script-src 'unsafe-inline'` on `/tide_dpop/:path*` via `next.config.ts` `headers()` — NOT in a route handler (Next.js 16 overrides CSP on route handler responses).
|
|
129
|
+
- **DPoP auth page**: `public/tide_dpop_auth.html` + `next.config.ts` `rewrites()` (`/tide_dpop/:path*` → `/tide_dpop_auth.html`). Do NOT use `app/tide_dpop/[...path]/route.ts`. Do not modify the HTML — integrity-checked. HTML must match SDK version. (I-12)
|
|
130
|
+
- **`silent-check-sso.html`**: Must exist in `public/`. See playbook `add-auth-nextjs-fresh`.
|
|
131
|
+
- **Redirect handler**: Must exist at configured `redirectUri` path. Without it, login ends on 404. See `canon/redirect-handler.md`.
|
|
132
|
+
- **Setup order**: License → IGA → E2EE. No other sequence works. See `canon/tidecloak-bootstrap.md`.
|
|
133
|
+
- **Version policy**: Tide packages at `0.13.26`. No 0.99.x. See `canon/version-policy.md`.
|
|
134
|
+
- **Docker images**: `tidecloak-dev` is production (full protocol). `tidecloak-stg-dev` is staging. Images are under `tideorg/` org (e.g. `tideorg/tidecloak-dev:latest`), NOT `tidecloak/`. Do NOT append `start-dev` to docker run — TideCloak images have a pre-configured entrypoint.
|
|
135
|
+
- **`_tide_enabled`**: Declare in realm.json. Not auto-created.
|
|
136
|
+
- **`tide-realm-admin`**: Client role on `realm-management`, not a realm role.
|
|
137
|
+
- **Token refresh delay**: After IGA commit, up to 120s before roles appear in JWT.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Handling Uncertainty
|
|
142
|
+
|
|
143
|
+
- Settled in canon/playbooks → use it.
|
|
144
|
+
- Playbook notes a caveat → preserve the caveat.
|
|
145
|
+
- GAP_REGISTER marks it STILL_UNRESOLVED → do not encode as resolved. Say "not yet documented".
|
|
146
|
+
- Deferred items (migration, multi-tenant, DR, Ragnarok) → do not include in app-building flows.
|