fix(chat): fail closed when embed gate cannot resolve workspace#5046
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryLow Risk Overview Paid-plan enforcement still runs only after a resolved Reviewed by Cursor Bugbot for commit 0d8ebc8. Configure here. |
|
@greptile |
|
@cursor review |
Greptile SummaryThis PR hardens the
Confidence Score: 5/5Safe to merge; the change is a small, well-scoped guard that only tightens access and cannot introduce a regression in the allow path. The guard is correct — No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[assertChatEmbedAllowed called] --> B{Billing & gate flags enabled?}
B -- No --> Z[return null — allow]
B -- Yes --> C{Origin header present\nand non-first-party?}
C -- No --> Z
C -- Yes --> D[DB: SELECT workspaceId\nWHERE id=workflowId\nAND archivedAt IS NULL]
D --> E{wf?.workspaceId\ntruthy?}
E -- No: NEW fail closed --> F[warn + return 403\n'chat unavailable']
E -- Yes --> G[isWorkspaceApiExecutionEntitled\nworkspaceId]
G --> H{Entitled?}
H -- No --> I[warn + return 403\n'paid plan required']
H -- Yes --> Z
Reviews (1): Last reviewed commit: "fix(chat): fail closed when embed gate c..." | Re-trigger Greptile |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 0d8ebc8. Configure here.
Greptile SummaryThis PR hardens the
Confidence Score: 5/5Safe to merge — the change tightens a security gate and is backed by a new test that exercises the previously unguarded code path. Both changed files are small and self-contained. The guard added to assertChatEmbedAllowed correctly handles all falsy workspaceId states (missing row, null column) and narrows the type so the downstream entitlement call always receives a concrete string. The test wiring follows the established @sim/testing dbChainMock pattern, uses mockResolvedValueOnce for the one-shot override, and the beforeEach re-establishes the permanent default on every test — no ordering hazards observed. No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant Client as External Embed
participant Gate as assertChatEmbedAllowed
participant DB as Database (workflow table)
participant Billing as isWorkspaceApiExecutionEntitled
Client->>Gate: request (cross-origin)
Gate->>Gate: check billing/gate flags enabled
Gate->>Gate: check isFirstPartyOrigin → false
Gate->>DB: "SELECT workspaceId FROM workflow WHERE id=? AND archivedAt IS NULL LIMIT 1"
alt Workflow not found / no workspaceId (new guard)
DB-->>Gate: []
Gate-->>Client: 403 — This chat is currently unavailable
else Workspace found
DB-->>Gate: "[{ workspaceId }]"
Gate->>Billing: isWorkspaceApiExecutionEntitled(workspaceId)
alt Not entitled (free plan)
Billing-->>Gate: false
Gate-->>Client: 403 — Requires paid plan
else Entitled
Billing-->>Gate: true
Gate-->>Client: null (allow)
end
end
Reviews (2): Last reviewed commit: "fix(chat): fail closed when embed gate c..." | Re-trigger Greptile |
Summary
assertChatEmbedAllowed) to fail closed when the workflow row can't be resolved (archived/deleted), instead of inheritingisWorkspaceApiExecutionEntitled'sundefined → entitleddefault and silently skipping the gate.lib/workflows/lifecycle.ts), and the route filters chats onisNull(archivedAt)+isActivebefore the gate runs. This guards against a future refactor breaking that invariant.@sim/dbmock so the workflow lookup is controllable.Type of Change
Testing
vitest run app/api/chat/utils.test.ts— 23 passedvitest run app/api/chat/[identifier]/route.test.ts— 16 passedChecklist