From 79a74fc81782b5922dccf21f8b5c9e89c5725a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Banaszewski?= Date: Thu, 2 Jul 2026 15:45:05 +0200 Subject: [PATCH] Revert "chore: hide AI Gateway key management UI/CLI/API (#26879)" (#26913) Reverting https://github.com/coder/coder/commit/377c1309b7a42ead9cfbd864f0af8e9b6e472851 since release 2.35 was already cut: https://github.com/coder/coder/tree/release/2.35 --- coderd/apidoc/docs.go | 20 +-- coderd/apidoc/swagger.json | 20 +-- docs/reference/api/enterprise.md | 146 ++++++++++++++++++ docs/reference/cli/index.md | 1 + enterprise/cli/aigateway.go | 5 +- enterprise/cli/testdata/coder_--help.golden | 1 + .../testdata/coder_ai-gateway_--help.golden | 12 ++ .../coder_ai-gateway_keys_--help.golden | 14 ++ ...coder_ai-gateway_keys_create_--help.golden | 9 ++ ...coder_ai-gateway_keys_delete_--help.golden | 15 ++ .../coder_ai-gateway_keys_list_--help.golden | 18 +++ enterprise/coderd/aibridgeserve.go | 1 - enterprise/coderd/aigatewaykeys.go | 3 - .../management/AISettingsSidebarView.tsx | 5 + site/src/router.tsx | 10 +- 15 files changed, 240 insertions(+), 40 deletions(-) create mode 100644 enterprise/cli/testdata/coder_ai-gateway_--help.golden create mode 100644 enterprise/cli/testdata/coder_ai-gateway_keys_--help.golden create mode 100644 enterprise/cli/testdata/coder_ai-gateway_keys_create_--help.golden create mode 100644 enterprise/cli/testdata/coder_ai-gateway_keys_delete_--help.golden create mode 100644 enterprise/cli/testdata/coder_ai-gateway_keys_list_--help.golden diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index a280e5e7c4..86eea40d2c 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -1434,10 +1434,7 @@ const docTemplate = `{ { "CoderSessionToken": [] } - ], - "x-apidocgen": { - "skip": true - } + ] }, "post": { "consumes": [ @@ -1474,10 +1471,7 @@ const docTemplate = `{ { "CoderSessionToken": [] } - ], - "x-apidocgen": { - "skip": true - } + ] } }, "/api/v2/ai-gateway/keys/{key}": { @@ -1506,10 +1500,7 @@ const docTemplate = `{ { "CoderSessionToken": [] } - ], - "x-apidocgen": { - "skip": true - } + ] } }, "/api/v2/ai-gateway/models": { @@ -1557,10 +1548,7 @@ const docTemplate = `{ { "AIGatewayKey": [] } - ], - "x-apidocgen": { - "skip": true - } + ] } }, "/api/v2/ai-gateway/sessions": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 5eaa93a980..d30e6894da 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -1269,10 +1269,7 @@ { "CoderSessionToken": [] } - ], - "x-apidocgen": { - "skip": true - } + ] }, "post": { "consumes": ["application/json"], @@ -1303,10 +1300,7 @@ { "CoderSessionToken": [] } - ], - "x-apidocgen": { - "skip": true - } + ] } }, "/api/v2/ai-gateway/keys/{key}": { @@ -1333,10 +1327,7 @@ { "CoderSessionToken": [] } - ], - "x-apidocgen": { - "skip": true - } + ] } }, "/api/v2/ai-gateway/models": { @@ -1378,10 +1369,7 @@ { "AIGatewayKey": [] } - ], - "x-apidocgen": { - "skip": true - } + ] } }, "/api/v2/ai-gateway/sessions": { diff --git a/docs/reference/api/enterprise.md b/docs/reference/api/enterprise.md index 9823449008..f631241229 100644 --- a/docs/reference/api/enterprise.md +++ b/docs/reference/api/enterprise.md @@ -178,6 +178,152 @@ curl -X GET http://coder-server:8080/api/v2/agent-firewall/sessions/{id}/logs \ To perform this operation, you must be authenticated. [Learn more](authentication.md). +## List AI Gateway keys + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/ai-gateway/keys \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /api/v2/ai-gateway/keys` + +### Example responses + +> 200 Response + +```json +[ + { + "created_at": "2019-08-24T14:15:22Z", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "key_prefix": "string", + "last_heartbeat_at": "2019-08-24T14:15:22Z", + "name": "string" + } +] +``` + +### Responses + +| Status | Meaning | Description | Schema | +|--------|---------------------------------------------------------|-------------|-------------------------------------------------------------------| +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | array of [codersdk.AIGatewayKey](schemas.md#codersdkaigatewaykey) | + +

Response Schema

+ +Status Code **200** + +| Name | Type | Required | Restrictions | Description | +|-----------------------|-------------------|----------|--------------|-------------| +| `[array item]` | array | false | | | +| `» created_at` | string(date-time) | false | | | +| `» id` | string(uuid) | false | | | +| `» key_prefix` | string | false | | | +| `» last_heartbeat_at` | string(date-time) | false | | | +| `» name` | string | false | | | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + +## Create AI Gateway key + +### Code samples + +```shell +# Example request using curl +curl -X POST http://coder-server:8080/api/v2/ai-gateway/keys \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`POST /api/v2/ai-gateway/keys` + +> Body parameter + +```json +{ + "name": "string" +} +``` + +### Parameters + +| Name | In | Type | Required | Description | +|--------|------|------------------------------------------------------------------------------------|----------|-------------------------------| +| `body` | body | [codersdk.CreateAIGatewayKeyRequest](schemas.md#codersdkcreateaigatewaykeyrequest) | true | Create AI Gateway key request | + +### Example responses + +> 201 Response + +```json +{ + "created_at": "2019-08-24T14:15:22Z", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "key": "string", + "key_prefix": "string", + "name": "string" +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +|--------|--------------------------------------------------------------|-------------|--------------------------------------------------------------------------------------| +| 201 | [Created](https://tools.ietf.org/html/rfc7231#section-6.3.2) | Created | [codersdk.CreateAIGatewayKeyResponse](schemas.md#codersdkcreateaigatewaykeyresponse) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + +## Delete AI Gateway key + +### Code samples + +```shell +# Example request using curl +curl -X DELETE http://coder-server:8080/api/v2/ai-gateway/keys/{key} \ + -H 'Coder-Session-Token: API_KEY' +``` + +`DELETE /api/v2/ai-gateway/keys/{key}` + +### Parameters + +| Name | In | Type | Required | Description | +|-------|------|--------------|----------|-------------| +| `key` | path | string(uuid) | true | Key ID | + +### Responses + +| Status | Meaning | Description | Schema | +|--------|-----------------------------------------------------------------|-------------|--------| +| 204 | [No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5) | No Content | | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + +## AI Gateway serve + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/ai-gateway/serve \ + -H 'X-AI-Governance-Gateway-Key: API_KEY' +``` + +`GET /api/v2/ai-gateway/serve` + +### Responses + +| Status | Meaning | Description | Schema | +|--------|--------------------------------------------------------------------------|---------------------|--------| +| 101 | [Switching Protocols](https://tools.ietf.org/html/rfc7231#section-6.2.2) | Switching Protocols | | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + ## Get appearance ### Code samples diff --git a/docs/reference/cli/index.md b/docs/reference/cli/index.md index a25269fd06..218cffa7db 100644 --- a/docs/reference/cli/index.md +++ b/docs/reference/cli/index.md @@ -66,6 +66,7 @@ Coder — A tool for provisioning self-hosted development environments with Terr | [support](./support.md) | Commands for troubleshooting issues with a Coder deployment. | | [server](./server.md) | Start a Coder server | | [provisioner](./provisioner.md) | View and manage provisioner daemons and jobs | +| [ai-gateway](./ai-gateway.md) | Manage AI Gateway | | [agent-firewall](./agent-firewall.md) | Network isolation tool for monitoring and restricting HTTP/HTTPS requests | | [features](./features.md) | List Enterprise features | | [licenses](./licenses.md) | Add, delete, and list licenses | diff --git a/enterprise/cli/aigateway.go b/enterprise/cli/aigateway.go index 11aae44a57..2844ef43dc 100644 --- a/enterprise/cli/aigateway.go +++ b/enterprise/cli/aigateway.go @@ -14,9 +14,8 @@ import ( func (r *RootCmd) aiGateway() *serpent.Command { return &serpent.Command{ - Use: "ai-gateway", - Short: "Manage AI Gateway", - Hidden: true, + Use: "ai-gateway", + Short: "Manage AI Gateway", Handler: func(inv *serpent.Invocation) error { return inv.Command.HelpHandler(inv) }, diff --git a/enterprise/cli/testdata/coder_--help.golden b/enterprise/cli/testdata/coder_--help.golden index 4e392a8dd6..c9e3b53168 100644 --- a/enterprise/cli/testdata/coder_--help.golden +++ b/enterprise/cli/testdata/coder_--help.golden @@ -16,6 +16,7 @@ USAGE: SUBCOMMANDS: agent-firewall Network isolation tool for monitoring and restricting HTTP/HTTPS requests + ai-gateway Manage AI Gateway external-workspaces Create or manage external workspaces features List Enterprise features groups Manage groups diff --git a/enterprise/cli/testdata/coder_ai-gateway_--help.golden b/enterprise/cli/testdata/coder_ai-gateway_--help.golden new file mode 100644 index 0000000000..2c0d35058b --- /dev/null +++ b/enterprise/cli/testdata/coder_ai-gateway_--help.golden @@ -0,0 +1,12 @@ +coder v0.0.0-devel + +USAGE: + coder ai-gateway + + Manage AI Gateway + +SUBCOMMANDS: + keys Manage AI Gateway keys + +——— +Run `coder --help` for a list of global options. diff --git a/enterprise/cli/testdata/coder_ai-gateway_keys_--help.golden b/enterprise/cli/testdata/coder_ai-gateway_keys_--help.golden new file mode 100644 index 0000000000..8c465b07b2 --- /dev/null +++ b/enterprise/cli/testdata/coder_ai-gateway_keys_--help.golden @@ -0,0 +1,14 @@ +coder v0.0.0-devel + +USAGE: + coder ai-gateway keys + + Manage AI Gateway keys + +SUBCOMMANDS: + create Create an AI Gateway key + delete Delete an AI Gateway key + list List AI Gateway keys + +——— +Run `coder --help` for a list of global options. diff --git a/enterprise/cli/testdata/coder_ai-gateway_keys_create_--help.golden b/enterprise/cli/testdata/coder_ai-gateway_keys_create_--help.golden new file mode 100644 index 0000000000..bcaa7cd6d1 --- /dev/null +++ b/enterprise/cli/testdata/coder_ai-gateway_keys_create_--help.golden @@ -0,0 +1,9 @@ +coder v0.0.0-devel + +USAGE: + coder ai-gateway keys create + + Create an AI Gateway key + +——— +Run `coder --help` for a list of global options. diff --git a/enterprise/cli/testdata/coder_ai-gateway_keys_delete_--help.golden b/enterprise/cli/testdata/coder_ai-gateway_keys_delete_--help.golden new file mode 100644 index 0000000000..62b0db207a --- /dev/null +++ b/enterprise/cli/testdata/coder_ai-gateway_keys_delete_--help.golden @@ -0,0 +1,15 @@ +coder v0.0.0-devel + +USAGE: + coder ai-gateway keys delete [flags] + + Delete an AI Gateway key + + Aliases: rm + +OPTIONS: + -y, --yes bool + Bypass confirmation prompts. + +——— +Run `coder --help` for a list of global options. diff --git a/enterprise/cli/testdata/coder_ai-gateway_keys_list_--help.golden b/enterprise/cli/testdata/coder_ai-gateway_keys_list_--help.golden new file mode 100644 index 0000000000..f922806ded --- /dev/null +++ b/enterprise/cli/testdata/coder_ai-gateway_keys_list_--help.golden @@ -0,0 +1,18 @@ +coder v0.0.0-devel + +USAGE: + coder ai-gateway keys list [flags] + + List AI Gateway keys + + Aliases: ls + +OPTIONS: + -c, --column [id|name|key prefix|created at|last heartbeat at] (default: id,name,key prefix,last heartbeat at,created at) + Columns to display in table output. + + -o, --output table|json (default: table) + Output format. + +——— +Run `coder --help` for a list of global options. diff --git a/enterprise/coderd/aibridgeserve.go b/enterprise/coderd/aibridgeserve.go index 562dd539cb..f2f9fcc54d 100644 --- a/enterprise/coderd/aibridgeserve.go +++ b/enterprise/coderd/aibridgeserve.go @@ -42,7 +42,6 @@ const aiGatewayKeyHeartbeatInterval = 60 * time.Second // @Tags Enterprise // @Success 101 // @Router /api/v2/ai-gateway/serve [get] -// @x-apidocgen {"skip": true} func (api *API) aiGatewayServe(rw http.ResponseWriter, r *http.Request) { key := r.Header.Get(codersdk.AIGatewayKeyHeader) if key == "" { diff --git a/enterprise/coderd/aigatewaykeys.go b/enterprise/coderd/aigatewaykeys.go index d7032a32a5..30815f9bdc 100644 --- a/enterprise/coderd/aigatewaykeys.go +++ b/enterprise/coderd/aigatewaykeys.go @@ -29,7 +29,6 @@ const nameFormatDetail = "Must be 64 characters or fewer, lowercase letters, num // @Param request body codersdk.CreateAIGatewayKeyRequest true "Create AI Gateway key request" // @Success 201 {object} codersdk.CreateAIGatewayKeyResponse // @Router /api/v2/ai-gateway/keys [post] -// @x-apidocgen {"skip": true} func (api *API) postAIGatewayKey(rw http.ResponseWriter, r *http.Request) { var ( ctx = r.Context() @@ -118,7 +117,6 @@ func writeKeyInsertError(ctx context.Context, rw http.ResponseWriter, err error) // @Tags Enterprise // @Success 200 {array} codersdk.AIGatewayKey // @Router /api/v2/ai-gateway/keys [get] -// @x-apidocgen {"skip": true} func (api *API) aiGatewayKeys(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -149,7 +147,6 @@ func (api *API) aiGatewayKeys(rw http.ResponseWriter, r *http.Request) { // @Param key path string true "Key ID" format(uuid) // @Success 204 // @Router /api/v2/ai-gateway/keys/{key} [delete] -// @x-apidocgen {"skip": true} func (api *API) deleteAIGatewayKey(rw http.ResponseWriter, r *http.Request) { var ( ctx = r.Context() diff --git a/site/src/modules/management/AISettingsSidebarView.tsx b/site/src/modules/management/AISettingsSidebarView.tsx index c9502b61c2..875055f047 100644 --- a/site/src/modules/management/AISettingsSidebarView.tsx +++ b/site/src/modules/management/AISettingsSidebarView.tsx @@ -42,6 +42,11 @@ const AISettingsSidebarView: FC = ({ AI Governance )} + {permissions.viewAIGatewayKeys && ( + + AI Gateway keys + + )} {permissions.viewAnyAIProvider && ( Providers diff --git a/site/src/router.tsx b/site/src/router.tsx index b83be153a9..c3fd85d72e 100644 --- a/site/src/router.tsx +++ b/site/src/router.tsx @@ -434,7 +434,7 @@ const AISettingsAddProviderPage = lazy( "./pages/AISettingsPage/ProvidersPage/AddProviderPage/AddProviderPage" ), ); -const _AISettingsGatewayKeysPage = lazy( +const AISettingsGatewayKeysPage = lazy( () => import("./pages/AISettingsPage/GatewayKeysPage/GatewayKeysPage"), ); const AISettingsModelsPage = lazy( @@ -476,6 +476,10 @@ const AISettingsIndexRedirect = () => { return ; } + if (permissions.viewAIGatewayKeys) { + return ; + } + if (permissions.editDeploymentConfig) { return ; } @@ -756,6 +760,10 @@ export const router = createBrowserRouter( }> } /> + } + /> } /> } /> } />