feat(api): gate access token issuance behind feature flag - #3101
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a feature flag to disable the creation of new access tokens, updating the API handler, OpenAPI specification, and tests accordingly. I have no feedback to provide.
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.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
There was a problem hiding this comment.
LGTM — small, default-off feature-flag gate with a unit test.
Extended reasoning...
Overview
The PR adds a new DisableAccessTokenIssuanceFlag (bool, default false) in packages/shared/pkg/featureflags/flags.go, gates the top of PostAccessTokens to return 403 with a migration hint when enabled, marks POST /access-tokens as deprecated: true in spec/openapi.yml and adds the 403 response. The two generated client files (api.gen.go and integration test generated.go) are mechanical regenerations from the spec, and a focused unit test verifies the 403 path via the LaunchDarkly test datasource.
Security risks
None introduced. This is a fail-closed gate that reduces the surface for new access token issuance; it does not touch the authenticator that validates existing tokens (that's an explicitly separate Aug 1 step per the PR description). The flag defaults to off, preserving current behavior, and the error message points to the migration path without leaking sensitive state.
Level of scrutiny
Low. This is a feature-flag-gated deprecation gate, default-off, behind LaunchDarkly with per-user context, fully reversible. The handler change is 5 lines; the rest is generated code and OpenAPI metadata. The unit test exercises the new branch correctly using ldtestdata.
Other factors
The 7 failing tests in CI (envd 502s on TestListDir, template build cancellation in TestTemplateBuildRUN) are clearly unrelated infrastructure flakes — none touch access token code. No bugs were found by the hunting system. The pattern matches existing bool flags in the same file and the existing feature-flag idiom across the codebase.
Regenerated api.gen.go + integration client from the merged spec (resolves generated-file conflict; combines #3109 with the 410 change).
🤖 I have created a release *beep* *boop* --- ## 0.0.1 (2026-07-30) ### Features * add workspace admin API foundations ([#3314](#3314)) ([0f72030](0f72030)) * **api:** add admin team API key routes ([#2825](#2825)) ([4a1e083](4a1e083)) * **api:** add feature flag to stop accepting E2B access tokens ([#3240](#3240)) ([2cf489b](2cf489b)) * **api:** add sandbox fork endpoint ([#3202](#3202)) ([643d726](643d726)) * **api:** add sandbox IAM workload token configuration ([13ddb3d](13ddb3d)) * **api:** add sandbox workload identity permission ([#3319](#3319)) ([13ddb3d](13ddb3d)) * **api:** add user agent integration attribution to PostHog events ([#3303](#3303)) ([d83be18](d83be18)) * **api:** discover orchestrators via nomad service ([#3176](#3176)) ([32af250](32af250)) * **api:** e2b access token deprecation feature flag rename ([#3110](#3110)) ([ebc2daa](ebc2daa)) * **api:** enforce blocked-team restrictions at mutating API endpoints ([#2659](#2659)) ([db848ab](db848ab)) * **api:** filter snapshots by name ([#3184](#3184)) ([6fa1bc7](6fa1bc7)) * **api:** gate access token issuance behind feature flag ([#3101](#3101)) ([2f7811e](2f7811e)) * **api:** LD-gated ClickHouse read switcher ([#3061](#3061)) ([29e74ca](29e74ca)) * **api:** limit template build name to 128 characters ([#3109](#3109)) ([84aa186](84aa186)) * **api:** paginated GET /v2/templates (EN-603) ([#3059](#3059)) ([91e02e4](91e02e4)) * **api:** per-region volume type defaults from node-derived region ([#3435](#3435)) ([baf5559](baf5559)) * **api:** pin resume retries to the node a previous resume timed out on ([#3066](#3066)) ([a4fd0f2](a4fd0f2)) * **api:** SOCKS5 egress proxy on sandbox network config (BYOP) ([#2642](#2642)) ([1fc3820](1fc3820)) * **api:** soft-delete build layers in DB on user delete ([#3121](#3121)) ([ee88776](ee88776)) * **auth:** support admin token team auth ([#2934](#2934)) ([5496666](5496666)) * dynamic sandbox log routing and ClickHouse-backed log reads ([#3236](#3236)) ([1b19a3b](1b19a3b)) * **evictor:** make max concurrent evictions a feature flag ([#2727](#2727)) ([0b33013](0b33013)) * **metrics:** distinguish joined from regular requests (ENG-4072) ([#2699](#2699)) ([390e296](390e296)) * **observability:** add kill_reason to sandbox.lifecycle.killed ([#2833](#2833)) ([e45418f](e45418f)) * **observability:** include kill_reason in kill-path structured logs ([#2846](#2846)) ([33c49f7](33c49f7)) * **orchestrator:** add dummy orchestrator binary for local API dev ([#2744](#2744)) ([ab56e25](ab56e25)) * **orchestrator:** report hugepage metrics to API ([#3182](#3182)) ([7735bae](7735bae)) * **orchestrator:** track and report last status change timestamp ([#2980](#2980)) ([f79be77](f79be77)) * **otel:** instrument auth service HTTP client with otelhttp ([#2722](#2722)) ([69b085d](69b085d)) * per-team events TTL limit (tier + addons) ([#3181](#3181)) ([f76b2cb](f76b2cb)) * **storage:** stamp provenance custom metadata on uploaded objects (incl. headers) ([#3033](#3033)) ([ba8604e](ba8604e)) ### Bug Fixes * added api and orch ([#3454](#3454)) ([fda5e45](fda5e45)) * **api:** check template alias tags in exists endpoint ([#2916](#2916)) ([9574cdf](9574cdf)) * **api:** copy auth/internal into api and dashboard-api image builds ([#3323](#3323)) ([bda1fee](bda1fee)) * **api:** discover the local orchestrator as a template builder ([#3386](#3386)) ([9ea005a](9ea005a)) * **api:** expose pagination headers via CORS ([#3388](#3388)) ([e832b1e](e832b1e)) * **api:** handle corrupted data in sandbox stop time ([#3203](#3203)) ([a98a178](a98a178)) * **api:** include exhaustion reason in "Node exhausted" placement warning ([#3279](#3279)) ([eb3797b](eb3797b)) * **api:** invalidate auth cache on API key deletion ([#3324](#3324)) ([8b02910](8b02910)) * **api:** keep API alive until in-flight requests finish ([#2708](#2708)) ([06378c7](06378c7)) * **api:** let the analytics collector address carry a port ([#3394](#3394)) ([6d41cb5](6d41cb5)) * **api:** parse the pause body regardless of Content-Length ([#3056](#3056)) ([d66aab8](d66aab8)) * **api:** prevent uint64 underflow in node allocated metrics ([#3216](#3216)) ([fed38e1](fed38e1)) * **api:** push api and db-migrator images to both latest and commit S… ([#2951](#2951)) ([6f010fc](6f010fc)) * **api:** reject non-positive timeout on sandbox create, resume, and fork ([#3419](#3419)) ([b672bd1](b672bd1)) * **api:** report invalid tag errors as bad requests ([#2799](#2799)) ([10085a1](10085a1)) * **api:** stop evicting the local node during sync ([#2881](#2881)) ([5455905](5455905)) * **api:** use correct error variable in processCustomErrors ([#3135](#3135)) ([a131a00](a131a00)) * **auth:** rename X-Team-Id header to X-Team-ID ([#2723](#2723)) ([f92ecc0](f92ecc0)) * correct 3 CVES ([#3218](#3218)) ([076823b](076823b)) * **orchestrator:** reject standby while draining ([#3325](#3325)) ([475a7ee](475a7ee)) * Support snapshots for non-default clusters ([#2947](#2947)) ([28eeb72](28eeb72)) ### Performance Improvements * **api:** wake reservation waiters via pub/sub instead of 20ms polling [ENG-4070] ([#2729](#2729)) ([2944d06](2944d06)) --- 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:** add admin team API key routes ([#2825](#2825)) ([4a1e083](4a1e083)) * **api:** add feature flag to stop accepting E2B access tokens ([#3240](#3240)) ([2cf489b](2cf489b)) * **api:** add sandbox fork endpoint ([#3202](#3202)) ([643d726](643d726)) * **api:** add sandbox IAM workload token configuration ([13ddb3d](13ddb3d)) * **api:** add sandbox workload identity permission ([#3319](#3319)) ([13ddb3d](13ddb3d)) * **api:** add user agent integration attribution to PostHog events ([#3303](#3303)) ([d83be18](d83be18)) * **api:** discover orchestrators via nomad service ([#3176](#3176)) ([32af250](32af250)) * **api:** e2b access token deprecation feature flag rename ([#3110](#3110)) ([ebc2daa](ebc2daa)) * **api:** enforce blocked-team restrictions at mutating API endpoints ([#2659](#2659)) ([db848ab](db848ab)) * **api:** filter snapshots by name ([#3184](#3184)) ([6fa1bc7](6fa1bc7)) * **api:** gate access token issuance behind feature flag ([#3101](#3101)) ([2f7811e](2f7811e)) * **api:** LD-gated ClickHouse read switcher ([#3061](#3061)) ([29e74ca](29e74ca)) * **api:** limit template build name to 128 characters ([#3109](#3109)) ([84aa186](84aa186)) * **api:** paginated GET /v2/templates (EN-603) ([#3059](#3059)) ([91e02e4](91e02e4)) * **api:** per-region volume type defaults from node-derived region ([#3435](#3435)) ([1bded44](1bded44)) * **api:** pin resume retries to the node a previous resume timed out on ([#3066](#3066)) ([a4fd0f2](a4fd0f2)) * **api:** SOCKS5 egress proxy on sandbox network config (BYOP) ([#2642](#2642)) ([1fc3820](1fc3820)) * **api:** soft-delete build layers in DB on user delete ([#3121](#3121)) ([ee88776](ee88776)) * **auth:** support admin token team auth ([#2934](#2934)) ([5496666](5496666)) * dynamic sandbox log routing and ClickHouse-backed log reads ([#3236](#3236)) ([1b19a3b](1b19a3b)) * **evictor:** make max concurrent evictions a feature flag ([#2727](#2727)) ([0b33013](0b33013)) * **metrics:** distinguish joined from regular requests (ENG-4072) ([#2699](#2699)) ([390e296](390e296)) * **observability:** add kill_reason to sandbox.lifecycle.killed ([#2833](#2833)) ([e45418f](e45418f)) * **observability:** include kill_reason in kill-path structured logs ([#2846](#2846)) ([33c49f7](33c49f7)) * **orchestrator:** add dummy orchestrator binary for local API dev ([#2744](#2744)) ([ab56e25](ab56e25)) * **orchestrator:** report hugepage metrics to API ([#3182](#3182)) ([7735bae](7735bae)) * **orchestrator:** track and report last status change timestamp ([#2980](#2980)) ([f79be77](f79be77)) * **otel:** instrument auth service HTTP client with otelhttp ([#2722](#2722)) ([69b085d](69b085d)) * per-team events TTL limit (tier + addons) ([#3181](#3181)) ([f76b2cb](f76b2cb)) * **storage:** stamp provenance custom metadata on uploaded objects (incl. headers) ([#3033](#3033)) ([ba8604e](ba8604e)) ### Bug Fixes * added api and orch ([#3454](#3454)) ([d56e0a8](d56e0a8)) * **api:** check template alias tags in exists endpoint ([#2916](#2916)) ([9574cdf](9574cdf)) * **api:** copy auth/internal into api and dashboard-api image builds ([#3323](#3323)) ([bda1fee](bda1fee)) * **api:** discover the local orchestrator as a template builder ([#3386](#3386)) ([9ea005a](9ea005a)) * **api:** expose pagination headers via CORS ([#3388](#3388)) ([e832b1e](e832b1e)) * **api:** handle corrupted data in sandbox stop time ([#3203](#3203)) ([a98a178](a98a178)) * **api:** include exhaustion reason in "Node exhausted" placement warning ([#3279](#3279)) ([eb3797b](eb3797b)) * **api:** invalidate auth cache on API key deletion ([#3324](#3324)) ([8b02910](8b02910)) * **api:** keep API alive until in-flight requests finish ([#2708](#2708)) ([06378c7](06378c7)) * **api:** let the analytics collector address carry a port ([#3394](#3394)) ([6d41cb5](6d41cb5)) * **api:** parse the pause body regardless of Content-Length ([#3056](#3056)) ([d66aab8](d66aab8)) * **api:** prevent uint64 underflow in node allocated metrics ([#3216](#3216)) ([fed38e1](fed38e1)) * **api:** push api and db-migrator images to both latest and commit S… ([#2951](#2951)) ([6f010fc](6f010fc)) * **api:** reject non-positive timeout on sandbox create, resume, and fork ([#3419](#3419)) ([5a4b631](5a4b631)) * **api:** report invalid tag errors as bad requests ([#2799](#2799)) ([10085a1](10085a1)) * **api:** stop evicting the local node during sync ([#2881](#2881)) ([5455905](5455905)) * **api:** use correct error variable in processCustomErrors ([#3135](#3135)) ([a131a00](a131a00)) * **auth:** rename X-Team-Id header to X-Team-ID ([#2723](#2723)) ([f92ecc0](f92ecc0)) * correct 3 CVES ([#3218](#3218)) ([076823b](076823b)) * **orchestrator:** reject standby while draining ([#3325](#3325)) ([475a7ee](475a7ee)) * Support snapshots for non-default clusters ([#2947](#2947)) ([28eeb72](28eeb72)) ### Performance Improvements * **api:** wake reservation waiters via pub/sub instead of 20ms polling [ENG-4070] ([#2729](#2729)) ([2944d06](2944d06)) --- 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
Adds a feature flag that lets us stop issuing new E2B access tokens (
sk_e2b_) viaPOST /access-tokens. Whendisable-access-token-issuanceis on, the endpoint returns 403 with a message pointing users toE2B_API_KEY+ the migration guide, before any token is generated.Why
Backend half of EN-1110.
E2B_ACCESS_TOKENis deprecated in favor ofE2B_API_KEY; the CLI now authenticates via Hydra JWTs (EN-1106/1107/1108), so issuance can be turned offChanges
Scope / blast radius