agentic review fixes

This commit is contained in:
Paweł Banaszewski
2026-05-22 16:09:30 +00:00
parent af0cc8d61a
commit ef7d4e78df
7 changed files with 230 additions and 192 deletions
@@ -28,7 +28,7 @@ const (
//
// Key shape: "cgw_" + 7 random chars + 32 random chars = 43 chars total.
func New(name string) (database.InsertAIGatewayCoderdKeyParams, string, error) {
secret, hashed, err := apikey.GenerateSecret(KeyLength)
secret, hashed, err := apikey.GenerateSecret(visiblePrefixLength + privateSuffixLength)
if err != nil {
return database.InsertAIGatewayCoderdKeyParams{}, "", xerrors.Errorf("generate secret: %w", err)
}
+94 -94
View File
@@ -64,100 +64,6 @@ const docTemplate = `{
}
}
},
"/aibridge/coderd-keys": {
"get": {
"produces": [
"application/json"
],
"tags": [
"Enterprise"
],
"summary": "List AI Gateway coderd keys",
"operationId": "list-ai-gateway-coderd-keys",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/codersdk.AIGatewayCoderdKey"
}
}
}
},
"security": [
{
"CoderSessionToken": []
}
]
},
"post": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Enterprise"
],
"summary": "Create AI Gateway coderd key",
"operationId": "create-ai-gateway-coderd-key",
"parameters": [
{
"description": "Create AI Gateway coderd key request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/codersdk.CreateAIGatewayCoderdKeyRequest"
}
}
],
"responses": {
"201": {
"description": "Created",
"schema": {
"$ref": "#/definitions/codersdk.CreateAIGatewayCoderdKeyResponse"
}
}
},
"security": [
{
"CoderSessionToken": []
}
]
}
},
"/aibridge/coderd-keys/{key}": {
"delete": {
"tags": [
"Enterprise"
],
"summary": "Delete AI Gateway coderd key",
"operationId": "delete-ai-gateway-coderd-key",
"parameters": [
{
"type": "string",
"format": "uuid",
"description": "Key ID",
"name": "key",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"description": "No Content"
}
},
"security": [
{
"CoderSessionToken": []
}
]
}
},
"/api/experimental/chats": {
"get": {
"description": "Experimental: this endpoint is subject to change.",
@@ -1516,6 +1422,100 @@ const docTemplate = `{
]
}
},
"/api/v2/aibridge/coderd-keys": {
"get": {
"produces": [
"application/json"
],
"tags": [
"Enterprise"
],
"summary": "List AI Gateway coderd keys",
"operationId": "list-ai-gateway-coderd-keys",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/codersdk.AIGatewayCoderdKey"
}
}
}
},
"security": [
{
"CoderSessionToken": []
}
]
},
"post": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Enterprise"
],
"summary": "Create AI Gateway coderd key",
"operationId": "create-ai-gateway-coderd-key",
"parameters": [
{
"description": "Create AI Gateway coderd key request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/codersdk.CreateAIGatewayCoderdKeyRequest"
}
}
],
"responses": {
"201": {
"description": "Created",
"schema": {
"$ref": "#/definitions/codersdk.CreateAIGatewayCoderdKeyResponse"
}
}
},
"security": [
{
"CoderSessionToken": []
}
]
}
},
"/api/v2/aibridge/coderd-keys/{key}": {
"delete": {
"tags": [
"Enterprise"
],
"summary": "Delete AI Gateway coderd key",
"operationId": "delete-ai-gateway-coderd-key",
"parameters": [
{
"type": "string",
"format": "uuid",
"description": "Key ID",
"name": "key",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"description": "No Content"
}
},
"security": [
{
"CoderSessionToken": []
}
]
}
},
"/api/v2/aibridge/interceptions": {
"get": {
"produces": [
+82 -82
View File
@@ -49,88 +49,6 @@
}
}
},
"/aibridge/coderd-keys": {
"get": {
"produces": ["application/json"],
"tags": ["Enterprise"],
"summary": "List AI Gateway coderd keys",
"operationId": "list-ai-gateway-coderd-keys",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/codersdk.AIGatewayCoderdKey"
}
}
}
},
"security": [
{
"CoderSessionToken": []
}
]
},
"post": {
"consumes": ["application/json"],
"produces": ["application/json"],
"tags": ["Enterprise"],
"summary": "Create AI Gateway coderd key",
"operationId": "create-ai-gateway-coderd-key",
"parameters": [
{
"description": "Create AI Gateway coderd key request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/codersdk.CreateAIGatewayCoderdKeyRequest"
}
}
],
"responses": {
"201": {
"description": "Created",
"schema": {
"$ref": "#/definitions/codersdk.CreateAIGatewayCoderdKeyResponse"
}
}
},
"security": [
{
"CoderSessionToken": []
}
]
}
},
"/aibridge/coderd-keys/{key}": {
"delete": {
"tags": ["Enterprise"],
"summary": "Delete AI Gateway coderd key",
"operationId": "delete-ai-gateway-coderd-key",
"parameters": [
{
"type": "string",
"format": "uuid",
"description": "Key ID",
"name": "key",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"description": "No Content"
}
},
"security": [
{
"CoderSessionToken": []
}
]
}
},
"/api/experimental/chats": {
"get": {
"description": "Experimental: this endpoint is subject to change.",
@@ -1337,6 +1255,88 @@
]
}
},
"/api/v2/aibridge/coderd-keys": {
"get": {
"produces": ["application/json"],
"tags": ["Enterprise"],
"summary": "List AI Gateway coderd keys",
"operationId": "list-ai-gateway-coderd-keys",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/codersdk.AIGatewayCoderdKey"
}
}
}
},
"security": [
{
"CoderSessionToken": []
}
]
},
"post": {
"consumes": ["application/json"],
"produces": ["application/json"],
"tags": ["Enterprise"],
"summary": "Create AI Gateway coderd key",
"operationId": "create-ai-gateway-coderd-key",
"parameters": [
{
"description": "Create AI Gateway coderd key request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/codersdk.CreateAIGatewayCoderdKeyRequest"
}
}
],
"responses": {
"201": {
"description": "Created",
"schema": {
"$ref": "#/definitions/codersdk.CreateAIGatewayCoderdKeyResponse"
}
}
},
"security": [
{
"CoderSessionToken": []
}
]
}
},
"/api/v2/aibridge/coderd-keys/{key}": {
"delete": {
"tags": ["Enterprise"],
"summary": "Delete AI Gateway coderd key",
"operationId": "delete-ai-gateway-coderd-key",
"parameters": [
{
"type": "string",
"format": "uuid",
"description": "Key ID",
"name": "key",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"description": "No Content"
}
},
"security": [
{
"CoderSessionToken": []
}
]
}
},
"/api/v2/aibridge/interceptions": {
"get": {
"produces": ["application/json"],
+1 -1
View File
@@ -11,7 +11,7 @@ import (
"golang.org/x/xerrors"
)
// AIGatewayCoderdKey is a shared secret used by an standalone AI Gateway
// AIGatewayCoderdKey is a shared secret used by a standalone AI Gateway
// to authenticate into coderd.
type AIGatewayCoderdKey struct {
ID uuid.UUID `json:"id" format:"uuid"`
+6 -6
View File
@@ -90,12 +90,12 @@ curl -X GET http://coder-server:8080/.well-known/oauth-protected-resource \
```shell
# Example request using curl
curl -X GET http://coder-server:8080/aibridge/coderd-keys \
curl -X GET http://coder-server:8080/api/v2/aibridge/coderd-keys \
-H 'Accept: application/json' \
-H 'Coder-Session-Token: API_KEY'
```
`GET /aibridge/coderd-keys`
`GET /api/v2/aibridge/coderd-keys`
### Example responses
@@ -140,13 +140,13 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
```shell
# Example request using curl
curl -X POST http://coder-server:8080/aibridge/coderd-keys \
curl -X POST http://coder-server:8080/api/v2/aibridge/coderd-keys \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Coder-Session-Token: API_KEY'
```
`POST /aibridge/coderd-keys`
`POST /api/v2/aibridge/coderd-keys`
> Body parameter
@@ -190,11 +190,11 @@ To perform this operation, you must be authenticated. [Learn more](authenticatio
```shell
# Example request using curl
curl -X DELETE http://coder-server:8080/aibridge/coderd-keys/{key} \
curl -X DELETE http://coder-server:8080/api/v2/aibridge/coderd-keys/{key} \
-H 'Coder-Session-Token: API_KEY'
```
`DELETE /aibridge/coderd-keys/{key}`
`DELETE /api/v2/aibridge/coderd-keys/{key}`
### Parameters
+45 -7
View File
@@ -11,6 +11,7 @@ import (
"github.com/google/uuid"
"github.com/coder/coder/v2/coderd/aigatewaycoderdkey"
"github.com/coder/coder/v2/coderd/audit"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/httpapi"
"github.com/coder/coder/v2/codersdk"
@@ -21,7 +22,7 @@ import (
const maxKeyInsertAttempts = 7
// nameFormatDetail is the human-readable description of valid key names.
const nameFormatDetail = "Must be 64 characters or fewer, lowercase letters, numbers, and non-consecutive hyphens, cannot start or end with a hyphen."
const nameFormatDetail = "Must be 64 characters or fewer, lowercase letters, numbers, and non-consecutive hyphens, cannot start or end with a hyphen."
// @Summary Create AI Gateway coderd key
// @ID create-ai-gateway-coderd-key
@@ -31,9 +32,19 @@ const nameFormatDetail = "Must be 64 characters or fewer, lowercase letters, nu
// @Tags Enterprise
// @Param request body codersdk.CreateAIGatewayCoderdKeyRequest true "Create AI Gateway coderd key request"
// @Success 201 {object} codersdk.CreateAIGatewayCoderdKeyResponse
// @Router /aibridge/coderd-keys [post]
// @Router /api/v2/aibridge/coderd-keys [post]
func (api *API) postAIGatewayCoderdKey(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var (
ctx = r.Context()
auditor = api.AGPL.Auditor.Load()
aReq, commitAudit = audit.InitRequest[database.AiGatewayCoderdKey](rw, &audit.RequestParams{
Audit: *auditor,
Log: api.Logger,
Request: r,
Action: database.AuditActionCreate,
})
)
defer commitAudit()
var req codersdk.CreateAIGatewayCoderdKeyRequest
if !httpapi.Read(ctx, rw, r, &req) {
@@ -49,6 +60,13 @@ func (api *API) postAIGatewayCoderdKey(rw http.ResponseWriter, r *http.Request)
return
}
aReq.New = database.AiGatewayCoderdKey{
ID: row.ID,
Name: row.Name,
SecretPrefix: row.SecretPrefix,
CreatedAt: row.CreatedAt,
}
httpapi.Write(ctx, rw, http.StatusCreated, codersdk.CreateAIGatewayCoderdKeyResponse{
ID: row.ID,
Name: row.Name,
@@ -109,7 +127,7 @@ func writeKeyInsertError(ctx context.Context, rw http.ResponseWriter, err error)
// @Produce json
// @Tags Enterprise
// @Success 200 {array} codersdk.AIGatewayCoderdKey
// @Router /aibridge/coderd-keys [get]
// @Router /api/v2/aibridge/coderd-keys [get]
func (api *API) aiGatewayCoderdKeys(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
@@ -137,9 +155,19 @@ func (api *API) aiGatewayCoderdKeys(rw http.ResponseWriter, r *http.Request) {
// @Tags Enterprise
// @Param key path string true "Key ID" format(uuid)
// @Success 204
// @Router /aibridge/coderd-keys/{key} [delete]
// @Router /api/v2/aibridge/coderd-keys/{key} [delete]
func (api *API) deleteAIGatewayCoderdKey(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var (
ctx = r.Context()
auditor = api.AGPL.Auditor.Load()
aReq, commitAudit = audit.InitRequest[database.AiGatewayCoderdKey](rw, &audit.RequestParams{
Audit: *auditor,
Log: api.Logger,
Request: r,
Action: database.AuditActionDelete,
})
)
defer commitAudit()
id, err := uuid.Parse(chi.URLParam(r, "key"))
if err != nil {
@@ -150,7 +178,8 @@ func (api *API) deleteAIGatewayCoderdKey(rw http.ResponseWriter, r *http.Request
return
}
if _, err := api.Database.DeleteAIGatewayCoderdKey(ctx, id); err != nil {
deleted, err := api.Database.DeleteAIGatewayCoderdKey(ctx, id)
if err != nil {
if httpapi.IsUnauthorizedError(err) {
httpapi.Forbidden(rw)
return
@@ -163,6 +192,15 @@ func (api *API) deleteAIGatewayCoderdKey(rw http.ResponseWriter, r *http.Request
return
}
aReq.Old = database.AiGatewayCoderdKey{
ID: deleted.ID,
Name: deleted.Name,
SecretPrefix: deleted.SecretPrefix,
HashedSecret: deleted.HashedSecret,
CreatedAt: deleted.CreatedAt,
LastUsedAt: deleted.LastUsedAt,
}
httpapi.Write(ctx, rw, http.StatusNoContent, nil)
}
+1 -1
View File
@@ -306,7 +306,7 @@ export interface AIConfig {
// From codersdk/aigatewaycoderdkeys.go
/**
* AIGatewayCoderdKey is a shared secret used by an standalone AI Gateway
* AIGatewayCoderdKey is a shared secret used by a standalone AI Gateway
* to authenticate into coderd.
*/
export interface AIGatewayCoderdKey {