Skip to content

v0.6.52: data retention, docs updates, slack manifest generator, security hardening, contact page, 404 page, access control, SES, SNS#4249

Open
waleedlatif1 wants to merge 18 commits intomainfrom
staging
Open

v0.6.52: data retention, docs updates, slack manifest generator, security hardening, contact page, 404 page, access control, SES, SNS#4249
waleedlatif1 wants to merge 18 commits intomainfrom
staging

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

@waleedlatif1 waleedlatif1 commented Apr 22, 2026

waleedlatif1 and others added 16 commits April 20, 2026 10:54
…nd auth flows (SSRF + open-redirect hardening) (#4236)

* fix(workday): validate tenantUrl to prevent SSRF in SOAP client

* fix(workday): use validation.sanitized in buildWsdlUrl

* fix(security): enforce URL validation across connectors, providers, auth

- Azure OpenAI/Anthropic: validate user-supplied azureEndpoint with validateUrlWithDNS to block SSRF to private IPs, localhost (in hosted mode), and dangerous ports.
- ServiceNow connector: enforce ServiceNow domain allowlist via validateServiceNowInstanceUrl before calling the instance URL.
- Obsidian connector: validate vaultUrl with validateUrlWithDNS and reuse the resolved IP via secureFetchWithPinnedIPAndRetry to block DNS rebinding between validation and request.
- Signup + verify flows: pass redirect/callbackUrl/redirectAfter and stored inviteRedirectUrl through validateCallbackUrl; drop unsafe values and log a warning.
- lib/knowledge/documents/utils.ts: add secureFetchWithPinnedIPAndRetry wrapper around secureFetchWithPinnedIP (used by Obsidian).

* fix(obsidian): use isomorphic SSRF validation to unblock client build

The Obsidian connector is reachable from client bundles via `connectors/registry.ts` (the knowledge UI reads metadata like `.icon`/`.name`). Importing `validateUrlWithDNS` / `secureFetchWithPinnedIP` from `input-validation.server` pulled `dns/promises`, `http`, `https`, `net` into client chunks, breaking the Turbopack build:

  Module not found: Can't resolve 'dns/promises'
  ./apps/sim/lib/core/security/input-validation.server.ts [Client Component Browser]
  ./apps/sim/connectors/obsidian/obsidian.ts [Client Component Browser]
  ./apps/sim/connectors/registry.ts [Client Component Browser]

Once that file polluted a browser context, Turbopack also failed to resolve the Node builtins in its legitimate server-route imports, cascading the error across App Routes and Server Components.

Fix: switch the Obsidian connector to the isomorphic `validateExternalUrl` + `fetchWithRetry` helpers, matching the pattern used by every other connector in the registry. This keeps the core SSRF protections:
  - hosted Sim: blocks localhost, private IPs, HTTP (HTTPS enforced)
  - self-hosted Sim: allows localhost + HTTP, still blocks non-loopback private IPs and dangerous ports (22, 25, 3306, 5432, 6379, 27017, 9200)

Drops the DNS-rebinding defense specifically (the IP-pinned fetch chain). The trade-off is acceptable because the vault URL is entered by the workspace admin — not arbitrary untrusted input — and hosted deployments already force the plugin to be exposed through a public URL (tunnel/port-forward), making rebinding a narrow threat.

Also reverts the `secureFetchWithPinnedIPAndRetry` wrapper in `lib/knowledge/documents/utils.ts` (no longer needed, and its `.server` import was the original source of the client-bundle pollution).

* fix(servicenow): propagate URL validation errors in getDocument

Match listDocuments behavior — invalid instance URL should surface as a
configuration error rather than being swallowed into a "document not found"
null response during sync.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(obsidian): drop allowHttp to restore HTTPS enforcement in hosted mode

allowHttp: true permitted plaintext HTTP for all hosts in all deployment
modes, contradicting the documented policy. The default validateExternalUrl
behavior already allows http://localhost in self-hosted mode (the actual
Obsidian Local REST API use case) via the built-in carve-out, while correctly
rejecting HTTP for public hosts in hosted mode — which prevents leaking the
Bearer access token over plaintext.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* feat(slack): add manifest copying

* Try using wizard modal

* clean up modal

* feat(ui): Add wizard emcn component

* Made modal subblock more generic

* Fix test

* Address greptile comments

* fix handle copy behavior

* Add secret input emcn type

* Lint code
#4230)

* workspace re-org checkpoint

* admin route reconciliation

* checkpoint consistency fixes

* prep merge

* regen migration

* checkpoint

* code cleanup

* update docs

* add feature for owner to leave + admin route

* address comments

* fix new account race

* address comments
…rise SSO docs (#4238)

* improvement(sso): fix provider lookup, migrate UI to emcn, add enterprise SSO docs

* fix(sso): add org membership guard on providers route, fix idpMetadata round-trip

* fix(sso): add org membership guard on register route, fix SP entityID, remove fullError leak

* fix(sso): fix SAML script callbackUrl and SP entityID to use app base URL

* fix(sso): correct SAML callback URL path in script header comment

* fix(sso): restrict SSO provider read/write to org owners and admins

* docs(sso): restructure page, fix provider guide accuracy, add external doc links

* fix(sso): correct SAML callback path and generate idpMetadata from cert+entryPoint

* fix(sso): always require NEXT_PUBLIC_APP_URL for SAML SP metadata entityID

* fix(sso): scope provider query to org only when organizationId is provided

* fix(sso): escape XML special chars in script idpMetadata generation

* fix(sso): final audit corrections — saml mapping, xml escaping, self-hosted org guard

* fix(sso): redact oidc client secret in providers response, add self-hosted org admin guard

* fix(sso): scope redacted-secret lookup to caller's org or userId

* fix(sso): null out oidcConfig on parse failure to prevent unredacted secret leak

* fix(sso): use issuer as entityID in auto-generated idp metadata xml
…stripe test mocks (#4239)

* fix(billing): close TOCTOU race in subscription transfer, centralize stripe test mocks

* more mocks

* fix(testing): provide complete Stripe.Event defaults in createMockStripeEvent

* fix(testing): make dbChainMock .for('update') chainable with .limit()

* fix(billing): gate subscription transfer noop behind membership check

Previously the 'already belongs to this organization' early return fired
before the org/member lookups, letting any authenticated caller probe
sub-to-org pairings without being a member of the target org. Move the
noop check after the admin/owner verification so unauthorized callers
hit the 403 first.
* feat(jobs): Add data retention jobs

Add 3 cron-triggered cleanup jobs dispatched via Trigger.dev (or inline fallback):
- cleanup-soft-deletes: hard-deletes soft-deleted workspace resources past retention
- cleanup-logs: deletes expired workflow execution logs + S3 files
- cleanup-tasks: deletes expired copilot chats, runs, feedback, inbox tasks

Enterprise admins can configure per-workspace retention via Settings > Data Retention.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

# Conflicts:
#	packages/db/migrations/meta/0192_snapshot.json
#	packages/db/migrations/meta/_journal.json
#	packages/db/schema.ts

* Cleanup orphaned using ids, not timestamp sorting

* fix lint
…edit modal (#4240)

* improvement(knowledge): show selector with saved option in connector edit modal

* fix(kb-connectors): clear canonical siblings when non-canonical dep changes; share selector field

* refactor(kb-connectors): extract canonical-field logic into useConnectorConfigFields hook

* fix(kb-connectors): only merge changed fields into sourceConfig on edit save

Avoids writing spurious empty-string keys for untouched optional fields when
another field triggers a save.

* refactor(kb-connectors): tighten state primitives in modals

- edit modal: replace useMemo([]) + eslint-disable with useState lazy
  initializer for initialSourceConfig — same mount-once semantics
  without the escape hatch.
- add modal: drop useCallback on handleConnectNewAccount (no observer
  saw the reference) and inline the one call site.
…tion updates (#4241)

* improvement(enterprise): slack wizard UI, enterprise docs, data retention updates

* improvement(docs): add enterprise screenshots to sso, access-control, whitelabeling pages

* form

* fix(enterprise): address PR review — h-full for recently-deleted, shared SettingRow, toast UX, stale form fix, emcn tokens

* fix(whitelabeling): scope drop zone to thumbnail only, not full upload row

* fix(whitelabeling): remove drop image text from drag overlay

* fix(config): add DATA_RETENTION_ENABLED to env schema to fix build type error

* fix(testing): add isDataRetentionEnabled to feature flags mock

* improvement(docs): remove redundant requirements section from data-retention page

* improvement(docs): remove requirements sections from all enterprise doc pages

* improvement(docs): add screenshot to audit-logs page

* fix(data-retention): bypass enterprise gate when billing is disabled for self-hosted
* feat(log): Add wrapper function for standardized logging

* Add all routes to wrapper, handle background execution

* fix lint

* fix test

* fix test missing url

* fix lint

* fix tests

* fix build

* fix(build): unmangle generic in admin outbox requeue route

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…on (#4242)

* feat(contact): add contact page, migrate help/demo forms to useMutation

* improvement(contact): address greptile review feedback

- Map contact topic to help email type for accurate confirmation emails
- Drop Zod schema details from 400 response on public /api/contact
- Wire aria-describedby + aria-invalid in LandingField for both forms
- Reset helpMutation on modal reopen to match demo-request pattern

* improvement(landing): extract shared LandingField component
…ations routes (#4243)

* fix(layout): use plain inline script for PublicEnvScript to set env before chunks eval on error pages

* fix(landing): handle runtime env race on error-page renders

React skips SSR on unhandled server errors and re-renders on the client
(see vercel/next.js#63980, #82456). Root-layout scripts — including the
runtime env script that populates window.__ENV — are inserted but not
executed on that client re-render, so any client module that reads env
at module evaluation crashes the render into a blank "Application error"
overlay instead of rendering the styled 404.

This replaces the earlier PublicEnvScript tweak with the architectural
fix:

- auth-client.ts: fall back to window.location.origin when getBaseUrl()
  throws on the client. Auth endpoints are same-origin, so this is the
  correct baseURL on the client. Server-side we still throw on genuine
  misconfig.
- loading.tsx under /models/[provider], /models/[provider]/[model], and
  /integrations/[slug]: establishes a Suspense boundary below the root
  layout so a page-level notFound() no longer invalidates the layout's
  SSR output (the fix endorsed by Next.js maintainers in #63980).
- layout.tsx: revert disableNextScript — the research showed this
  doesn't actually fix error-page renders. The real fix is above.

* improvement(landing): use emcn Loader in scoped loading.tsx, trim auth-client comment

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
…gn scoped 404s with root (#4246)

* improvement(landing): scope navbar/footer shell to (shell) route group, align scoped 404s with root

Move integrations and models page routes into a `(shell)` route group so the Navbar+Footer layout wraps pages but not `not-found.tsx`. This lets scoped 404s render the same `<AuthBackground>` + Navbar treatment as the root `/` 404, instead of appearing inside the landing CTA footer.

Extract the shared 404 markup into `<NotFoundView>` so root, integrations, and models 404s share a single source of truth. Route URLs are unchanged — route groups are URL-transparent.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(landing): convert relative imports to absolute in integrations (shell) page

Build failed because the move into the (shell) route group invalidated relative `./components/...` and `./data/...` imports. CLAUDE.md mandates absolute imports throughout — switching these resolves the Turbopack build errors.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* improvement(access-control): migrate to workspace scope

* fix edge cases

* update docs

* prep merge

* regen migrations

* address comments

* add ws id, user constraint

* address more comments

* address ui comments

* address more comments
…S/CloudWatch/DynamoDB (#4245)

* feat(integrations): add AWS SES, IAM Identity Center, and enhanced IAM/STS/CloudWatch/DynamoDB integrations

- Add AWS SES v2 integration with 9 operations (send email, templated, bulk, templates, account)
- Add AWS IAM Identity Center integration with 12 operations (account assignments, permission sets, users, groups)
- Add 3 new IAM tools: list-attached-role-policies, list-attached-user-policies, simulate-principal-policy
- Fix DynamoDB duplicate subBlock IDs, add operation-scoped field names, add subblock migrations
- Add authMode: AuthMode.ApiKey to DynamoDB block
- Fix CloudWatch routes: toError, client.destroy(), withRouteHandler, auth outside try
- Fix STS/DynamoDB/IAM routes: nullable Zod schemas, withRouteHandler adoption
- Fix Identity Center: list_instances pagination, list_groups instanceArn condition
- Add subblock migrations for renamed DynamoDB fields (key, filterExpression, etc.)
- Apply withRouteHandler to all new and existing AWS tool routes

* docs(ses): add manual intro section to SES docs

* fix(dynamodb): add legacy fallbacks in params for subblock migration compatibility

Workflows saved with the old shared IDs (key, filterExpression, etc.) that migrate
to get-scoped slots via subblock-migrations still work correctly on update/delete/scan/put
operations via fallback lookups in tools.config.params.

* feat(contact): add contact page, migrate help/demo forms to useMutation (#4242)

* feat(contact): add contact page, migrate help/demo forms to useMutation

* improvement(contact): address greptile review feedback

- Map contact topic to help email type for accurate confirmation emails
- Drop Zod schema details from 400 response on public /api/contact
- Wire aria-describedby + aria-invalid in LandingField for both forms
- Reset helpMutation on modal reopen to match demo-request pattern

* improvement(landing): extract shared LandingField component

* fix(landing): resolve error-page crash on invalid /models and /integrations routes (#4243)

* fix(layout): use plain inline script for PublicEnvScript to set env before chunks eval on error pages

* fix(landing): handle runtime env race on error-page renders

React skips SSR on unhandled server errors and re-renders on the client
(see vercel/next.js#63980, #82456). Root-layout scripts — including the
runtime env script that populates window.__ENV — are inserted but not
executed on that client re-render, so any client module that reads env
at module evaluation crashes the render into a blank "Application error"
overlay instead of rendering the styled 404.

This replaces the earlier PublicEnvScript tweak with the architectural
fix:

- auth-client.ts: fall back to window.location.origin when getBaseUrl()
  throws on the client. Auth endpoints are same-origin, so this is the
  correct baseURL on the client. Server-side we still throw on genuine
  misconfig.
- loading.tsx under /models/[provider], /models/[provider]/[model], and
  /integrations/[slug]: establishes a Suspense boundary below the root
  layout so a page-level notFound() no longer invalidates the layout's
  SSR output (the fix endorsed by Next.js maintainers in #63980).
- layout.tsx: revert disableNextScript — the research showed this
  doesn't actually fix error-page renders. The real fix is above.

* improvement(landing): use emcn Loader in scoped loading.tsx, trim auth-client comment

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>

* fix(iam): correct MissingContextValues mapping in simulatePrincipalPolicy

* fix(aws): add conditionExpression migration fallback for DynamoDB delete, fix SES pageSize min

* fix(aws): deep validation fixes across SES, IAM, Identity Center, DynamoDB integrations

- IAM: replace non-existent StatementId with SourcePolicyType in simulatePrincipalPolicy
- IAM: add .int() constraint to list-users/roles/policies/groups Zod schemas
- IAM: remove redundant manual requestId from all 21 IAM route handlers
- SES: add .refine() body validation to create-template route
- SES: make bulk email destination templateData optional, only include ReplacementEmailContent when present
- SES: fix pageSize guard to if (pageSize != null) to correctly forward 0
- SES: add max(100) to list-templates pageSize, revert list-identities to min(0) per SDK
- STS: fix logger.error calls to use structured metadata pattern
- Identity Center: remove deprecated account.Status fallback, use account.State only
- DynamoDB: convert empty interface extends to type aliases, remove redundant error field, fix barrel to absolute imports

* regen docs

* fix(iam): add .int() constraint to maxSessionDuration in create-role route

* fix(ses): forward pageSize=0 correctly in listIdentities util

* fix(aws): add gradient background to IdentityCenterIcon, fix listTemplates pageSize guard

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
… fixes (#4248)

* improvement(contact): add Turnstile CAPTCHA, honeypot, and robustness fixes

- Add Cloudflare Turnstile with graceful degradation: when the widget
  fails to load (ad blockers, iOS privacy, corporate DNS), submissions
  fall through to a tighter rate-limit bucket rather than hard-blocking
- Add honeypot field to filter automated submissions without user impact
- Add separate CAPTCHA_UNAVAILABLE_RATE_LIMIT bucket (3/min) for the
  no-captcha path so spam via ad-blocker bypass remains expensive
- Pass expectedHostname to verifyTurnstileToken to close cross-site
  token reuse gap
- Add SITE_HOSTNAME as module-level constant (avoid URL parsing per req)
- Wire onExpire/onError/onUnsupported callbacks so token expiry during
  slow form-filling falls back gracefully instead of showing a captcha error
- Add getResponsePromise(30_000) timeout to prevent indefinite hang on
  network blips
- Add size: 'invisible' to Turnstile options (required for execute mode)
- Move turnstile.ts to lib/core/security/ alongside csp/encryption/input-validation
- Switch all CSS to --landing-* variables throughout contact form
- Move error display inline next to label with truncation in LandingField
- Add labelClassName prop to LandingField for context-specific overrides
- Simplify contact page to single-column max-w-[640px] layout

* fix(contact): fall through to no-captcha rate limit on Cloudflare transport errors

* chore(contact): remove extraneous comments from route

* fix(contact): remove forced min-height on success state, let content flow naturally

* fix(contact): cast CONTACT_TOPIC_OPTIONS to satisfy Combobox mutable type

* fix(contact): disable submit during CAPTCHA resolution window, add relative to form
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 22, 2026

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

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Apr 22, 2026 2:55am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 22, 2026

PR Summary

Medium Risk
Medium risk because it adds a new public POST /api/contact endpoint with CAPTCHA/rate-limiting logic and changes auth/session redirect handling (open-redirect hardening) plus post-upgrade org activation behavior.

Overview
Adds substantial docs expansion: new Enterprise section pages (sso, access-control, audit-logs, data-retention, whitelabeling), updates plan/workspace-permissions docs, and enriches multiple tool docs (CloudWatch/DynamoDB/IAM/STS/JSM/Slack/Fireflies), including new docs entries for AWS Identity Center and AWS SES.

Introduces new landing contact surface: /contact page, reusable LandingField component, and a ContactForm that submits to a new POST /api/contact route. The API implements honeypot spam defense, optional Turnstile verification with fallback rate-limiting, IP-based throttling, and sends both internal help-inbox and user confirmation emails.

Hardens redirect safety by validating callback/redirect URLs in signup and email verification flows (logging and discarding unsafe values), and tweaks SessionProvider to, after a subscription upgrade redirect, invalidate org/subscription queries and attempt to set an active organization when missing.

Adds new integration icons/mappings (IdentityCenterIcon, SESIcon) and updates integrations metadata to include identity_center/ses plus additional IAM operations.

Reviewed by Cursor Bugbot for commit 34cfc26. Configure here.

…SRF (#4250)

* fix(aws): add validateAwsRegion to all AWS route schemas to prevent SSRF

* fix(validation): add mx and eu-isoe prefixes to validateAwsRegion regex

* test(validation): add mx-central-1, eu-isoe-west-1, and us-iso-west-1 region test cases

* fix(aws): eliminate double validateAwsRegion call and fix regex alternation order

- Replace double-call .refine() pattern with single-call + static message across all 61 AWS routes
- Reorder regex alternation to put longer prefixes first (eu-isoe before eu, us-isob/us-iso/us-gov before us) for engine-agnostic correctness
#4252)

* fix(deps): bump drizzle-orm to 0.45.2 (GHSA-gpj5-g38j-94v9)

Resolves Dependabot alert #98. Drizzle ORM <0.45.2 improperly escaped
quoted SQL identifiers, allowing SQL injection via untrusted input
passed to APIs like sql.identifier() or .as().

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore(mcp): adopt native SDK types after @modelcontextprotocol/sdk 1.25.3 bump

Replace hand-written schema/annotation shapes with the SDK's exported
Tool, JSONRPCResultResponse, and Tool['annotations'] types so changes
upstream flow through automatically.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(types): use drizzle $inferSelect for row types

Replace hand-written interfaces that duplicated schema shape with
typeof table.$inferSelect aliases for webhook, workflow, and
workspaceFiles rows. Also simplify metadata insert/update to use
.returning() instead of field-by-field copies.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(uploads): fall through to INSERT if restore-deleted row races a hard delete

If a hard delete races between the initial SELECT and the restore UPDATE,
.returning() yields no row. Previously the function would return undefined
and silently violate the Promise<FileMetadataRecord> contract. Now the
function falls through to the INSERT path, which already handles
uniqueness races via the 23505 catch.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore(uploads): align metadata.ts with global standards

Replace dynamic uuid import with generateId() per @sim/utils/id
convention, narrow the error catch off `any`, and convert the inline
comment to TSDoc.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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.

4 participants