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:
Yevhenii Shcherbina
2026-06-10 00:29:06 +00:00
committed by GitHub
parent f95f5e6f86
commit 360611ea15
17 changed files with 429 additions and 37 deletions
+20
View File
@@ -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 {