Scoped PAT: add api_gateway_keys_secret_read and data_api_config_secret_read permissions (#50134)

## What kind of change does this PR introduce?

Surface the new scoped personal access token permissions published in
`@supabase/shared-types` 0.1.95 (added by
https://github.com/supabase/platform/pull/38060, now deployed).

**Stacked on #50234**, which regenerates the Management API types so
Studio's scope type includes the new ids. This PR targets that branch
and will retarget to `master` when it merges.

## What's in here

- Bump `@supabase/shared-types` to 0.1.95 (Studio and shared-data).
- Catalog entries in
`packages/shared-data/scoped-access-token-permissions.ts`:
- **API Key Secrets** (`api_gateway_keys_secret_read`): gates
`?reveal=true` on the API keys endpoints. Renamed from "JWT secret",
which described the wrong thing.
- **Data API JWT Secret** (`data_api_config_secret_read`): gates the
`jwt_secret` field on the PostgREST config endpoint.
- **Compute** (`workers_read` / `workers_write`): shared-types 0.1.95
also publishes the workers scopes, so they surface in the catalog now.
Named to match Studio's product naming (#50208).
- Minimum roles for the four new ids in `FGA_SCOPE_MINIMUM_ROLE`,
transcribed from the OpenFGA model (secret reads: developer; workers
read: readonly; workers write: developer).
- Docs generator (`generateAccessControlPartials.mts`):
  - Drop the workers exclusion now that the scopes are live.
- When an endpoint lists alternative permission sets (for example API
keys read alone, or read plus secret read for reveal), a row's footnote
now only considers the alternatives that include that row's own scope.
Previously the API Key Secrets row would have said "Requires API Keys
(Read), or API Keys (Read) and API Key Secrets (Read)".
- Regenerated PAT guide tables. The committed Management API specs
predate the secret scopes, so this also includes the same spec refresh
the weekly docs bot performs (`chore(docs): refresh the Management API
specs`, kept as its own commit). Besides the new rows it picks up two
new upstream endpoints under Advisors and the branch rows.

## Verified

- `pnpm --filter studio typecheck` clean on top of #50234.
- Access token test suite passes, including the guard that the role
table covers exactly the ids shared-types publishes.
- Partial regeneration is idempotent, so the Docs Tests stale-table gate
passes.

## Follow-ups (not in this PR)

- `apps/docs/content/guides/getting-started/api-keys.mdx` says a
fine-grained token needs `api_gateway_keys_read` for the `?reveal=true`
example. It now also needs `api_gateway_keys_secret_read`.
- `project:api_gateway_keys` still says "Read exposes API keys" in its
risk reason, which overstates it now that secret values sit behind a
separate scope. Rewording may mean revisiting its risk level.
- The comment in `ComputeLayout.tsx` about shared-types not exposing
`workers_read` is stale.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added permission support for API key secrets, Data API JWT secrets,
and compute workers.
  * Added API endpoints to run project advisors and create branches.
* Added support for additional log-drain destinations, including S3,
Last9, and OTLP.
* Added storage object versioning information to project configuration
responses.
* **Documentation**
* Updated access-control documentation for new permissions, worker
operations, advisor runs, and branch creation.
  * Clarified Data API configuration and secret descriptions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
This commit is contained in:
Gildas GarciaandAlaister Young authored and GitHub committed 2026-09-11 13:31:21 +08:00
1 parent 737b8595f2
commit 9b1dddde11
12 files changed
+2771 -1110

No files matched your search

@@ -33,6 +33,7 @@
| | Read-write | [Update action run status](/docs/reference/api/v1-update-action-run-status) |
| Advisors | Read | [Get performance advisors](/docs/reference/api/v1-get-performance-advisors) |
| | | [Get security advisors](/docs/reference/api/v1-get-security-advisors) |
| | | [Run project advisors](/docs/reference/api/v2-run-project-advisors) |
| Analytics Config | Read | [List log drains](/docs/reference/api/v2-list-log-drains) |
| | Read-write | [Create log drain](/docs/reference/api/v2-create-log-drain) |
| | | [Delete log drain](/docs/reference/api/v2-delete-log-drain) |
@@ -111,6 +112,8 @@
| | | [Delete project API key](/docs/reference/api/v1-delete-project-api-key) |
| | | [Update project API key](/docs/reference/api/v1-update-project-api-key) |
| | | [Update project legacy API keys](/docs/reference/api/v1-update-project-legacy-api-keys) |
| API Key Secrets | Read | [Get project API key](/docs/reference/api/v1-get-project-api-key)[^6] |
| | | [Get project API keys](/docs/reference/api/v1-get-project-api-keys)[^6] |
| Auth Config | Read | [Get a SSO provider](/docs/reference/api/v1-get-a-sso-provider) |
| | | [Get auth service config](/docs/reference/api/v1-get-auth-service-config) |
| | | [Get project config](/docs/reference/api/v2-get-project-config)[^5] |
@@ -133,6 +136,7 @@
| Data API Config | Read | [Get PostgREST service config](/docs/reference/api/v1-get-postgrest-service-config) |
| | | [Get project config](/docs/reference/api/v2-get-project-config)[^5] |
| | Read-write | [Update PostgREST service config](/docs/reference/api/v1-update-postgrest-service-config) |
| Data API JWT Secret | Read | [Get PostgREST service config](/docs/reference/api/v1-get-postgrest-service-config)[^7] |
| Edge Functions | Read | [Get a function](/docs/reference/api/v1-get-a-function) |
| | | [Get a function body](/docs/reference/api/v1-get-a-function-body) |
| | | [List all functions](/docs/reference/api/v1-list-all-functions) |
@@ -152,11 +156,17 @@
| Storage Config | Read | [Get project config](/docs/reference/api/v2-get-project-config)[^5] |
| | | [Get storage config](/docs/reference/api/v1-get-storage-config) |
| | Read-write | [Update storage config](/docs/reference/api/v1-update-storage-config) |
| Compute | Read | [Get a worker](/docs/reference/api/v2-get-a-worker) |
| | | [List all workers](/docs/reference/api/v2-list-all-workers) |
| | Read-write | [Create worker upload](/docs/reference/api/v2-create-worker-upload) |
| | | [Delete a worker](/docs/reference/api/v2-delete-a-worker) |
| | | [Deploy a worker](/docs/reference/api/v2-deploy-a-worker) |
| **Infrastructure and delivery** | | |
| Development Branches | Read | [Get a branch](/docs/reference/api/v1-get-a-branch) |
| | | [Get a branch config](/docs/reference/api/v1-get-a-branch-config) |
| | | [List all branches](/docs/reference/api/v1-list-all-branches) |
| | Read-write | [Create a branch](/docs/reference/api/v1-create-a-branch) |
| | | [Create a branch](/docs/reference/api/v2-create-a-branch) |
| | | [Delete a branch](/docs/reference/api/v1-delete-a-branch) |
| | | [Diff a branch](/docs/reference/api/v1-diff-a-branch) |
| | | [Merge a branch](/docs/reference/api/v1-merge-a-branch) |
@@ -168,6 +178,7 @@
| | | [Get a branch config](/docs/reference/api/v1-get-a-branch-config) |
| | | [List all branches](/docs/reference/api/v1-list-all-branches) |
| | Read-write | [Create a branch](/docs/reference/api/v1-create-a-branch) |
| | | [Create a branch](/docs/reference/api/v2-create-a-branch) |
| | | [Delete a branch](/docs/reference/api/v1-delete-a-branch) |
| | | [Diff a branch](/docs/reference/api/v1-diff-a-branch) |
| | | [Disable preview branching](/docs/reference/api/v1-disable-preview-branching) |
@@ -234,3 +245,7 @@
[^4]: Requires **Project Settings** (Read-write) and **Database** (Read-write).
[^5]: Requires **Database Config** (Read), **Database** (Read), **SSL Enforcement** (Read), **Network Restrictions** (Read), **Auth Config** (Read), **Data API Config** (Read), **Realtime Config** (Read), and **Storage Config** (Read).
[^6]: Requires **API Keys** (Read) and **API Key Secrets** (Read).
[^7]: Requires **Data API Config** (Read) and **Data API JWT Secret** (Read).
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+12
View File
@@ -21,6 +21,12 @@
"title": "Get security advisors",
"slug": "v1-get-security-advisors",
"type": "operation"
},
{
"id": "v2-run-project-advisors",
"title": "Run project advisors",
"slug": "v2-run-project-advisors",
"type": "operation"
}
]
},
@@ -610,6 +616,12 @@
"slug": "v1-create-a-branch",
"type": "operation"
},
{
"id": "v2-create-a-branch",
"title": "Create a branch",
"slug": "v2-create-a-branch",
"type": "operation"
},
{
"id": "v1-delete-a-branch",
"title": "Delete a branch",
@@ -89,9 +89,6 @@ const permissionRows: PermissionRow[] = PERMISSION_CATALOG_BY_CATEGORY.flatMap((
const rowByScope = new Map(permissionRows.flatMap((row) => row.scopes.map((scope) => [scope, row])))
// Workers permissions are present in the API spec but are not live for scoped PATs yet.
const EXCLUDED_SCOPES = new Set(['workers_read', 'workers_write'])
// The public v2 webhook operations currently omit x-fga-permissions from the OpenAPI projection.
// Keep this fallback narrow so the generated table can still link those endpoints, and fail below
// if any other public operation has not been classified for the scoped-PAT table.
@@ -136,7 +133,6 @@ function webhookPermissionGroups(
function knownGroups(groups: ScopeGroupAlternatives, missing: Set<string>) {
return groups.filter((group) => {
if (group.some((scope) => EXCLUDED_SCOPES.has(scope))) return false
const unknown = group.filter((scope) => !rowByScope.has(scope))
unknown.forEach((scope) => missing.add(scope))
return unknown.length === 0
@@ -265,12 +261,19 @@ function generatePermissionsPartial(specPaths: string[], tools: McpMap, outputPa
const link = /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(endpoint.operationId)
? `[${label}](/docs/reference/api/${endpoint.operationId})`
: label
const unlocksAlone = endpoint.groups.some((group) =>
// An endpoint can list alternative permission sets (e.g. reading API keys needs
// `api_gateway_keys_read`, and revealing their secret values needs that plus
// `api_gateway_keys_secret_read`). Only the alternatives that include this row's own scope
// say anything about this row, so the footnote ignores the rest.
const relevantGroups = endpoint.groups.filter((group) =>
group.some((scope) => rowScopes.has(scope))
)
const unlocksAlone = relevantGroups.some((group) =>
group.every((scope) => rowScopes.has(scope))
)
let requirement = ''
if (!unlocksAlone) {
const text = `Requires ${formatRequirement(endpoint.groups)}.`
const text = `Requires ${formatRequirement(relevantGroups)}.`
const id = footnotes.get(text) ?? String(footnotes.size + 1)
footnotes.set(text, id)
requirement = `[^${id}]`
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -95,6 +95,7 @@ export const FGA_SCOPE_MINIMUM_ROLE: Record<string, TokenRoleLevel> = {
analytics_logs_read: 'readonly',
analytics_usage_read: 'readonly',
api_gateway_keys_read: 'developer',
api_gateway_keys_secret_read: 'developer',
api_gateway_keys_write: 'administrator',
auth_config_read: 'readonly',
auth_config_write: 'developer',
@@ -113,6 +114,7 @@ export const FGA_SCOPE_MINIMUM_ROLE: Record<string, TokenRoleLevel> = {
custom_domain_read: 'readonly',
custom_domain_write: 'administrator',
data_api_config_read: 'readonly',
data_api_config_secret_read: 'developer',
data_api_config_write: 'administrator',
database_read: 'readonly',
database_write: 'developer',
@@ -156,6 +158,8 @@ export const FGA_SCOPE_MINIMUM_ROLE: Record<string, TokenRoleLevel> = {
vanity_subdomain_write: 'administrator',
platform_webhooks_projects_read: 'member',
platform_webhooks_projects_write: 'administrator',
workers_read: 'readonly',
workers_write: 'developer',
}
/**
+1 -1
View File
@@ -73,7 +73,7 @@
"@supabase/mcp-server-supabase": "^0.12.0",
"@supabase/pg-meta": "workspace:*",
"@supabase/realtime-js": "catalog:",
"@supabase/shared-types": "0.1.91",
"@supabase/shared-types": "0.1.95",
"@supabase/supabase-js": "catalog:",
"@tanstack/react-devtools": "^0.10.3",
"@tanstack/react-hotkeys": "^0.10.0",
+1 -1
View File
@@ -15,7 +15,7 @@
"author": "",
"license": "MIT",
"dependencies": {
"@supabase/shared-types": "0.1.91",
"@supabase/shared-types": "0.1.95",
"zod": "catalog:"
}
}
@@ -364,6 +364,14 @@ const RESOURCE_METADATA: Record<string, ResourceMeta> = {
allowsRead: ['Read project API keys'],
allowsWrite: ['Create and revoke API keys'],
},
'project:api_gateway_keys_secret': {
category: 'appsvc',
name: 'API Key Secrets',
description: 'Secret values of project API keys.',
risk: 'high',
riskReason: 'Read reveals the secret values of project API keys.',
allowsRead: ['Reveal project API key secrets'],
},
'project:edge_functions': {
category: 'appsvc',
name: 'Edge Functions',
@@ -382,6 +390,15 @@ const RESOURCE_METADATA: Record<string, ResourceMeta> = {
allowsRead: ['Read edge function secrets'],
allowsWrite: ['Set edge function secrets'],
},
'project:workers': {
category: 'appsvc',
name: 'Compute',
description: 'Compute workers deployed to the project.',
risk: 'medium',
riskReason: 'Read-write can deploy or delete compute workers.',
allowsRead: ['List compute workers'],
allowsWrite: ['Deploy and delete compute workers'],
},
'project:realtime_config': {
category: 'appsvc',
name: 'Realtime Config',
@@ -412,12 +429,20 @@ const RESOURCE_METADATA: Record<string, ResourceMeta> = {
'project:data_api_config': {
category: 'appsvc',
name: 'Data API Config',
description: 'PostgREST behavior and settings.',
description: 'Data API behavior and settings.',
risk: 'medium',
riskReason: 'Read-write can change how the auto-generated Data API behaves.',
allowsRead: ['Read Data API configuration'],
allowsWrite: ['Update Data API configuration'],
},
'project:data_api_config_secret': {
category: 'appsvc',
name: 'Data API JWT Secret',
description: 'JWT secret used by the Data API.',
risk: 'high',
riskReason: 'Read exposes the JWT secret, which can be used to mint tokens for any role.',
allowsRead: ['Read Data API JWT secret'],
},
// --- Infrastructure and delivery ---
'project:branching_development': {
+7 -7
View File
@@ -1051,8 +1051,8 @@ importers:
specifier: 'catalog:'
version: 2.112.4
'@supabase/shared-types':
specifier: 0.1.91
version: 0.1.91
specifier: 0.1.95
version: 0.1.95
'@supabase/supabase-js':
specifier: 'catalog:'
version: 2.112.4(@opentelemetry/api@1.9.1)
@@ -2614,8 +2614,8 @@ importers:
packages/shared-data:
dependencies:
'@supabase/shared-types':
specifier: 0.1.91
version: 0.1.91
specifier: 0.1.95
version: 0.1.95
zod:
specifier: 'catalog:'
version: 3.25.76
@@ -8022,8 +8022,8 @@ packages:
resolution: {integrity: sha512-vZ+j079SKrM0Xiq7MJCvQKLDpaH2kfKfLY68xuQE1sqsCsMmx1CyrDBJHsxZ3cX01VOs5SI9igmoZAF3BmdZxw==}
engines: {node: '>=22.0.0'}
'@supabase/shared-types@0.1.91':
resolution: {integrity: sha512-n4co7cT2MD0RGKkAdVPRz8O+f+LaWAqfujV/ug/4U434u5bmopLvCWrA8AzIgNSEr9xyJ+Yv3ksCQo9C0UJWTw==}
'@supabase/shared-types@0.1.95':
resolution: {integrity: sha512-Z/L/nHCiQVqj6nRIBerfQJLcEgYUUFTw+pIr/RMCbldibFrsAg8AkZQxVx/Oe9kSlwgKVxiWHj8m89CLtqo6lg==}
'@supabase/sql-to-rest@0.1.6':
resolution: {integrity: sha512-06KgjeINtc6405XQvfnchBE1azEsU8G2NElfadmvVHKmHa5l2bFzjbtFbpaYgpgTzccHlcDmBaCgedVf2Gyl8Q==}
@@ -24583,7 +24583,7 @@ snapshots:
'@supabase/phoenix': 0.4.5
tslib: 2.8.1
'@supabase/shared-types@0.1.91': {}
'@supabase/shared-types@0.1.95': {}
'@supabase/sql-to-rest@0.1.6(encoding@0.1.13)(supports-color@8.1.1)':
dependencies: