1
0
forked from wrenn/wrenn

feat: add audit logging for all admin actions and admin audit page

Log every admin-panel action (user activate/deactivate, team BYOC toggle,
team delete, template delete, build create/cancel) to the audit_logs table
under PlatformTeamID with scope "admin".

Add GET /v1/admin/audit-logs endpoint and /admin/audit frontend page with
infinite scroll and hierarchical filters. Expose audit.Entry + Log() for
cloud repo extensibility.

Fix seed_platform_team down-migration FK violation by deleting dependent
rows before the team row.
This commit is contained in:
2026-04-21 15:41:45 +06:00
parent edec170652
commit 7fd801c1eb
10 changed files with 917 additions and 51 deletions

View File

@ -13,6 +13,8 @@ import (
"github.com/go-chi/chi/v5"
"git.omukk.dev/wrenn/wrenn/internal/layout"
"git.omukk.dev/wrenn/wrenn/pkg/audit"
"git.omukk.dev/wrenn/wrenn/pkg/auth"
"git.omukk.dev/wrenn/wrenn/pkg/db"
"git.omukk.dev/wrenn/wrenn/pkg/id"
"git.omukk.dev/wrenn/wrenn/pkg/lifecycle"
@ -22,13 +24,14 @@ import (
)
type buildHandler struct {
svc *service.BuildService
db *db.Queries
pool *lifecycle.HostClientPool
svc *service.BuildService
db *db.Queries
pool *lifecycle.HostClientPool
audit *audit.AuditLogger
}
func newBuildHandler(svc *service.BuildService, db *db.Queries, pool *lifecycle.HostClientPool) *buildHandler {
return &buildHandler{svc: svc, db: db, pool: pool}
func newBuildHandler(svc *service.BuildService, db *db.Queries, pool *lifecycle.HostClientPool, al *audit.AuditLogger) *buildHandler {
return &buildHandler{svc: svc, db: db, pool: pool, audit: al}
}
type createBuildRequest struct {
@ -187,6 +190,8 @@ func (h *buildHandler) Create(w http.ResponseWriter, r *http.Request) {
return
}
ac := auth.MustFromContext(r.Context())
h.audit.LogBuildCreate(r.Context(), ac, build.ID, req.Name)
writeJSON(w, http.StatusCreated, buildToResponse(build))
}
@ -305,6 +310,8 @@ func (h *buildHandler) DeleteTemplate(w http.ResponseWriter, r *http.Request) {
return
}
ac := auth.MustFromContext(r.Context())
h.audit.LogTemplateDelete(r.Context(), ac, name)
w.WriteHeader(http.StatusNoContent)
}
@ -323,5 +330,7 @@ func (h *buildHandler) Cancel(w http.ResponseWriter, r *http.Request) {
return
}
ac := auth.MustFromContext(r.Context())
h.audit.LogBuildCancel(r.Context(), ac, buildID)
w.WriteHeader(http.StatusNoContent)
}