fix(logs): stop requiring a human subject on actorless runs - #7220
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
Greptile SummaryThe PR separates optional human attribution from authorization for actorless workflow runs while retaining explicit user requirements for person-scoped operations.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| packages/auth/src/principal.ts | Adds optional subject-user resolution and implements the existing required resolver on top of it. |
| apps/sim/lib/logs/fetch-log-detail.ts | Propagates an optional viewer identity through log materialization and child-trace hydration. |
| apps/sim/lib/logs/execution/hydrate-child-traces.ts | Allows actorless child-trace hydration while retaining workspace and publisher-policy checks. |
| apps/sim/lib/mcp/application/authorization.ts | Resolves MCP’s credential user from the verified principal first and otherwise from the trusted execution actor. |
| apps/sim/lib/internal/tool-operations/identity-faults.ts | Centralizes unauthenticated and missing-human-subject error classification for internal tools. |
| scripts/check-actorless-executor-operations.ts | Adds a static audit requiring executor-admitting operations to resolve identity optionally or document why actorless execution is unsupported. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[Workflow trigger] --> B[Verified principal]
B --> C{Human subject present?}
C -->|Yes| D[Use subject for attribution]
C -->|No| E[Continue actorless-capable operation]
E --> F[Authorize from deployment delegation]
E --> G[Use trusted execution actor for MCP]
C -->|Required by operation| H[Return explicit identity-required response]
Reviews (3): Last reviewed commit: "fix(mcp): keep unattended runs connectin..." | Re-trigger Greptile
There was a problem hiding this comment.
All reported issues were addressed across 41 files
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
Scheduled, public-API, and subject-less webhook runs carry no user on their principal. Several use cases resolved one with requirePrincipalSubjectUserId where the user was only attribution, so those runs failed with an opaque 500. Authorization for an actorless caller comes from the workflow running a deployment, never from a userId; each site now treats the user as what it actually is.
TheodoreSpeaks
force-pushed
the
fix/log-regression
branch
from
August 28, 2026 18:35
c950e05 to
07b7a5c
Compare
Collaborator
Author
Restores the identity MCP used before the Logs and MCP tools moved in-process: the executor minted an internal token from ExecutionContext.userId and the MCP route ran as that user, so a schedule, webhook, or public-API run has always reached MCP as the execution actor. Names it for what it is rather than implying it is the workflow's author, and documents that a workspace-level MCP identity is the real fix. Also types the missing-execution-context error so it is answered as unauthenticated rather than falling through to a generic 500.
TheodoreSpeaks
force-pushed
the
fix/log-regression
branch
from
August 28, 2026 18:48
07b7a5c to
3125c1f
Compare
Collaborator
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Scheduled, webhook, and public-API runs are actorless by design — no human behind them. Since #7190,
execution-core.tsonly setsexecutorDelegationOrigin.subjectUserIdwhen the run's principal resolves to asim_user, so the executor delegation for those runs carries no subject. Every use case downstream that calledrequirePrincipalSubjectUserIdthen threwPrincipalSubjectUserRequiredError, which isn't anOrchestrationErrorand surfaced as an opaque 500.The reported symptom was Logs —
logs_get,logs_get_run_details, andlogs_get_executionreturnedFailed to fetch logfor every scheduled run whilelogs_querykept working — but the same break hit several domains at once.Authorization for an actorless caller was never the problem and is unchanged.
workspace-authorization.tsauthorizes those callers on the workflow running a deployment, with no userId involved; that's exactly why the query tools kept working. What broke was code treating the userId as required when it was doing something else entirely. Each site now treats it as what it actually is:read-log-detail,read-execution-snapshotLargeValueStoreContext.userIdis already optional and unread.viewerUserIdoptional throughfetch-log-detailandhydrate-child-tracesrows.tstables-v2-apifeature-flag dimensionfalsewith no query, so the gate only ever narrowscreate-invite-linkcreated_by, a nullableon delete set nullcolumnsend-invitereuses the subject its own guard already resolvedexecute-tool,use-casesMCP
This one is a real identity, so it preserves what was already happening rather than changing it. Before these tools moved in-process, the executor minted an internal token from
ExecutionContext.userIdand the MCP route ran as that user; the intermediate version passed the same value assubjectUserId. An unattended run has therefore always reached MCP as the execution actor.That value is now passed explicitly as
executionActorUserIdinstead of arriving implicitly, and is documented for what it is: for a schedule, webhook, or anonymous public-API run the actor is the workspace system actor resolved during preprocessing — the billing payer, not the workflow's author. A principal that names its own subject always wins, so this can't be used to nominate someone else's credentials, and it is not an authorization input.An
external_userwebhook subject falls back too, deliberately: it is a real identity but never a Sim user, so it has no Sim credentials of its own, and those runs have always connected as the actor. Refusing them would break working workflows over a boundary the old path never drew.Supporting changes
@sim/authgainsresolvePrincipalSubjectUserId, withrequirePrincipalSubjectUserIdreimplemented on top. Theresolve/requirepair makes the choice visible at each call site — pickingrequirewhereresolvewas correct is what caused this.identity-faults.tscentralizes the identity-error classification that was copy-pasted across 8 internal tool handlers:PrincipalSubjectUserRequiredError→ 403 naming the cause, and a now-typedExecutorDelegationOriginRequiredError→ 401 (it was a bareError, so a request with no execution context fell through to a generic 500). Each handler keeps its own response envelope.check:actorless-executor-operationsaudit keeps this class visible instead of waiting on a canary: it resolves operation policies through spreads and same-file factories, fails closed forlib/internal/**and for shared use-case factories in executor-admitting domains, and requires// actorless-unsupported: <reason>on the 14 sites where a person genuinely is required.Known gap / follow-ups
authType === 'oauth'servers.headers(the DB default) andnoneneed no person unless the config references a personal env var, andresolveMcpConfigEnvVarsruns withstrict: trueso a missing var throws rather than silently sending an empty header.Type of Change
Testing
Tested manually.
bun run type-check,bun run lint:check,check-block-registry, andbun run check:audits(39/39, including the new audit) all pass. 434 test files / 4807 tests pass across logs, mcp, credential-groups, tables, internal, and auth.New regression coverage: the actorless path at the
readLogDetailUseCaseboundary (exercising the real authorization path, not a stub), inhydrateChildTraces, inreadLogDetail, for an unattended run and an external-subject webhook reaching MCP as the execution actor, for an authenticated subject taking precedence over it, for the 403 and 401 identity-fault mappings, and fixture-driven tests for the new audit script.Checklist