Skip to content

v0.7.1: chat voice mode model update, sim trigger, codepipeline integration, smooth streaming, security hardening, db fixes #4951

Merged
waleedlatif1 merged 10 commits into
mainfrom
staging
Jun 10, 2026
Merged

v0.7.1: chat voice mode model update, sim trigger, codepipeline integration, smooth streaming, security hardening, db fixes #4951
waleedlatif1 merged 10 commits into
mainfrom
staging

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

waleedlatif1 and others added 9 commits June 9, 2026 21:54
#4939)

* fix(db): serialize concurrent migrations with a Postgres advisory lock

Deployments start N app replicas at once, each with a migration sidecar.
drizzle migrate() has no cross-process lock, so all N read
__drizzle_migrations, all see the same migration pending, and all apply it
concurrently — one wins, the losers run the same DDL against already-mutated
state and exit 1 (e.g. DROP TABLE "form" -> table does not exist /
TaskFailedToStart). Wrap migrate() in a session-level pg_advisory_lock so
runners serialize: the winner migrates, the losers block, then re-read and
find nothing pending. Session locks auto-release on disconnect, so a crashed
runner never wedges the lock.

* fix(db): guard pg_advisory_unlock so it cannot mask a successful migration

If the explicit unlock throws (e.g. connection drops in the window after
migrate() commits), the exception bubbled to the outer catch and exited 1 —
falsely reporting a failed migration to the deploy orchestrator. The session
lock auto-releases on disconnect anyway, so swallow and log instead.

* refactor(db): move unlock-guard rationale to TSDoc helper
* feat(realtime): preflight schema-compatibility check on startup

The socket service authorizes every connection with a full-row query against
the workflow table. When a deploy ships a realtime image whose compiled schema
is ahead of/behind the live DB (e.g. a column dropped by a migration the image
predates), that query fails on every request and silently breaks persistence —
yet the process stays up and the shallow /health probe keeps returning 200, so
the deploy looks healthy while serving nothing.

Run one representative workflow query before listen(): a schema mismatch throws,
propagates to the entrypoint, and the task exits non-zero and never goes healthy,
so CodeDeploy auto-rolls-back instead of shifting traffic onto broken tasks.

Schema-class errors (undefined column/table/function) fail fast; connection-class
errors retry with backoff so a cold DB at boot does not flap. Runs once at
startup, never on the per-probe LB health check, to avoid a DB blip mass-
terminating the fleet (cascading failure).

* fix(realtime): unwrap cause for schema codes, drop sleep after final attempt

- isSchemaMismatch now walks the error.cause chain — drizzle wraps the driver
  error, so the SQLSTATE often lives on the inner cause, not the outer throw.
  Without this a wrapped 42703/42P01 was retried 5x and mis-reported as
  "database unreachable" instead of failing fast.
- No longer sleeps after the final failed attempt (~6-10s of dead wait that
  undermined the fail-fast contract); sleep now only happens between attempts.
- Tests: assert sleep is called exactly 4 times on exhaustion, and add a
  wrapped-cause fail-fast case.
…hem (#4942)

* fix(secrets): keep readonly secret names legible instead of dimming them

Readonly viewers saw the workspace secret name at opacity-50 while the
masked value rendered at full opacity, an inconsistent and hostile
treatment of content they need to read. Drop the opacity dim on the
non-renameable key; non-editability is already conveyed by the read-only
field and absent edit affordances.

* fix(secrets): use cursor-text on readonly key to hint selectability
* improvement(chat-voice): modernize ElevenLabs TTS to Flash v2.5

- Switch default TTS model from eleven_turbo_v2_5 to eleven_flash_v2_5 (ElevenLabs recommends Flash over Turbo in all cases; ~75ms latency)
- Drop deprecated optimize_streaming_latency knob plus legacy use_pvc_as_ivc / enable_ssml_parsing flags
- Move output_format to the query string and raise it from mp3_22050_32 to mp3_44100_128 for higher audio quality
- Switch apply_text_normalization from off to auto for correct number/date pronunciation

* improvement(chat-voice): default to Jessica voice (Flash v2.5-optimized)

Replace the legacy Sarah default (EXAVITQu4vr4xnSDxMaL), which has no high-quality
eleven_flash_v2_5 base, with Jessica (cgSgspJ2msm6clMCkdW9) — a current premade
conversational voice verified against the live account and optimized for Flash v2.5.
* feat(workflows): sim trigger, logs v2 block, toolbar renaming

* fix(review): bound rule queries, canonical logs params, watched-workflow SQL scoping

Code-review fixes: read the canonical workflowIds param in logs_v2 (the
serializer deletes the source pair ids), aggregate failure-rate in the DB
and switch rule windows to the indexed startedAt column, clamp rule config
to the legacy contract bounds, push no_activity watch scoping into SQL
before the LIMIT, fix the generated sim icon-map key, normalize docs
wording, and drop dead exports.

Co-authored-by: Cursor <cursoragent@cursor.com>

* address comments

* fix(review): integer rule rounding, success-gated workflow labels, display module hygiene

Second-pass review fixes: round integer rule fields so fractional input
never reaches SQL LIMIT, gate workflow-name readiness on a successful
non-placeholder load in both editor and preview (errored loads mislabeled
valid workflows as deleted), lazily read the variables store in preview
rows, move the filter-field JSON preview into the shared display module
and unexport its single-consumer helpers, and align >= boundary copy
(failure rate, error count, cooldown window) with implementation.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: sync lockfile after staging merge

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(workspace-events): keyset-paginate the no_activity subscription scan

A fixed LIMIT 500 with no ORDER BY silently starved subscriptions beyond
the cap once the global count exceeded it. The poll now pages by webhook
id so every subscription is visited each cycle; pagination bounds memory,
not total work.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(workspace-events): keyset-paginate the watched-workflow scan

The 500-row LIMIT silently and deterministically excluded high-id
workflows from no_activity coverage in watch-everything subscriptions on
large workspaces. The scan now pages by workflow id, mirroring the
subscription scan; per-workflow checks move into a helper so the
pagination loop stays flat.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(workspace-events): skip no_activity subscriptions on the execution-completion path

no_activity is poller-owned and can never fire from a completed execution,
but it passed into the rule branch and cost a pointless cooldown point-read
per subscription on the hottest path. Early-continue alongside the
workflow_deployed guard.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(sim-trigger): note failure-based alert conditions evaluate on failed runs

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(blocks): recategorize Data Enrichment as a core block

It's a Sim-native capability (registry enrichments over a managed provider
cascade, like Search), not a third-party integration. Moves it to Core
Blocks in the toolbar, out of the integrations catalog, and relocates its
docs page to blocks/ with the icon-map allowlist keeping the docs card icon.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(blocks): recategorize MySQL, PostgreSQL, SFTP, SMTP, SSH as integrations

External-system connectors with host/credential auth belong under
Integrations, not Core Blocks — consistent with MongoDB, Redis,
ClickHouse, and the other datastore integrations. They already carried
integrationType and /tools docsLinks; the regenerated docs pages turn
those previously-dangling links into real pages, and the blocks join the
integrations catalog and icon maps.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(knowledge): require write access for batch chunk operations

The PATCH /api/knowledge/[id]/documents/[documentId]/chunks handler
performs enable/disable/delete operations but authorized callers with
only read-level access (checkDocumentAccess). This let read-only
workspace members destroy or disable indexed chunks.

Switch to checkDocumentWriteAccess (write/admin required), matching the
sibling POST/PUT/DELETE chunk mutation endpoints.

* fix(env): restrict decrypted workspace env vars to secret admins

GET /api/workspaces/:id/environment returned decrypted workspace
environment variables to any member, including read-only collaborators,
leaking API tokens, database URLs, and other secrets.

Mask workspace variable values for non-admin viewers while preserving
the variable names, so editor autocomplete and conflict detection keep
working. A value is revealed only when the caller is a credential admin
of that key, or — for legacy keys with no per-secret ACL — holds
workspace admin permission. This mirrors the per-key edit gating already
enforced by PUT/DELETE: if you can administer a secret, you can read it.

Personal variables and execution-time resolution are unchanged.

* fix(files): block cross-tenant deletion via client-controlled context

POST /api/files/delete trusted a client-supplied `context`, letting any
authenticated user delete another tenant's file by naming an arbitrary
key with `context: "og-images"`. verifyFileAccess() short-circuited the
three public contexts (profile-pictures, og-images, workspace-logos) to
`true` before any ownership/requireWrite check.

- Derive the storage context strictly from the trusted key prefix in the
  delete route; reject a supplied `context` that disagrees with the key.
- Gate the public-context short-circuit to reads only. Destructive ops
  (requireWrite) now prove ownership via verifyPublicAssetWriteAccess:
  workspace-logos require write/admin on the bound workspace,
  profile-pictures require an exact owner match, og-images always deny.

Reads of public assets are unchanged.

* fix(telegram): verify X-Telegram-Bot-Api-Secret-Token on inbound webhooks

Telegram triggers accepted any forged update from anyone who knew the
webhook URL path: verifyAuth was a no-op that always returned null, and
setWebhook registered no secret_token.

Generate a per-webhook secret in createSubscription, register it with
Telegram as secret_token, and persist it to providerConfig. verifyAuth
now fails closed — rejects when no token is configured, when the
X-Telegram-Bot-Api-Secret-Token header is absent, or when it does not
match via constant-time safeCompare.

* fix(security): pin DNS for Agiloft directExecution and Grafana update tools

The Agiloft directExecution tools (read/create/search/update/delete/lock/
saved_search/select/get_choice_line_id/remove_attachment/attachment_info)
and the Grafana update_dashboard/update_alert_rule postProcess hooks issued
outbound HTTP to a fully user-controlled host (instanceUrl/baseUrl) via the
global fetch(), guarded only by the synchronous validateExternalUrl() — which
never resolves DNS, so a hostname resolving to an internal/reserved IP passed
validation (SSRF).

Route all of these through the codebase's standard SSRF-safe path:
- Agiloft: moved executeAgiloftRequest into utils.server.ts where the existing
  pinned helpers live. It now resolves+validates the instance URL once and pins
  every hop (login, operation, logout) to that IP via secureFetchWithPinnedIP.
  The 11 tool configs now import it from utils.server; URL builders stay in the
  client-safe utils.ts.
- Grafana: the postProcess POST/PUT now uses validateUrlWithDNS +
  secureFetchWithPinnedIP, matching the already-pinned initial GET.

This completes the Agiloft SSRF pinning started in #4639 (which covered the
attach/retrieve API routes) by closing the directExecution path, and extends
the same guard to the Grafana update tools.

* fix(api): enforce workspace allowPersonalApiKeys policy on v1 surface

The external v1 API authenticated API keys without evaluating the
per-workspace allowPersonalApiKeys setting, so a personal API key could
read and mutate a workspace's resources (workflows, tables, files,
knowledge, logs) even when the workspace had explicitly disabled personal
keys. The same control is already enforced on the workflow-execution
surface.

Enforce the policy in checkWorkspaceScope (covering validateWorkspaceAccess
too): reject personal keys with 403 when the workspace has
allowPersonalApiKeys=false. checkWorkspaceScope becomes async; all v1
route callsites updated to await it.

* fix(billing): close usage-cap admission race with atomic reservation

The server-side usage-limit gate read already-recorded cost, but cost is
only written when an execution finishes. A burst of concurrent executions
all observed the same pre-burst usage, all passed the cap, and all ran —
collectively spending far past the limit before any cost landed in the
ledger (free-tier abuse / hard-cap defeat). manual/chat triggers also skip
rate limiting, removing the only throttle.

Add an atomic check-then-reserve admission step (Redis Lua) that bounds
in-flight, un-costed executions per billing entity by both a per-plan
concurrency cap and remaining usage headroom, so recordedUsage +
reservedSlots * estimate <= limit always holds. The slot is released at
execution completion via LoggingSession (skipped on pause; TTL self-heals
crashes). Runs for all trigger types, covering the previously-unthrottled
manual/chat paths.

Fails open when billing is disabled or Redis is unavailable, matching the
rate limiter — a Redis blip can't turn into an execution outage, and the
recorded-usage gate still runs.

* fix(workflows): validate folderId belongs to workflow's workspace on create/update/reorder

Reject a folderId that references a folder in a different workspace (or
an archived/non-existent folder) before writing it to workflow.folderId.
Previously create, update, and reorder only checked workspace permission
on the workflow and the folder's lock status, never that the folder lived
in the workflow's own workspace, allowing a dangling cross-workspace
folder reference.

Adds isFolderInWorkspace/assertFolderInWorkspace + FolderNotFoundError to
@sim/workflow-authz (mirroring assertTargetFolderMutable in the duplicate
path), enforced in performCreateWorkflow, performUpdateWorkflow, and the
reorder route. Invalid folders now return 400.

* fix(folders): validate parentId against workspace on create/update/reorder

Folder write endpoints accepted a caller-supplied parentId and persisted it
without verifying the parent existed in the same workspace, and the create and
reorder paths had no cycle guard. A workspace member with write access could
reparent a folder to a foreign-workspace folder, a non-existent id, or (via
reorder) into a cycle, hiding the folder and its workflows from all members.

- performCreateFolder: reject self-parenting and validate the parent exists in
  the workspace and is not archived (mirrors the duplicate route).
- performUpdateFolder: add the same workspace/archived parent check alongside
  the existing circular-reference guard.
- folders/reorder: validate every target parent against the workspace, detect
  cycles in the resulting parent graph (catches batch cycles), and normalize
  falsy parentId to null to prevent orphaning.

Adds tests for cross-workspace parent rejection and batch-cycle rejection.

* chore(knowledge): drop non-TSDoc inline comments from chunks route

* fix(webhooks): fail closed when HMAC signing secret is not configured

Inbound webhook signature verification failed open for HMAC providers
(GitHub, Intercom, Jira, JSM, Confluence, Cal.com, Notion, Greenhouse,
Typeform, Fireflies, Circleback): when no signing secret was stored,
verifyAuth returned null and the workflow executed on a fully
attacker-controlled body. Reject these deliveries with 401 instead,
matching the fail-closed Stripe/WhatsApp/Vercel providers.

Run provider reachability/verification handshakes (Notion
verification_token, Grain/Intercom ping) ahead of auth so the
pre-secret setup handshake still completes — those return a canned 200
without executing the workflow, and real event payloads fall through to
fail-closed verification.

Update the trigger secret-field copy to state the secret is required
for deliveries to be accepted (was misleadingly marked optional).

* style(files): trim verbose inline comments on delete authorization fix

* fix(auth): close account-enumeration oracle on email sign-up

The custom before-hook pre-check threw a distinguishing
422/USER_ALREADY_EXISTS for already-registered emails, letting an
unauthenticated attacker enumerate accounts — defeating better-auth's
own OWASP enumeration protection (active under requireEmailVerification).

Remove the pre-check and rely on better-auth's generic duplicate-sign-up
response, wiring:
- onExistingUserSignUp: notify the real account owner out-of-band,
  mirroring the privacy-preserving forget-password flow.
- customSyntheticUser: include admin (role/banned/banReason/banExpires)
  and Stripe (stripeCustomerId, billing-gated) user fields so the fake
  response shape is byte-identical to a real new-user response.

Adds an ExistingAccountEmail template + 'existing-account' subject.

* style(tools): drop non-TSDoc inline comments from Grafana/Agiloft SSRF tools

* chore(api): trim extraneous inline comments in v1 logs/files routes

Remove a redundant size annotation and two verbose multi-line
materialization comments whose intent is already clear from the code.
Load-bearing comments (race-condition and key-translation notes) kept.

* fix(billing): exclude table-cell dispatch from admission reservation

Table-cell dispatch is row-bounded, async rate-limited, and already
surfaces a graceful usage state. Applying the in-flight concurrency
reservation there turned its 429 into a hard cell error on a normal
>15-concurrent-cell run (only 402 was handled gracefully). Skip the
reservation for that surface via a new skipConcurrencyReservation option
(the usage-cost cap is still enforced), and tidy the reservation comments
to TSDoc.

* fix(chat): rate-limit and constant-time password auth for public chats

Password-protected public chat (POST /api/chat/[identifier]) had no
throttling on the password check and compared with a non-constant-time
!==, allowing unlimited brute-force and per-character timing leaks.

- Add per-IP rate limiting (10 / 15min) to the password branch of
  validateChatAuth, mirroring the OTP/SSO endpoints; return 429 with
  Retry-After. Only explicit unlock attempts consume tokens — message
  sends carry no password and ride the auth cookie.
- Replace password !== decrypted with safeCompare.
- Fails open on rate-limiter storage errors; no availability regression.

* fix(security): cap JSON request body size and gate public chat endpoint

The shared parseJsonBody helper (behind parseRequest, used by nearly
every contract route) read request bodies with no size limit, buffering
the full body into memory before validation. The unauthenticated public
deployed-chat endpoint reached this sink with no admission gate, enabling
an anonymous memory-exhaustion DoS.

- parseRequest/parseJsonBody now enforce a byte cap via a size-limited
  stream read (content-length precheck + streamed cap), returning 413.
  Default is API_MAX_JSON_BODY_BYTES (50 MB), overridable per route via
  maxBodyBytes. Decoding uses TextDecoder to match request.json() BOM
  handling.
- Public chat POST is wrapped with the admission gate (tryAdmit) and
  passes an explicit CHAT_MAX_REQUEST_BYTES (20 MB) cap.
- Chat body contract gains .max() bounds on input, password,
  conversationId, file data/name/type, and files array length.
- Admin bulk workspace import opts into a higher 100 MB cap to avoid
  regressing large multi-workflow imports.

* fix(chat): rate-limit and constant-time password auth for public chats

Password-protected public chat (POST /api/chat/[identifier]) had no
throttling on the password check and compared with a non-constant-time
!==, allowing unlimited brute-force and per-character timing leaks.

- Add per-IP rate limiting (10 / 15min) to the password branch of
  validateChatAuth, mirroring the OTP/SSO endpoints; return 429 with
  Retry-After. Only explicit unlock attempts consume tokens — message
  sends carry no password and ride the auth cookie.
- Replace password !== decrypted with safeCompare.
- Fails open on rate-limiter storage errors; no availability regression.

Reinstates the fix reverted by an intervening commit.

* fix(billing): never block a lone execution on usage headroom

The admission reservation tapered allowed concurrency by remaining usage
headroom. With under one credit of headroom left (but not yet over the
cap), floor(headroom / estimate) hit zero and rejected even a single,
zero-concurrency execution — stricter than the recorded-usage gate, which
would have allowed that last run, and with a misleading "too many
concurrent executions" message. Floor the headroom term at 1 so a lone
execution is governed only by the cost gate; concurrency above the first
slot still tapers with headroom.

* refactor(env): document workspace env masking, drop inline comments

Extract the workspace-env value masking into a TSDoc-documented
maskWorkspaceEnvForViewer helper and remove the redundant inline
comments from the GET handler and its test. No behavior change.

* refactor(env): convert PUT/DELETE authz comments to TSDoc

Move the tiered-authorization rationale for the workspace env upsert and
delete handlers into TSDoc blocks and drop the inline comments. No
behavior change.

* fix(telegram): keep legacy webhooks working via Telegram source-IP fallback

The secret-token check rejected every webhook registered before secret_token
support, breaking live triggers until re-saved. Fall back to verifying the
request originates from Telegram's published webhook IP ranges when no secret
is configured, so existing triggers keep firing with no re-save or migration
while forged updates from arbitrary hosts are still rejected. Webhooks with a
registered secret continue to use strict constant-time token verification.

* fix(chat): restore constant-time password auth and IP rate limit

A billing commit (ac56525) reverted the public-chat auth hardening as
collateral, leaving HEAD with a timing-oracle password comparison
(password !== decrypted) and no per-IP brute-force rate limit. Restore
safeCompare and the password-attempt rate limiter, and re-add the 429 test.

* revert(webhooks): undo trigger auth hardening pending compat plan

Reverts the Telegram inbound-token verification (3ed97a4, 41f133a)
and the HMAC fail-closed change (5b6cae9). Production data shows ~79
live webhooks have no signing secret configured (63 GitHub, 9 Fireflies,
3 Jira, 2 Circleback, 1 Confluence, 1 Cal.com), so failing closed would
401 them. Restoring fail-open behavior until a backwards-compatible
rollout (grandfather existing secretless webhooks / migration) is designed.
Other security fixes on this branch are unaffected.

* test(chat): make RateLimiter mock a constructable class

The arrow-function mockImplementation form was not reliably constructable
in the full suite run (`new RateLimiter()` threw "is not a constructor"),
though it passed in isolation. Switch to the class-based mock used by the
sibling OTP/speech route tests.

* fix(billing): release admission slot on pre-execution aborts; cluster-safe release

Addresses PR review on the usage-cap admission reservation:

- Slot leak: the reservation taken at the end of preprocessing was only
  released when the LoggingSession finalized. The execute route's
  pre-execution exits (client cancel, workspace/API-key guards) returned
  without finalizing a session, leaking the slot until its TTL and wrongly
  throttling later runs. Release explicitly on those paths; executions that
  start are still released via session finalization.
- Release is now cluster-safe: replaced the Lua script that rebuilt the
  in-flight key from the pointer value (a key not declared in KEYS, which
  silently breaks Redis Cluster slot routing) with discrete single-key
  GETDEL + ZREM commands.

* improvement(files): log missing owner metadata distinctly on profile-picture delete deny

Per PR review: when a profile-picture delete is denied, distinguish a
missing owner record (no userId metadata) from a genuine ownership
mismatch so the fail-closed denial is diagnosable. Behavior unchanged —
both still deny.

* fix(billing): release admission slot when async enqueue fails

If queueing the background workflow job throws, no job runs and no
LoggingSession finalizes, so the admission slot reserved during
preprocessing would leak until its TTL. Release it before returning 500.

* fix(api): make body-size caps NaN-safe and raise chat input/attachment limits

- DEFAULT_MAX_JSON_BODY_BYTES and CHAT_MAX_REQUEST_BYTES now fall back to
  hardcoded defaults (50 MB / 220 MB) when the env value is missing or
  non-numeric, so a misconfig can't silently produce a NaN cap that never
  rejects.
- Raise CHAT_MAX_REQUEST_BYTES default to 220 MB to cover 15 base64 file
  attachments, and MAX_CHAT_INPUT_CHARS to 1,000,000.
- Minor: tidy use-inline-rename onSave type; drop two redundant test comments.

* fix(hooks): restore void return in useInlineRename onSave type

A prior commit changed onSave's return type from `void | Promise<unknown>`
to `undefined | Promise<unknown>`, which broke the build: callbacks that
return nothing (table-grid column rename, table header rename) infer a
`void` return, which is not assignable to `undefined`. Restore the `void`
union so both fire-and-forget and Promise-returning callbacks type-check.

* fix(billing,api): release chat reservation slot on early exit; preserve 413 on oversized import

- Chat route: preprocessExecution reserves a billing concurrency slot, but
  the post-preprocess early exits (missing workspaceId, execution-setup
  failure) returned without releasing it, leaking the slot until TTL and
  wrongly throttling later runs. Release explicitly on those paths
  (idempotent), mirroring the workflows execute route.
- Admin import route: an oversized JSON body now returns the real 413 from
  parseJsonBody instead of being remapped to a 400; invalid JSON still 400s.

* fix(icons): make Infisical icon black for contrast; regenerate docs

The Infisical mark rendered near-white on its yellow block background and
was barely visible; switch its fill from currentColor to #000000 (matching
the hardcoded-fill pattern of sibling brand icons). Sync the docs icon copy
and pick up a stale servicenow doc regeneration.

* fix(billing): release reserved slot on execute-route 503 and setup throw

After preprocessExecution reserves a billing concurrency slot, the streaming
path could exit without releasing it: the 503 return when
initializeExecutionStreamMeta fails, and any throw during stream setup (caught
by the outer handler, which only returned 500). Both left the slot held until
TTL, wrongly throttling unrelated runs. Release on the 503 path and in the
outer catch (executionId hoisted so the catch can see it; release is
idempotent and a no-op when no slot was reserved).

* fix(icons): make Linkup icon black for contrast

The Linkup mark rendered with currentColor (near-white on its block
background); switch its fill to #000000 for legibility, matching the
Infisical fix. Docs icon copy synced via generate-docs.

* fix(billing): release reserved slot if inline async job never starts

In the inline (single-process) async path, if jobQueue.startJob threw before
executeWorkflowJob ran, no LoggingSession finalized and the reserved billing
slot was held until TTL. Release it in the fire-and-forget catch (idempotent;
a no-op when the job already finalized and released). The queued-worker path
and all in-job outcomes already release via the job's LoggingSession finalize.
…lock (#4945)

* feat(codepipeline): add AWS CodePipeline integration with tools and block

* fix(codepipeline): address review feedback on input coercion and error statuses

* chore(hooks): restore use-inline-rename onSave type accidentally swept into previous commit
…ex fix (#4947)

* fix(emcn): render dropdown menus above modals so in-modal dropdowns are clickable

The base DropdownMenuContent defaulted to --z-dropdown (100), below the
modal at --z-modal (200) — the only Radix popper that sat below the
modal (Popover/Tooltip/Toast all sit above). Since the modal overlay is
semi-transparent, an in-modal dropdown was faintly visible but
intercepted no clicks, which forced one-off z-popover overrides on
ChipDropdown and ChipSelect.

Move the DropdownMenu base to the popover layer (--z-popover, above the
modal) and drop the redundant per-component overrides, so every menu —
including the 39 raw DropdownMenu consumers — is clickable inside a chip
modal from a single source of truth. The --z-dropdown variable stays at
100 for the in-flow panels that intentionally sit below modals.

* improvement(mothership): smooth streamed text reveal and fix completion flash

Port opencode's paced word-boundary reveal into useSmoothText so streamed text builds smoothly regardless of how the model chunks deltas, and keep it smooth through completion:

- Reveal on a steady 24ms timer in tiered steps that snap to word/punctuation boundaries instead of revealing partial tokens.
- Drain the lagging tail at the paced cadence on stream end instead of snapping; the consumer holds streaming render until the reveal catches up.
- Pin a streamed message to Streamdown's streaming mode for its mounted lifetime so the static-mode swap doesn't remount and re-highlight the message.
- Key the assistant row by its owning user message id so the live->persisted id swap no longer remounts the row (whole-message blink) at completion.

* docs(emcn): trim z-index scale comment to original footprint

Correct the pre-existing scale comment in place (the old wording became
stale when DropdownMenu moved to the popover layer) rather than expanding
it. The scale tokens are global, so their documentation stays with them.
@gitguardian

gitguardian Bot commented Jun 10, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
33881454 Triggered Generic Password 3cedac8 apps/sim/app/api/chat/utils.test.ts View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@vercel

vercel Bot commented Jun 10, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jun 10, 2026 8:15pm

Request Review

@cursor

cursor Bot commented Jun 10, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Changes span authz (files, folders, v1 API keys, webhooks), billing concurrency on execute/chat, and realtime startup failure modes—high impact if misconfigured, though most paths add fail-closed checks and tests.

Overview
v0.7.1 bundles workspace observability workflows, new integrations/docs, realtime deploy safety, and a broad security/reliability pass.

Sim trigger & Logs — Docs add a Logs block page and a Sim trigger guide; execution API/logging docs drop workspace webhook/email/Slack notification setup and point real-time reactions at the Sim trigger instead. Icons/docs register sim_workspace_event, CodePipeline, and database/transfer tools (MySQL, PostgreSQL, SFTP, SMTP, SSH).

AWS CodePipeline — New internal-auth tool API routes (list/start/stop pipelines, approvals, retries, etc.) plus matching docs.

RealtimeassertSchemaCompatibility runs once before the socket server listens: fails fast on schema mismatch, retries transient DB errors, so bad deploys don’t stay “healthy” while auth queries break.

Security & abuse preventionFile deletes infer context from the storage key and reject client context mismatches; public asset contexts stay world-readable but writes require ownership. Chat passwords use constant-time compare and per-IP rate limits (429 + Retry-After). Webhook trigger returns 404 for sim/table internal paths so events can’t be forged over HTTP. Folder reorder/create validates parents and cycle detection; workflow reorder checks folder in workspace. v1 APIs checkWorkspaceScope is async and blocks personal API keys when the workspace disallows them. Log detail by execution accepts internal/session hybrid auth. KB batch chunk create uses write access.

Execution & chat hardeningChat and workflow execute use admission tryAdmit, larger chat body cap, and releaseExecutionSlot on early failures/async enqueue errors so billing concurrency doesn’t leak.

OtherElevenLabs TTS stream defaults updated (mp3_44100_128, simplified body). globals.css raises popover/tooltip z-index above modals. Email preview drops workflow-notification templates. Minor icon fill tweaks (Linkup, Infisical).

Reviewed by Cursor Bugbot for commit 9aa2a51. Configure here.

@waleedlatif1 waleedlatif1 merged commit 7ffc495 into main Jun 10, 2026
14 checks passed
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.

3 participants