fix(decopilot): resolve model permissions off the target org's role in dispatch-run#4947
Merged
pedrofrxncx merged 1 commit intoJul 21, 2026
Conversation
…n dispatch-run Follows #4943/#4944 hardening. `fetchModelPermissions` in dispatchRunAndWait's resume/automation re-entry path used `ctx.auth.user?.role` (the session's active-org role) instead of the path-resolved role for `input.organizationId`, letting an owner/admin of one org bypass model-tier restrictions when a dispatch targets a different, lower-privileged org. #4944 already fixed the same fetchModelPermissions call in routes.ts/key-list.ts/list-models.ts but missed this call site.
pedrofrxncx
deleted the
fix/dispatch-run-model-permissions-active-org-role-w1
branch
July 21, 2026 17:34
This was referenced Jul 21, 2026
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.
Follows #4943 (org-SSO gate fix) and the just-opened #4944 (model-permissions active-org-role fix in routes.ts/key-list.ts/list-models.ts) — same bug class, a call site those PRs missed.
dispatchRunAndWait's model-permission check (inapps/mesh/src/api/routes/decopilot/dispatch-run.ts) callsfetchModelPermissions(ctx.db, input.organizationId, ctx.auth.user?.role).ctx.auth.user?.rolereflects the session's ACTIVE org, notinput.organizationId(the dispatch target) — the code comment right above it even says this is the resume/automation re-entry path that bypasses the HTTP-layer gate in routes.ts. An owner/admin of one org whose active session role isowner/admincould dispatch a run against a different org where they hold only a lower-privileged custom role, andfetchModelPermissionswould treat them as admin (bypassing the role's model-tier restrictions) for that other org's models.Fix: read
ctx.organization?.role ?? ctx.auth.user?.roleinstead —ctx.organization.roleis the path-resolved role for the target org (set byresolveOrgFromPathfor HTTP-originated calls); for background automation contexts (automationContextFactory)ctx.organization.roleis unset butctx.auth.user.roleis already correctly scoped toinput.organizationIdthere, so the fallback preserves existing behavior. This mirrors the exact fix already applied toroutes.ts/key-list.ts/list-models.tsin #4944.No test added — the underlying
fetchModelPermissionslogic already has unit coverage (model-permissions.test.ts); this is a one-line call-site correction, same precedent as #4944 (which also shipped without a new test sincedispatchRunAndWaitrequires heavy StudioContext mocking to invoke directly).To verify:
cd apps/mesh && bunx tsc --noEmit(clean) and read the diff againstapps/mesh/src/api/routes/decopilot/routes.ts's equivalent fix in #4944 to confirm the same pattern is applied correctly.Locally ran:
bun run fmtandbunx tsc --noEmitinapps/mesh(both clean). Full CI validates the rest.Summary by cubic
Fixes a permission gap in Decopilot dispatch-run by resolving model permissions using the target org’s role. This prevents cross-org privilege escalation when the active session org differs from the dispatch target.
dispatchRunAndWaitwithctx.organization?.role ?? ctx.auth.user?.rolewhen callingfetchModelPermissions.ctx.auth.user.roleifctx.organization.roleis unset.Written for commit 929ad80. Summary will update on new commits.