Skip to content

v0.5.93: NextJS config changes, MCP and Blocks whitelisting, copilot keyboard shortcuts, audit logs#3241

Merged
waleedlatif1 merged 10 commits intomainfrom
staging
Feb 18, 2026
Merged

v0.5.93: NextJS config changes, MCP and Blocks whitelisting, copilot keyboard shortcuts, audit logs#3241
waleedlatif1 merged 10 commits intomainfrom
staging

Conversation

@waleedlatif1
Copy link
Collaborator

@waleedlatif1 waleedlatif1 commented Feb 18, 2026

waleedlatif1 and others added 5 commits February 17, 2026 16:27
* feat(mcp): add ALLOWED_MCP_DOMAINS env var for domain allowlist

* ack PR comments

* cleanup
* Allow outbound connections from locked blocks to be modified

- Modified isEdgeProtected to only check target block protection
- Outbound connections (from locked blocks) can now be added/removed
- Inbound connections (to locked blocks) remain protected
- Updated notification messages and comments to reflect the change

Co-authored-by: Emir Karabeg <[email protected]>

* update notif msg

---------

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Emir Karabeg <[email protected]>
Co-authored-by: waleed <[email protected]>
…d block restrictions (#3238)

* feat(access-control): add ALLOWED_INTEGRATIONS env var for self-hosted block restrictions

* fix(tests): add getAllowedIntegrationsFromEnv mock to agent-handler tests

* fix(access-control): add auth to allowlist endpoint, fix loading state race, use accurate error message

* fix(access-control): remove auth from allowed-integrations endpoint to match models endpoint pattern

* fix(access-control): normalize blockType to lowercase before env allowlist check

* fix(access-control): expose merged allowedIntegrations on config to prevent bypass via direct access

* consolidate merging of allowed blocks so all callers have it by default

* normalize to lower case

* added tests

* added tests, normalize to lower case

* added safety incase userId is missing

* fix failing tests
* fix: prevent copilot keyboard shortcuts from triggering when panel is inactive

The OptionsSelector component was capturing keyboard events (1-9 number keys and Enter)
globally on the document, causing accidental option selections when users were
interacting with other parts of the application.

This fix adds a check to only handle keyboard shortcuts when the copilot panel
is the active tab, preventing the shortcuts from interfering with other workflows.

Co-authored-by: Emir Karabeg <[email protected]>

* lint

---------

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Emir Karabeg <[email protected]>
Co-authored-by: Waleed Latif <[email protected]>
@vercel
Copy link

vercel bot commented Feb 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Feb 18, 2026 8:08pm

Request Review

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 18, 2026

Greptile Summary

This release bundle (v0.5.93) introduces several features and fixes across the platform:

  • Audit logging system: New audit_log database table with comprehensive instrumentation across ~60 API routes, recording actions like workflow CRUD, deployments, API key management, credential sets, MCP servers, and more. The recordAudit function is fire-and-forget (non-blocking) with proper error handling.
  • MCP domain allowlisting: New ALLOWED_MCP_DOMAINS env var to restrict MCP server connections to approved domains. Includes server-side validation (with double-check after env var resolution), client-side UI feedback, and env var hostname bypass for deferred validation.
  • Integration block restrictions: New ALLOWED_INTEGRATIONS env var for self-hosted deployments to restrict available block types. Merges with existing enterprise permission group config via intersection logic.
  • Locked block outbound connections: Edge protection now only restricts connections to locked blocks, allowing outbound connections from locked blocks.
  • Copilot keyboard shortcut fix: Keyboard navigation for the options selector is now gated to only fire when the copilot panel tab is active, preventing conflicts with other UI elements.
  • Socket crash fix: Locked block subblock updates now send operation-confirmed instead of crashing, preventing client-side socket errors.
  • NextJS config: Beluga tracking short links changed from rewrite to redirect for proper tracking behavior.
  • SSO UI refinement: Callback URL copy button repositioned inline with label, icon changed from Copy to Clipboard.

Confidence Score: 4/5

  • This PR is safe to merge with low risk — the core changes are well-tested and the audit logging is non-blocking.
  • The PR is large (123 files, ~14k lines added) but the bulk of changes are mechanical audit log instrumentation following a consistent pattern. The three new features (audit logging, MCP domain allowlisting, integration block restrictions) are well-tested with dedicated test suites. The audit log is fire-and-forget so it cannot break existing API behavior. The MCP domain check has thorough edge case coverage including env var bypass. The block protection and copilot keyboard shortcut fixes are small, focused changes. Minor style issues exist around case normalization consistency but do not affect runtime behavior. Score reduced from 5 to 4 due to the sheer volume of changes and two minor consistency concerns flagged.
  • apps/sim/hooks/use-permission-config.ts has an asymmetric lowercasing pattern in intersectAllowlists that could cause issues if permission group configs contain mixed-case values. apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/integrations/integrations.tsx is missing .toLowerCase() on service ID comparison.

Important Files Changed

Filename Overview
apps/sim/lib/audit/log.ts New audit log module with fire-and-forget recordAudit function, comprehensive action/resource type enums, and proper error handling. Well-structured and non-blocking.
apps/sim/lib/mcp/domain-check.ts New MCP domain allowlist enforcement with env var bypass for unresolvable hostnames. Properly handles edge cases for authority vs path/query env vars. Well tested.
apps/sim/ee/access-control/utils/permission-check.ts Extended to merge env-level ALLOWED_INTEGRATIONS with permission group config using intersection logic. Case-insensitive matching added. Clean merge logic.
apps/sim/lib/core/config/feature-flags.ts Added getAllowedIntegrationsFromEnv and getAllowedMcpDomainsFromEnv with proper normalization. Handles bare hostnames and full URLs correctly.
apps/sim/next.config.ts Changed Beluga tracking from rewrite to redirect. Removes rewrites() function entirely. Correct fix for short link tracking.
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/block-protection-utils.ts Edge protection now only checks target block, allowing outbound connections from locked blocks. Comments updated to match new behavior.
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/tool-call/tool-call.tsx Fixed copilot keyboard shortcut conflicts by gating keyboard navigation to only when copilot panel is active. Added activeTab dependency correctly.
apps/sim/socket/handlers/subblocks.ts Fixed socket crash by sending operation-confirmed instead of operation-failed when block is locked, preventing client-side errors.
apps/sim/hooks/use-permission-config.ts Added client-side env allowlist fetch via React Query, intersects with permission group config. Proper loading state management.
apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/mcp/mcp.tsx Added client-side MCP domain validation with UI feedback. Duplicates env var hostname detection logic from server-side. Domain check properly blocks submit and test buttons.
packages/db/schema.ts New auditLog table with proper indexes on workspace+created_at, actor+created_at, resource_type+resource_id, and action. FK references with set null on delete.
apps/sim/lib/auth/hybrid.ts Added userName and userEmail to AuthResult interface and populated them from session data. Enables audit logging in routes using hybrid auth.
apps/sim/lib/mcp/service.ts Added domain validation at resolve time and filtered server listings by domain allowlist. Double validation (pre and post env var resolution) is correct.
apps/sim/app/api/mcp/servers/route.ts Added MCP domain validation on POST and audit logging on POST/DELETE. Proper error handling for McpDomainNotAllowedError.
apps/sim/app/api/mcp/servers/test-connection/route.ts Added domain validation both before and after env var resolution, correctly preventing bypass via environment variables resolving to disallowed domains.
apps/sim/lib/copilot/process-contents.ts Extended block metadata processing to use env allowlist as fallback when no userId is present. Case-insensitive matching added.
apps/sim/app/api/settings/allowed-mcp-domains/route.ts New API endpoint exposing allowed MCP domains to the client. Automatically includes platform hostname in the allowlist.
apps/sim/app/api/settings/allowed-integrations/route.ts Simple API endpoint exposing allowed integrations from env var to client. Properly authenticated.
apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/integrations/integrations.tsx Added hyphen-to-underscore normalization for service ID matching against allowlist. Ensures service IDs like google-drive match block types like google_drive.

Flowchart

flowchart TD
    subgraph EnvConfig["Environment Configuration"]
        ALLOWED_MCP["ALLOWED_MCP_DOMAINS env var"]
        ALLOWED_INT["ALLOWED_INTEGRATIONS env var"]
    end

    subgraph MCPDomainEnforcement["MCP Domain Enforcement"]
        ALLOWED_MCP --> FeatureFlags["getAllowedMcpDomainsFromEnv()"]
        FeatureFlags --> DomainCheck["domain-check.ts"]
        DomainCheck -->|"validateMcpDomain()"| ServerRoutes["MCP Server Routes\n(POST/PATCH/DELETE)"]
        DomainCheck -->|"isMcpDomainAllowed()"| McpService["MCP Service\n(resolve/list/get)"]
        DomainCheck -->|"isMcpDomainAllowed()"| ClientMCP["MCP Settings UI\n(domain warning)"]
        FeatureFlags --> AllowedDomainsAPI["/api/settings/allowed-mcp-domains"]
        AllowedDomainsAPI --> ClientMCP
    end

    subgraph IntegrationEnforcement["Integration Block Enforcement"]
        ALLOWED_INT --> IntFeatureFlags["getAllowedIntegrationsFromEnv()"]
        IntFeatureFlags --> PermCheck["permission-check.ts\nmergeEnvAllowlist()"]
        IntFeatureFlags --> CopilotTools["Copilot Block Tools\n(5 server tools)"]
        IntFeatureFlags --> ProcessContents["process-contents.ts"]
        IntFeatureFlags --> AllowedIntAPI["/api/settings/allowed-integrations"]
        AllowedIntAPI --> UsePermConfig["usePermissionConfig hook"]
        UsePermConfig --> IntegrationsUI["Integrations Settings UI"]
        UsePermConfig --> BlockToolbar["Block Toolbar Filter"]
    end

    subgraph AuditSystem["Audit Log System"]
        AuditTable[("audit_log table")] 
        RecordAudit["recordAudit()\nfire-and-forget"]
        RecordAudit -->|"async insert"| AuditTable
        APIRoutes["~60 API Routes"] -->|"recordAudit()"| RecordAudit
        AuthHooks["Auth Hooks\n(password reset)"] -->|"recordAudit()"| RecordAudit
    end
Loading

Last reviewed commit: e396462

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

29 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 18, 2026

Additional Comments (1)

apps/sim/ee/access-control/utils/permission-check.ts
getPermissionConfig returns null without env merge when userId is absent

getPermissionConfig returns null (line 142) when userId is undefined, skipping the mergeEnvAllowlist(null) call. While validateBlockType (line 191) handles this by directly calling mergeEnvAllowlist(null), other callers of getPermissionConfig (like copilot tools that use it via context caching) will not see the env allowlist when userId is undefined. Consider returning mergeEnvAllowlist(null) here for consistency:

  if (!userId) {
    return mergeEnvAllowlist(null)
  }

…oute instrumentation (#3242)

* feat(audit-log): add persistent audit log system with comprehensive route instrumentation

* fix(audit-log): address PR review — nullable workspaceId, enum usage, remove redundant queries

- Make audit_log.workspace_id nullable with ON DELETE SET NULL (logs survive workspace/user deletion)
- Make audit_log.actor_id nullable with ON DELETE SET NULL
- Replace all 53 routes' string literal action/resourceType with AuditAction.X and AuditResourceType.X enums
- Fix empty workspaceId ('') → null for OAuth, form, and org routes to avoid FK violations
- Remove redundant DB queries in chat manage route (use checkChatAccess return data)
- Fix organization routes to pass workspaceId: null instead of organizationId

* fix(audit-log): replace remaining workspaceId '' fallbacks with null

* fix(audit-log): credential-set org IDs, workspace deletion FK, actorId fallback, string literal action

* reran migrations

* fix(mcp,audit): tighten env var domain bypass, add post-resolution check, form workspaceId

- Only bypass MCP domain check when env var is in hostname/authority, not path/query
- Add post-resolution validateMcpDomain call in test-connection endpoint
- Match client-side isDomainAllowed to same hostname-only bypass logic
- Return workspaceId from checkFormAccess, use in form audit logs
- Add 49 comprehensive domain-check tests covering all edge cases

* fix(mcp): stateful regex lastIndex bug, RFC 3986 authority parsing

- Remove /g flag from module-level ENV_VAR_PATTERN to avoid lastIndex state
- Create fresh regex instances per call in server-side hasEnvVarInHostname
- Fix authority extraction to terminate at /, ?, or # per RFC 3986
- Prevents bypass via https://evil.com?token={{SECRET}} (no path)
- Add test cases for query-only and fragment-only env var URLs (53 total)

* fix(audit-log): try/catch for never-throw contract, accept null actorName/Email, fix misleading action

- Wrap recordAudit body in try/catch so nanoid() or header extraction can't throw
- Accept string | null for actorName and actorEmail (session.user.name can be null)
- Normalize null -> undefined before insert to match DB column types
- Fix org members route: ORG_MEMBER_ADDED -> ORG_INVITATION_CREATED (sends invite, not adds member)

* improvement(audit-log): add resource names and specific invitation actions

* fix(audit-log): use validated chat record, add mock sync tests
…, env, deployments, passwords (#3246)

* feat(audit-log): add audit events for templates, billing, credentials, env, deployments, passwords

* improvement(audit-log): add actorName/actorEmail to all recordAudit calls

* fix(audit-log): resolve user for password reset, add CREDENTIAL_SET_INVITATION_RESENT action

* fix(audit-log): add workspaceId to deployment activation audit

* improvement(audit-log): use better-auth callback for password reset audit, remove cast

- Move password reset audit to onPasswordReset callback in auth config
  instead of coupling to better-auth's verification table internals
- Remove ugly double-cast on workflowData.workspaceId in deployment activation

* fix(audit-log): add missing actorName/actorEmail to workflow duplicate

* improvement(audit-log): add resourceName to credential set invitation accept
@waleedlatif1
Copy link
Collaborator Author

@greptile

@waleedlatif1
Copy link
Collaborator Author

@cursor review

@waleedlatif1 waleedlatif1 changed the title v0.5.93: NextJS config changes, MCP and Blocks whitelisting, copilot keyboard shortcuts v0.5.93: NextJS config changes, MCP and Blocks whitelisting, copilot keyboard shortcuts, audit logs Feb 18, 2026
…non-admin) (#3243)

- Add isEnterpriseMember and canViewUsageInfo flags to subscription permissions
- Hide UsageHeader, CreditBalance, billing date, and usage notifications from enterprise members
- Show only plan name in subscription tab for enterprise members (non-admin)
- Hide usage indicator details (amount, progress pills) from enterprise members
- Team tab already hidden via requiresTeam check in settings modal

Closes #6882

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Emir Karabeg <[email protected]>
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

123 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

@waleedlatif1 waleedlatif1 merged commit fdca736 into main Feb 18, 2026
14 of 15 checks passed
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

resourceId: credentialSetId,
description: `Left credential set`,
request: req,
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent resource names in audit logs

Low Severity

Some recordAudit calls omit resourceName while similar operations include it, creating inconsistent audit log completeness. For credential set operations, memberships/route.ts doesn't include the credential set name, while [id]/members/route.ts does via result.set.name. Similarly, billing and environment audit calls lack resource names that would improve traceability. This reduces audit log usefulness since users can't easily identify which specific resource was affected without cross-referencing IDs.

Additional Locations (2)

Fix in Cursor Fix in Web

return createMcpErrorResponse(e, e.message, 403)
}
throw e
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Domain validation runs on optional URLs

Medium Severity

Domain validation executes unconditionally on body.url even when undefined, causing the creation endpoint to reject servers without URLs when an MCP domain allowlist is configured. This contradicts the deliberate design choice to allow creating servers without URLs (evidenced by line 86 generating random UUIDs when URL is missing), and creates inconsistency with the PATCH endpoint which only validates domains when a URL is actually provided.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments