mirror of
https://github.com/coder/coder.git
synced 2026-06-04 13:38:21 +00:00
3fb7c6264f
## Summary Adds an entitlement-gated **AI add-on** column to both the **Users** table and the **Organization Members** table. When `ai_governance_user_limit` is entitled, each row shows whether the user is consuming an AI seat. ## Background The AI governance add-on tracks which users are consuming AI seats. Admins need visibility into per-user seat consumption directly from the user management tables. This change surfaces that information through both the site-wide Users table and the per-organization Members table, gated behind the `ai_governance_user_limit` entitlement so the column only appears when the feature is licensed. ## Implementation ### Backend - **New SQL query** `GetUserAISeatStates` (`coderd/database/queries/aiseatstate.sql`) — returns user IDs consuming an AI seat, derived from: - Users with entries in `aibridge_interceptions` (AI Bridge usage) - Users who own workspaces with `has_ai_task = true` builds (AI Tasks usage) - **SDK types** — added `has_ai_seat: boolean` to `codersdk.User` and `codersdk.OrganizationMemberWithUserData` - **Handler wiring** — both the Users list endpoint (`coderd/users.go`) and all Members endpoints (`coderd/members.go`) query AI seat state per page of user IDs and populate the response field - **dbauthz** — per-user `ActionRead` checks on `ResourceUserObject` ### Frontend - **Shared `AISeatCell` component** (`site/src/modules/users/AISeatCell.tsx`) — green `CircleCheck` for consuming, gray `X` for non-consuming - **`TableColumnHelpTooltip`** — extended with `ai_addon` variant with tooltip: *"Users with access to AI features like AI Bridge, Boundary, or Tasks who are actively consuming a seat."* - **Column visibility** gated behind `useFeatureVisibility().ai_governance_user_limit` ## Validation - Backend: dbauthz full method suite (`TestMethodTestSuite`) passes including new `GetUserAISeatStates` test - Backend: `TestGetUsers`, `TestUsersFilter`, CLI golden file tests pass - Frontend: 7/7 tests pass across `UsersPage.test.tsx` and `OrganizationMembersPage.test.tsx` (column visibility gating both directions) - `go build ./coderd/...` compiles clean - `pnpm --dir site run lint:types` passes - `make gen` clean ## Risks - **Pagination performance**: The AI seat query is scoped to the current page's user IDs (not a full table scan), keeping it efficient for paginated views. - **Semantic scope**: The workspace-side AI seat derivation uses "any build with `has_ai_task = true`" rather than "latest build only". If the product intent is latest-build-only, this can be tightened in a follow-up. --- _Generated with `mux` • Model: `anthropic:claude-opus-4-6` • Thinking: `xhigh` • Cost: `$27.25`_ <!-- mux-attribution: model=anthropic:claude-opus-4-6 thinking=xhigh costs=27.25 -->
104 lines
2.9 KiB
Markdown
Generated
104 lines
2.9 KiB
Markdown
Generated
# Audit
|
|
|
|
## Get audit logs
|
|
|
|
### Code samples
|
|
|
|
```shell
|
|
# Example request using curl
|
|
curl -X GET http://coder-server:8080/api/v2/audit?limit=0 \
|
|
-H 'Accept: application/json' \
|
|
-H 'Coder-Session-Token: API_KEY'
|
|
```
|
|
|
|
`GET /audit`
|
|
|
|
### Parameters
|
|
|
|
| Name | In | Type | Required | Description |
|
|
|----------|-------|---------|----------|--------------|
|
|
| `q` | query | string | false | Search query |
|
|
| `limit` | query | integer | true | Page limit |
|
|
| `offset` | query | integer | false | Page offset |
|
|
|
|
### Example responses
|
|
|
|
> 200 Response
|
|
|
|
```json
|
|
{
|
|
"audit_logs": [
|
|
{
|
|
"action": "create",
|
|
"additional_fields": {},
|
|
"description": "string",
|
|
"diff": {
|
|
"property1": {
|
|
"new": null,
|
|
"old": null,
|
|
"secret": true
|
|
},
|
|
"property2": {
|
|
"new": null,
|
|
"old": null,
|
|
"secret": true
|
|
}
|
|
},
|
|
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
|
"ip": "string",
|
|
"is_deleted": true,
|
|
"organization": {
|
|
"display_name": "string",
|
|
"icon": "string",
|
|
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
|
"name": "string"
|
|
},
|
|
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
|
"request_id": "266ea41d-adf5-480b-af50-15b940c2b846",
|
|
"resource_icon": "string",
|
|
"resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
|
|
"resource_link": "string",
|
|
"resource_target": "string",
|
|
"resource_type": "template",
|
|
"status_code": 0,
|
|
"time": "2019-08-24T14:15:22Z",
|
|
"user": {
|
|
"avatar_url": "http://example.com",
|
|
"created_at": "2019-08-24T14:15:22Z",
|
|
"email": "user@example.com",
|
|
"has_ai_seat": true,
|
|
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
|
"is_service_account": true,
|
|
"last_seen_at": "2019-08-24T14:15:22Z",
|
|
"login_type": "",
|
|
"name": "string",
|
|
"organization_ids": [
|
|
"497f6eca-6276-4993-bfeb-53cbbbba6f08"
|
|
],
|
|
"roles": [
|
|
{
|
|
"display_name": "string",
|
|
"name": "string",
|
|
"organization_id": "string"
|
|
}
|
|
],
|
|
"status": "active",
|
|
"theme_preference": "string",
|
|
"updated_at": "2019-08-24T14:15:22Z",
|
|
"username": "string"
|
|
},
|
|
"user_agent": "string"
|
|
}
|
|
],
|
|
"count": 0
|
|
}
|
|
```
|
|
|
|
### Responses
|
|
|
|
| Status | Meaning | Description | Schema |
|
|
|--------|---------------------------------------------------------|-------------|------------------------------------------------------------------|
|
|
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.AuditLogResponse](schemas.md#codersdkauditlogresponse) |
|
|
|
|
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|