Files
coder/coderd/audit/diff.go
T
Yevhenii Shcherbina 2732378da2 feat: audit group AI budget mutations (#25374)
Relates to
https://linear.app/codercom/issue/AIGOV-284/add-group-budgets-table-and-crud-api

Adds audit-log support for `group_ai_budget` mutations. Without it, an
admin could silently lower a spend limit from `$500` to `$50` or delete
a budget entirely, with no record of who performed the action.

Both write (`create-or-update`) and delete actions now produce audit log
entries, including before/after diffs for `spend_limit_micros`.

Depends on #25203.

## Old Version
<img width="1340" height="456" alt="image"
src="https://github.com/user-attachments/assets/e9ff52fb-a905-4aef-a4ee-7cdc58e68b75"
/>

## New Version (see
https://github.com/coder/coder/pull/25374/changes/9d22833de87cc106c24142c1d471a3f71872bf67)
<img width="1347" height="496" alt="image"
src="https://github.com/user-attachments/assets/1b9bbfa1-f86d-48e3-a0b1-266eb76f851f"
/>
2026-05-18 15:17:20 -04:00

76 lines
2.0 KiB
Go

package audit
import (
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/idpsync"
)
// Auditable is mostly a marker interface. It contains a definitive list of all
// auditable types. If you want to audit a new type, first define it in
// AuditableResources, then add it to this interface.
type Auditable interface {
database.APIKey |
database.Template |
database.TemplateVersion |
database.User |
database.WorkspaceTable |
database.GitSSHKey |
database.WorkspaceBuild |
database.AuditableGroup |
database.License |
database.WorkspaceProxy |
database.AuditOAuthConvertState |
database.HealthSettings |
database.NotificationsSettings |
database.OAuth2ProviderApp |
database.OAuth2ProviderAppSecret |
database.PrebuildsSettings |
database.CustomRole |
database.AuditableOrganizationMember |
database.Organization |
database.NotificationTemplate |
idpsync.OrganizationSyncSettings |
idpsync.GroupSyncSettings |
idpsync.RoleSyncSettings |
database.TaskTable |
database.AiSeatState |
database.AIProvider |
database.AIProviderKey |
database.Chat |
database.AuditableGroupAiBudget |
database.UserSecret
}
// Map is a map of changed fields in an audited resource. It maps field names to
// the old and new value for that field.
type Map map[string]OldNew
// OldNew is a pair of values representing the old value and the new value.
type OldNew struct {
Old any
New any
Secret bool
}
// Empty returns a default value of type T.
func Empty[T Auditable]() T {
var t T
return t
}
// Diff compares two auditable resources and produces a Map of the changed
// values.
func Diff[T Auditable](a Auditor, left, right T) Map { return a.diff(left, right) }
// Differ is used so the enterprise version can implement the diff function in
// the Auditor feature interface. Only types in the same package as the
// interface can implement unexported methods.
type Differ struct {
DiffFn func(old, newVal any) Map
}
//nolint:unused
func (d Differ) diff(old, newVal any) Map {
return d.DiffFn(old, newVal)
}