This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/server/handlers/audit.go
Jeffrey Smith f0dd43144e rebrand: Switchboard Core → Armature
- Rename Go module switchboard-core → armature (155+ files)
- Rename Docker image → gobha/armature
- Rename K8s resources, secrets, deployments
- Rename Prometheus metrics switchboard_* → armature_*
- Rename env vars SWITCHBOARD_ADMIN_* → ARMATURE_ADMIN_*
- Rename DB names switchboard_core* → armature*
- Update all frontend branding, notification templates, docs
- Update CI scripts, e2e tests, Keycloak realm, nginx conf
- Rename scripts/switchboard-ca.sh → scripts/armature-ca.sh
- Rename k8s/switchboard.yaml → k8s/armature.yaml
- Rename chart alerting/dashboard files
- Fix: DockerHub push uses env: binding for secret injection
- Helm chart updated (name, labels, template functions, dashboard, alerting)
- Replace favicon/icon assets with Armature brand

No functional changes. Pure mechanical rename + CI fix.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 21:39:58 +00:00

92 lines
2.2 KiB
Go

package handlers
import (
"context"
"encoding/json"
"log"
"net/http"
"github.com/gin-gonic/gin"
"armature/models"
"armature/store"
)
// AuditLog writes an audit entry via the store interface.
// Non-blocking: errors are logged but don't break the caller.
func AuditLog(auditStore store.AuditStore, c *gin.Context, action, resourceType, resourceID string, metadata map[string]interface{}) {
if auditStore == nil {
return
}
actorID := getUserID(c)
if actorID == "" {
return
}
var meta models.JSONMap
if metadata != nil {
b, _ := json.Marshal(metadata)
json.Unmarshal(b, &meta)
}
entry := &models.AuditEntry{
ActorID: &actorID,
Action: action,
ResourceType: resourceType,
ResourceID: resourceID,
Metadata: meta,
IPAddress: c.ClientIP(),
UserAgent: c.GetHeader("User-Agent"),
}
if err := auditStore.Log(context.Background(), entry); err != nil {
log.Printf("audit log error: %v", err)
}
}
// ── Admin Audit Viewer ──────────────────────
// ListAuditLog returns paginated audit entries with optional filters.
// GET /api/v1/admin/audit?page=1&per_page=50&action=user.create&actor_id=...&resource_type=...
func (h *AdminHandler) ListAuditLog(c *gin.Context) {
page, perPage, offset := parsePagination(c)
opts := store.AuditListOptions{
ListOptions: store.ListOptions{
Limit: perPage,
Offset: offset,
},
Action: c.Query("action"),
ActorID: c.Query("actor_id"),
ResourceType: c.Query("resource_type"),
}
entries, total, err := h.stores.Audit.List(c.Request.Context(), opts)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "query failed"})
return
}
if entries == nil {
entries = []models.AuditEntry{}
}
c.JSON(http.StatusOK, gin.H{
"data": entries,
"total": total,
"page": page,
"per_page": perPage,
})
}
// ListAuditActions returns distinct action names for filter dropdowns.
// GET /api/v1/admin/audit/actions
func (h *AdminHandler) ListAuditActions(c *gin.Context) {
actions, err := h.stores.Audit.ListActions(c.Request.Context())
if err != nil {
c.JSON(http.StatusOK, gin.H{"actions": []string{}})
return
}
c.JSON(http.StatusOK, gin.H{"actions": actions})
}