Skip to content

v0.7.66: provenance logs, nuqs consolidation - #6487

Merged
waleedlatif1 merged 6 commits into
mainfrom
staging
Aug 10, 2026
Merged

v0.7.66: provenance logs, nuqs consolidation#6487
waleedlatif1 merged 6 commits into
mainfrom
staging

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

…d subject layer (#6482)

* improvement(emails): funnel every sender through the shared render and subject layer

* fix(emails): cover dynamic imports in the boundary guard and mock the new subject helper

* fix(emails): mock the module the limit-notification sender actually imports
…ed (#6484)

DISABLE_REGISTRATION blocks /signup server-side, but the invite flow, the
login form, the SSO form, and the CLI handoff all kept routing people there,
stranding invited users on a dead end. The flag also never covered OAuth
account creation, so social sign-in still minted accounts for unknown
identities.
… refusal (#6483)

* fix(provenance): report why a projection was refused, at the point of refusal

A refusal fails closed and reaches the user as one fixed sentence. The guard
that caused it may have tripped many frames — or a whole process — earlier, and
the incompleteness latch is one-way, so by then the causing call has long
returned. #6478 recorded the reason when the guard tripped, but marking
early-returns once a registry is already incomplete, so a run that inherits an
incomplete registry refused with nothing recorded anywhere. That is the case
production actually hits.

Retain reasons on the registry and report them where the refusal happens. The
reason is recorded before the already-incomplete return so a causal chain
accumulates, and before the silence checks so a by-design origin that logs
nothing when marked is still nameable at refusal. Propagation inherits through
markIncomplete's source argument, and copying incomplete input paths carries
their reasons, so a fork cannot latch without its cause.

Route all 68 refusal sites through one choke point that logs boundary, cause,
input path and workspace before throwing. It returns never, so callers still
narrow; messages and thrown types are unchanged at every site. Records carry a
cause discriminator, since a latched registry and a caller-side cross-check of
the projection's own output both arrive here and only the former has reasons.

No behaviour change.

* fix(provenance): stop registry-less refusals deduplicating across requests

A refusal with no registry aborts the request rather than iterating, so it
reaches the reporter at most once per request. Remembering it for the process
silenced every later request, including the one being investigated.

* improvement(provenance): inherit copied-path reasons once per copy

Semantics are unchanged — reasons are still inherited only when at least one
incomplete path was actually copied — but the source set is walked once rather
than once per copied path.
* chore(deps): drop the archived image-size dependency

* improvement(content): cover GIF and warn when OG dimensions are unreadable

* improvement(content): read OG dimensions via sharp instead of a bespoke parser
…mirroring it (#6486)

* improvement(url-state): use nuqs setters and derive state instead of mirroring it

Wave 1 of a URL-state audit sweep.

- files: replace the last hand-built same-path query mutation with the nuqs
  group setter, which no longer drops shareFileId/search/type/size/uploaded-by/sort/dir
- suspense: give six page entries their co-located loading.tsx skeleton
  instead of fallback={null}
- invite: derive isNewUser/urlError/token during render so the invitation
  query key is correct on first commit
- resume: derive selectedStatus/queuePosition from the query cache the
  mutation already writes
- verify, logs, terminal: delete dead and duplicate state
- rules: document same-path router.replace as a query mutation, and the
  loading.tsx-as-Suspense-fallback convention

* fix(invite): wait for the stored token before enabling the invitation query

An authenticated user opening an invite without a token in the URL fired the
query with a null token before the effect restored the session-stored one,
producing a transient forbidden state and a redundant request under a second
cache key. Distinguish 'storage not yet read' (undefined) from 'read and empty'
(null) and gate the query on that.
@waleedlatif1
waleedlatif1 requested a review from a team as a code owner August 10, 2026 06:20
@vercel

vercel Bot commented Aug 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 Aug 10, 2026 6:44am

Request Review

@cursor

cursor Bot commented Aug 10, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Changes touch authentication and account-creation gates (including social OAuth paths) and widespread secret projection refusal in the execution stack—both security-sensitive—with a large diff surface across auth, executor, and email.

Overview
When DISABLE_REGISTRATION is on, the product no longer treats signup as available: social providers get applyRegistrationGate (disableSignUp and disableIdTokenSignIn), login/SSO hide signup links, /signup shows a RegistrationDisabled shell that preserves callbackUrl, invite/CLI auth route existing users to login, and oauth-error explains signup_disabled. Docs clarify that the flag blocks all new accounts (including social) while SSO stays separate.

Auth redirect logic is centralized in resolveAuthRedirect and buildAuthCrossLink (including new=true for invite flows), with server signupSearchParamsCache and tests so login/signup/invite cannot drift on which param wins.

Resolved-secret projection failures now go through refuseResolvedSecretProjection, which logs site, cause, and registry diagnostics once per boundary; ResolvedSecretTraceRegistry retains ordered incompleteness reasons for forks/merges. Agent, memory, mothership, MCP serve, and other handlers adopt this instead of generic throws.

Email sends funnel through render.ts and subjects.ts (OTP and help/contact confirmation subjects, plan welcome helper); new agent inbox reply templates and a boundary test block ad-hoc subjects and direct template imports.

URL/nuqs rules tighten query mutation (use nuqs setters, no fallback={null} on page entries—use route loading.tsx), and files drops the new query param via setFilesParams instead of hand-built router.replace. Several workspace/auth pages swap Suspense fallbacks to real loading chrome; resume and terminal UI derive state instead of mirroring detail in local state.

Reviewed by Cursor Bugbot for commit 5bfcc67. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR consolidates URL state around nuqs, enforces registration-disabled behavior across authentication entry points, centralizes email rendering and subjects, and adds provenance-aware projection-refusal reporting.

  • Preserves authentication and invitation destinations while preventing unavailable account-creation paths.
  • Replaces mirrored component state with derived URL or query-cache state.
  • Routes email senders through shared subject and rendering helpers.
  • Adds consistent logging and refusal behavior when resolved-secret projection is unsafe.
  • Removes the archived image-size dependency.

Confidence Score: 5/5

The PR appears safe to merge because no concrete changed-code failure remains after tracing the affected authentication, projection, email, and state-management paths.

Unsafe provenance projections terminate before reaching response sinks, registration-disabled flows retain valid sign-in destinations, and resume state remains synchronized through explicit query-cache updates.

Important Files Changed

Filename Overview
apps/sim/lib/auth/auth.ts Extends the registration gate across applicable account-creation paths while preserving existing-account and SSO behavior.
apps/sim/app/invite/[id]/invite.tsx Derives invitation URL signals during render and adapts signed-out actions to the registration configuration.
apps/sim/components/emails/render.ts Adds shared rendering for agent inbox responses and a final unsafe-URL neutralization pass.
apps/sim/executor/utils/resolved-secret-projection-refusal.ts Centralizes projection-refusal diagnostics and guarantees termination by throwing.
apps/sim/app/api/mcp/serve/[serverId]/route.ts Replaces generic projection failures with logged, non-returning refusal calls without exposing rejected content.
apps/sim/app/(interfaces)/resume/[workflowId]/[executionId]/resume-page-client.tsx Derives selected pause-point state from query data while synchronously updating the relevant caches after resume.
apps/sim/tools/request-transport.ts Adds stricter model-input projection verification and refuses requests whose projected shape cannot be validated.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  User[User or external caller] --> Auth[Authentication and invitation flows]
  User --> URL[Workspace URL state]
  Workflow[Workflow execution] --> Projection[Resolved-secret projection]
  Projection -->|safe| Output[Projected model or MCP output]
  Projection -->|unsafe| Refusal[Log refusal and throw]
  Agent[Agent or system sender] --> Render[Shared email render layer]
  Render --> Subject[Shared subject helpers]
  Subject --> Mailer[Email delivery]
Loading

Reviews (1): Last reviewed commit: "improvement(url-state): use nuqs setters..." | Re-trigger Greptile

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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 using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 5bfcc67. Configure here.

Comment thread apps/sim/app/invite/[id]/invite.tsx
…6488)

Two gaps left by #6486.

The query was gated on isTokenResolved but the loading state was not. With
enabled: false React Query still reports success when the key already holds
data, so a cached null-token entry made isPending false and rendered the accept
UI for one frame before the effect applied the stored token. Reachable only on a
client-side remount after a tokenless fetch already succeeded.

An empty ?token= also stopped falling back to storage: searchParams.get returns
'' which is not null, so token became '' where the pre-#6486 truthiness check
had read sessionStorage. Normalize to null at the source.
@waleedlatif1
waleedlatif1 merged commit f4cc8d7 into main Aug 10, 2026
54 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.

1 participant