feat(dashboard-api): map Ory SSO organizations to E2B teams - #3094
Conversation
PR SummaryHigh Risk Overview Reviewed by Cursor Bugbot for commit 0ddac04. Bugbot is set up for automated code reviews on this repo. Configure here. |
❌ 5 Tests Failed:
View the top 3 failed test(s) by shortest run time
View the full list of 1 ❄️ flaky test(s)
To view more test analytics, go to the Test Analytics Dashboard |
There was a problem hiding this comment.
Code Review
Performing an external network call to Ory Kratos inside an active database transaction in assignSSOTeams holds database connections and locks open, which can lead to connection pool exhaustion; the SSO organization ID should be fetched before starting the transaction. Additionally, the rejectIfSSOManagedTeam check must be integrated into the member removal handler to prevent manual member deletions on SSO-managed teams.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
1246250 to
783b5b5
Compare
783b5b5 to
ae2460b
Compare
eefc70f to
e3f8297
Compare
e3f8297 to
86cd4ed
Compare
Rebased onto main (#3133 external_id-after-commit) and squashed the SSO work. Enterprise SSO users land in their organization's teams instead of a personal team, with per-team control over automatic vs invite-only access: - teams.sso_organization_id + teams.sso_auto_join columns - bootstrap: SSO identities join their org's auto-join teams (idempotent, never default, no billing). The Kratos org lookup runs before the transaction so it isn't held under the per-user lock, and external_id is backfilled post-commit like main's other paths. Fails closed only when the user would end up with no team at all — a returning member (existing memberships, no default team) is never blocked, even if the org has no auto-join team. - create-team is blocked for SSO users - invites to an SSO team are allowed, but the invitee's Ory identity must belong to the team's organization (compared as UUIDs, not raw strings)
86cd4ed to
71d2e87
Compare
Keep SSO issuer ownership in dashboard-api configuration and fail closed when local Ory identity mappings are ambiguous, while limiting idempotent team membership creation to SSO auto-join.
Inline SSO invite organization validation and fall back to the default events TTL when team limits are unavailable.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0ddac04. Configure here.
🤖 I have created a release *beep* *boop* --- ## 0.0.1 (2026-07-30) ### Features * add workspace admin API foundations ([#3314](#3314)) ([0f72030](0f72030)) * **api:** LD-gated ClickHouse read switcher ([#3061](#3061)) ([29e74ca](29e74ca)) * **api:** soft-delete build layers in DB on user delete ([#3121](#3121)) ([ee88776](ee88776)) * **auth:** support admin token team auth ([#2934](#2934)) ([5496666](5496666)) * **auth:** verifiers on one axis, and a reusable authenticator constructor ([#3423](#3423)) ([923b99b](923b99b)) * **dashboard-api:** add internal admin route for deleting a user ([#2986](#2986)) ([ecc1291](ecc1291)) * **dashboard-api:** add internal team creation ([#2824](#2824)) ([375051b](375051b)) * **dashboard-api:** add OIDC admin user bootstrap endpoint ([#2841](#2841)) ([6a7a59e](6a7a59e)) * **dashboard-api:** add Ory user profile provider and auth middleware fix ([#2840](#2840)) ([30d40d2](30d40d2)) * **dashboard-api:** add template tags handlers ([#2885](#2885)) ([bf52a4b](bf52a4b)) * **dashboard-api:** batch member sync route, and unenumerate project_type ([#3427](#3427)) ([cc16acf](cc16acf)) * **dashboard-api:** expose auth profile admin routes ([#2743](#2743)) ([b673a10](b673a10)) * **dashboard-api:** flag sandboxes past data retention ([#3102](#3102)) ([9b162bf](9b162bf)) * **dashboard-api:** implement upsertProjectLimits ([#3438](#3438)) ([ec1ed29](ec1ed29)) * **dashboard-api:** include build resources in /builds response ([#3009](#3009)) ([bf49c32](bf49c32)) * **dashboard-api:** map Ory SSO organizations to E2B teams ([#3094](#3094)) ([dbd098f](dbd098f)) * **dashboard-api:** populate Ory identity external_id on admin bootstrap ([#3062](#3062)) ([6c51232](6c51232)) * **dashboard-api:** project upsert, member sync and user purge ([#3442](#3442)) ([f997c39](f997c39)) * **dashboard-api:** templates list pagination ([#2904](#2904)) ([6882463](6882463)) * **db:** add project_limits, an override the limits owner can write ([#3429](#3429)) ([021c2a4](021c2a4)) * improve templates list sorting ([#2983](#2983)) ([51ad7ff](51ad7ff)) * **otel:** instrument auth service HTTP client with otelhttp ([#2722](#2722)) ([69b085d](69b085d)) * per-team events TTL limit (tier + addons) ([#3181](#3181)) ([f76b2cb](f76b2cb)) ### Bug Fixes * added api and orch ([#3454](#3454)) ([fda5e45](fda5e45)) * **api:** copy auth/internal into api and dashboard-api image builds ([#3323](#3323)) ([bda1fee](bda1fee)) * **api:** invalidate auth cache on API key deletion ([#3324](#3324)) ([8b02910](8b02910)) * correct 3 CVES ([#3218](#3218)) ([076823b](076823b)) * **dashboard-api:** avoid repeated Ory bootstrap provisioning ([#2940](#2940)) ([da5ce59](da5ce59)) * **dashboard-api:** drop removed read-replica accessor in provisioning tests ([#3340](#3340)) ([6addc91](6addc91)) * **dashboard-api:** pass signup metadata to billing provisioning ([#2978](#2978)) ([d0ea5b4](d0ea5b4)) * **dashboard-api:** set Ory external_id only after the bootstrap commit ([#3133](#3133)) ([00ad04b](00ad04b)) * push client-proxy, dashboard-api, and docker-reverse-proxy image… ([#2953](#2953)) ([1d930ee](1d930ee)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: e2b-release-please[bot] <298072688+e2b-release-please[bot]@users.noreply.github.com> Co-authored-by: Charlie Wyse <charlie.wyse@e2b.dev>
🤖 I have created a release *beep* *boop* --- ## [0.1.0](dashboard-api-v0.0.1...dashboard-api-v0.1.0) (2026-07-31) ### Features * add workspace admin API foundations ([#3314](#3314)) ([0f72030](0f72030)) * **api:** LD-gated ClickHouse read switcher ([#3061](#3061)) ([29e74ca](29e74ca)) * **api:** soft-delete build layers in DB on user delete ([#3121](#3121)) ([ee88776](ee88776)) * **auth:** support admin token team auth ([#2934](#2934)) ([5496666](5496666)) * **auth:** verifiers on one axis, and a reusable authenticator constructor ([#3423](#3423)) ([923b99b](923b99b)) * **dashboard-api:** add internal admin route for deleting a user ([#2986](#2986)) ([ecc1291](ecc1291)) * **dashboard-api:** add internal team creation ([#2824](#2824)) ([375051b](375051b)) * **dashboard-api:** add OIDC admin user bootstrap endpoint ([#2841](#2841)) ([6a7a59e](6a7a59e)) * **dashboard-api:** add Ory user profile provider and auth middleware fix ([#2840](#2840)) ([30d40d2](30d40d2)) * **dashboard-api:** add template tags handlers ([#2885](#2885)) ([bf52a4b](bf52a4b)) * **dashboard-api:** batch member sync route, and unenumerate project_type ([#3427](#3427)) ([cc16acf](cc16acf)) * **dashboard-api:** expose auth profile admin routes ([#2743](#2743)) ([b673a10](b673a10)) * **dashboard-api:** flag sandboxes past data retention ([#3102](#3102)) ([9b162bf](9b162bf)) * **dashboard-api:** implement upsertProjectLimits ([#3438](#3438)) ([ec1ed29](ec1ed29)) * **dashboard-api:** include build resources in /builds response ([#3009](#3009)) ([bf49c32](bf49c32)) * **dashboard-api:** map Ory SSO organizations to E2B teams ([#3094](#3094)) ([dbd098f](dbd098f)) * **dashboard-api:** populate Ory identity external_id on admin bootstrap ([#3062](#3062)) ([6c51232](6c51232)) * **dashboard-api:** project upsert, member sync and user purge ([#3442](#3442)) ([f997c39](f997c39)) * **dashboard-api:** templates list pagination ([#2904](#2904)) ([6882463](6882463)) * **db:** add project_limits, an override the limits owner can write ([#3429](#3429)) ([021c2a4](021c2a4)) * improve templates list sorting ([#2983](#2983)) ([51ad7ff](51ad7ff)) * **otel:** instrument auth service HTTP client with otelhttp ([#2722](#2722)) ([69b085d](69b085d)) * per-team events TTL limit (tier + addons) ([#3181](#3181)) ([f76b2cb](f76b2cb)) ### Bug Fixes * added api and orch ([#3454](#3454)) ([fda5e45](fda5e45)) * **api:** copy auth/internal into api and dashboard-api image builds ([#3323](#3323)) ([bda1fee](bda1fee)) * **api:** invalidate auth cache on API key deletion ([#3324](#3324)) ([8b02910](8b02910)) * correct 3 CVES ([#3218](#3218)) ([076823b](076823b)) * creating whitespace to test publish ([#3476](#3476)) ([5158cc9](5158cc9)) * **dashboard-api:** avoid repeated Ory bootstrap provisioning ([#2940](#2940)) ([da5ce59](da5ce59)) * **dashboard-api:** drop removed read-replica accessor in provisioning tests ([#3340](#3340)) ([6addc91](6addc91)) * **dashboard-api:** pass signup metadata to billing provisioning ([#2978](#2978)) ([d0ea5b4](d0ea5b4)) * **dashboard-api:** set Ory external_id only after the bootstrap commit ([#3133](#3133)) ([00ad04b](00ad04b)) * push client-proxy, dashboard-api, and docker-reverse-proxy image… ([#2953](#2953)) ([1d930ee](1d930ee)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: e2b-release-please[bot] <298072688+e2b-release-please[bot]@users.noreply.github.com>
🤖 I have created a release *beep* *boop* --- ## 0.0.1 (2026-07-30) ### Features * add workspace admin API foundations ([#3314](#3314)) ([0f72030](0f72030)) * **api:** LD-gated ClickHouse read switcher ([#3061](#3061)) ([29e74ca](29e74ca)) * **api:** soft-delete build layers in DB on user delete ([#3121](#3121)) ([ee88776](ee88776)) * **auth:** support admin token team auth ([#2934](#2934)) ([5496666](5496666)) * **auth:** verifiers on one axis, and a reusable authenticator constructor ([#3423](#3423)) ([f68e713](f68e713)) * **dashboard-api:** add internal admin route for deleting a user ([#2986](#2986)) ([ecc1291](ecc1291)) * **dashboard-api:** add internal team creation ([#2824](#2824)) ([375051b](375051b)) * **dashboard-api:** add OIDC admin user bootstrap endpoint ([#2841](#2841)) ([6a7a59e](6a7a59e)) * **dashboard-api:** add Ory user profile provider and auth middleware fix ([#2840](#2840)) ([30d40d2](30d40d2)) * **dashboard-api:** add template tags handlers ([#2885](#2885)) ([bf52a4b](bf52a4b)) * **dashboard-api:** batch member sync route, and unenumerate project_type ([#3427](#3427)) ([6d8dc38](6d8dc38)) * **dashboard-api:** expose auth profile admin routes ([#2743](#2743)) ([b673a10](b673a10)) * **dashboard-api:** flag sandboxes past data retention ([#3102](#3102)) ([9b162bf](9b162bf)) * **dashboard-api:** implement upsertProjectLimits ([#3438](#3438)) ([f4ee390](f4ee390)) * **dashboard-api:** include build resources in /builds response ([#3009](#3009)) ([bf49c32](bf49c32)) * **dashboard-api:** map Ory SSO organizations to E2B teams ([#3094](#3094)) ([dbd098f](dbd098f)) * **dashboard-api:** populate Ory identity external_id on admin bootstrap ([#3062](#3062)) ([6c51232](6c51232)) * **dashboard-api:** project upsert, member sync and user purge ([#3442](#3442)) ([8c90702](8c90702)) * **dashboard-api:** templates list pagination ([#2904](#2904)) ([6882463](6882463)) * **db:** add project_limits, an override the limits owner can write ([#3429](#3429)) ([5ab6259](5ab6259)) * improve templates list sorting ([#2983](#2983)) ([51ad7ff](51ad7ff)) * **otel:** instrument auth service HTTP client with otelhttp ([#2722](#2722)) ([69b085d](69b085d)) * per-team events TTL limit (tier + addons) ([#3181](#3181)) ([f76b2cb](f76b2cb)) ### Bug Fixes * added api and orch ([#3454](#3454)) ([d56e0a8](d56e0a8)) * **api:** copy auth/internal into api and dashboard-api image builds ([#3323](#3323)) ([bda1fee](bda1fee)) * **api:** invalidate auth cache on API key deletion ([#3324](#3324)) ([8b02910](8b02910)) * correct 3 CVES ([#3218](#3218)) ([076823b](076823b)) * **dashboard-api:** avoid repeated Ory bootstrap provisioning ([#2940](#2940)) ([da5ce59](da5ce59)) * **dashboard-api:** drop removed read-replica accessor in provisioning tests ([#3340](#3340)) ([6addc91](6addc91)) * **dashboard-api:** pass signup metadata to billing provisioning ([#2978](#2978)) ([d0ea5b4](d0ea5b4)) * **dashboard-api:** set Ory external_id only after the bootstrap commit ([#3133](#3133)) ([00ad04b](00ad04b)) * push client-proxy, dashboard-api, and docker-reverse-proxy image… ([#2953](#2953)) ([1d930ee](1d930ee)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: e2b-release-please[bot] <298072688+e2b-release-please[bot]@users.noreply.github.com> Co-authored-by: Charlie Wyse <charlie.wyse@e2b.dev>
🤖 I have created a release *beep* *boop* --- ## [0.1.0](dashboard-api-v0.0.1...dashboard-api-v0.1.0) (2026-07-31) ### Features * add workspace admin API foundations ([#3314](#3314)) ([0f72030](0f72030)) * **api:** LD-gated ClickHouse read switcher ([#3061](#3061)) ([29e74ca](29e74ca)) * **api:** soft-delete build layers in DB on user delete ([#3121](#3121)) ([ee88776](ee88776)) * **auth:** support admin token team auth ([#2934](#2934)) ([5496666](5496666)) * **auth:** verifiers on one axis, and a reusable authenticator constructor ([#3423](#3423)) ([f68e713](f68e713)) * **dashboard-api:** add internal admin route for deleting a user ([#2986](#2986)) ([ecc1291](ecc1291)) * **dashboard-api:** add internal team creation ([#2824](#2824)) ([375051b](375051b)) * **dashboard-api:** add OIDC admin user bootstrap endpoint ([#2841](#2841)) ([6a7a59e](6a7a59e)) * **dashboard-api:** add Ory user profile provider and auth middleware fix ([#2840](#2840)) ([30d40d2](30d40d2)) * **dashboard-api:** add template tags handlers ([#2885](#2885)) ([bf52a4b](bf52a4b)) * **dashboard-api:** batch member sync route, and unenumerate project_type ([#3427](#3427)) ([6d8dc38](6d8dc38)) * **dashboard-api:** expose auth profile admin routes ([#2743](#2743)) ([b673a10](b673a10)) * **dashboard-api:** flag sandboxes past data retention ([#3102](#3102)) ([9b162bf](9b162bf)) * **dashboard-api:** implement upsertProjectLimits ([#3438](#3438)) ([f4ee390](f4ee390)) * **dashboard-api:** include build resources in /builds response ([#3009](#3009)) ([bf49c32](bf49c32)) * **dashboard-api:** map Ory SSO organizations to E2B teams ([#3094](#3094)) ([dbd098f](dbd098f)) * **dashboard-api:** populate Ory identity external_id on admin bootstrap ([#3062](#3062)) ([6c51232](6c51232)) * **dashboard-api:** project upsert, member sync and user purge ([#3442](#3442)) ([8c90702](8c90702)) * **dashboard-api:** templates list pagination ([#2904](#2904)) ([6882463](6882463)) * **db:** add project_limits, an override the limits owner can write ([#3429](#3429)) ([5ab6259](5ab6259)) * improve templates list sorting ([#2983](#2983)) ([51ad7ff](51ad7ff)) * **otel:** instrument auth service HTTP client with otelhttp ([#2722](#2722)) ([69b085d](69b085d)) * per-team events TTL limit (tier + addons) ([#3181](#3181)) ([f76b2cb](f76b2cb)) ### Bug Fixes * added api and orch ([#3454](#3454)) ([d56e0a8](d56e0a8)) * **api:** copy auth/internal into api and dashboard-api image builds ([#3323](#3323)) ([bda1fee](bda1fee)) * **api:** invalidate auth cache on API key deletion ([#3324](#3324)) ([8b02910](8b02910)) * correct 3 CVES ([#3218](#3218)) ([076823b](076823b)) * creating whitespace to test publish ([#3476](#3476)) ([6b4177f](6b4177f)) * **dashboard-api:** avoid repeated Ory bootstrap provisioning ([#2940](#2940)) ([da5ce59](da5ce59)) * **dashboard-api:** drop removed read-replica accessor in provisioning tests ([#3340](#3340)) ([6addc91](6addc91)) * **dashboard-api:** pass signup metadata to billing provisioning ([#2978](#2978)) ([d0ea5b4](d0ea5b4)) * **dashboard-api:** set Ory external_id only after the bootstrap commit ([#3133](#3133)) ([00ad04b](00ad04b)) * push client-proxy, dashboard-api, and docker-reverse-proxy image… ([#2953](#2953)) ([1d930ee](1d930ee)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: e2b-release-please[bot] <298072688+e2b-release-please[bot]@users.noreply.github.com>

What
Maps Ory SSO organizations → E2B teams in
dashboard-api. When an enterprise user signs in through their org's SSO connection, Ory stampsidentity.organization_id; on bootstrap we read that server-side and enroll the user into the team(s) mapped to that org instead of creating a personal team. SSO users are blocked from mutating team membership.How it works
teams.ory_organization_id(nullable, non-unique — one org may map to many teams). Set operationally when the enterprise team is provisioned.userprofile.Provider.GetIdentitySSOOrganization/GetUserSSOOrganization.assignSSOTeams): joins every mapped team, earliest-created becomes the default, emits no billing provisioning (SSO teams are provisioned out of band), and fails closed if the org maps to no usable team. Non-SSO identities fall through to the existing personal-team path.ensureNotSSOManaged); SSO-managed teams reject member adds (rejectIfSSOManagedTeam, read from the authenticated team context).CreateTeamMembershipmade idempotent (ON CONFLICT DO NOTHING); sqlc regenerated.Tests
sso_test.go: multi-team join + earliest-default, fail-closed + rollback, create-team blocked, add-member blocked.go build/vet/gofmtclean;go test -shortgreen. DB-backed tests run via testcontainers in CI.Out of scope / follow-ups
teams.ory_organization_id(no admin endpoint in this PR) and applying the migration are operational steps.Notes
Branched from the harness
full-stackpin, which is ~2 commits behindmain; rebase before merge if needed. Pairs with the dashboard PR (UI gating +AuthUser.isSso).🤖 Generated with Claude Code