mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: audit user AI budget override mutations (#25745)
Relates to https://linear.app/codercom/issue/AIGOV-285/add-user-budget-overrides-table-and-crud-api Adds audit-log support for `user_ai_budget_override` mutations. Without it, an admin could quietly change a user's per-user spend cap (e.g. from `$500` to `$50`), reassign it to a different group, or delete it entirely with no record of who did it. Both write (`create-or-update`) and delete actions now generate audit log entries. Unlike group AI budgets, which only track `spend_limit`, overrides also track `group_name`: an override can be reassigned to a different attributed group, so that change needs to show up in the diff. The raw `spend_limit_micros`, IDs, and timestamps are ignored in favor of the human-readable `spend_limit` and `group_name`. Depends on #25439. ## Screenshot <img width="1343" height="514" alt="image" src="https://github.com/user-attachments/assets/aee30f58-6e81-435e-9bca-5bc98f49d8d3" />
This commit is contained in:
Generated
+2
-1
@@ -569,7 +569,8 @@ CREATE TYPE resource_type AS ENUM (
|
||||
'ai_provider_key',
|
||||
'group_ai_budget',
|
||||
'user_skill',
|
||||
'ai_gateway_key'
|
||||
'ai_gateway_key',
|
||||
'user_ai_budget_override'
|
||||
);
|
||||
|
||||
CREATE TYPE shareable_workspace_owners AS ENUM (
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
-- Postgres does not support removing enum values.
|
||||
@@ -0,0 +1,2 @@
|
||||
-- Audit log resource type for user AI budget overrides.
|
||||
ALTER TYPE resource_type ADD VALUE IF NOT EXISTS 'user_ai_budget_override';
|
||||
@@ -102,6 +102,26 @@ func (b GroupAiBudget) Auditable(groupName string) AuditableGroupAiBudget {
|
||||
}
|
||||
}
|
||||
|
||||
// AuditableUserAiBudgetOverride is the audit-log representation of
|
||||
// UserAiBudgetOverride. It enriches the raw record with the username, the
|
||||
// attributed group's name, and a human-readable spend limit so audit
|
||||
// entries can display meaningful values instead of UUIDs and micros.
|
||||
type AuditableUserAiBudgetOverride struct {
|
||||
UserAiBudgetOverride
|
||||
Username string `json:"username"`
|
||||
GroupName string `json:"group_name"`
|
||||
SpendLimit string `json:"spend_limit"`
|
||||
}
|
||||
|
||||
func (o UserAiBudgetOverride) Auditable(username, groupName string) AuditableUserAiBudgetOverride {
|
||||
return AuditableUserAiBudgetOverride{
|
||||
UserAiBudgetOverride: o,
|
||||
Username: username,
|
||||
GroupName: groupName,
|
||||
SpendLimit: fmt.Sprintf("$%.2f", float64(o.SpendLimitMicros)/1_000_000),
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns an object that can be used in audit logs.
|
||||
// Covers both group and group member changes.
|
||||
func (g Group) Auditable(members []GroupMember) AuditableGroup {
|
||||
|
||||
Generated
+4
-1
@@ -3366,6 +3366,7 @@ const (
|
||||
ResourceTypeGroupAiBudget ResourceType = "group_ai_budget"
|
||||
ResourceTypeUserSkill ResourceType = "user_skill"
|
||||
ResourceTypeAIGatewayKey ResourceType = "ai_gateway_key"
|
||||
ResourceTypeUserAiBudgetOverride ResourceType = "user_ai_budget_override"
|
||||
)
|
||||
|
||||
func (e *ResourceType) Scan(src interface{}) error {
|
||||
@@ -3438,7 +3439,8 @@ func (e ResourceType) Valid() bool {
|
||||
ResourceTypeAIProviderKey,
|
||||
ResourceTypeGroupAiBudget,
|
||||
ResourceTypeUserSkill,
|
||||
ResourceTypeAIGatewayKey:
|
||||
ResourceTypeAIGatewayKey,
|
||||
ResourceTypeUserAiBudgetOverride:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -3480,6 +3482,7 @@ func AllResourceTypeValues() []ResourceType {
|
||||
ResourceTypeGroupAiBudget,
|
||||
ResourceTypeUserSkill,
|
||||
ResourceTypeAIGatewayKey,
|
||||
ResourceTypeUserAiBudgetOverride,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user