1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
package controlplane
import (
"context"
"fmt"
"strings"
)
func (s *Store) WriteAudit(ctx context.Context, input AuditInput) error {
actorType := "console_user"
if input.Actor.Bootstrap {
actorType = "bootstrap"
}
_, err := s.db.Exec(ctx, `INSERT INTO audit_logs
(actor_id, actor_type, actor_role, tenant_id, request_id, method, path, action, status_code, remote_ip, user_agent)
VALUES (NULLIF($1,'')::uuid,$2,$3,NULLIF($4,'')::uuid,$5,$6,$7,$8,$9,NULLIF($10,'')::inet,$11)`,
input.Actor.ID, actorType, input.Actor.Role, input.Actor.TenantID, input.RequestID, input.Method,
input.Path, input.Action, input.StatusCode, input.RemoteIP, input.UserAgent)
if err != nil {
return fmt.Errorf("write audit log: %w", err)
}
return nil
}
func (s *Store) ListAudit(ctx context.Context, tenantID string, limit int) ([]AuditLog, error) {
if limit < 1 || limit > 1000 {
limit = 200
}
query := `SELECT id, COALESCE(actor_id::text,''), actor_type, actor_role, COALESCE(tenant_id::text,''),
request_id, method, path, action, status_code, COALESCE(host(remote_ip),''), user_agent, created_at FROM audit_logs`
args := []any{}
if strings.TrimSpace(tenantID) != "" {
query += ` WHERE tenant_id=$1`
args = append(args, tenantID)
}
args = append(args, limit)
query += fmt.Sprintf(` ORDER BY created_at DESC LIMIT $%d`, len(args))
rows, err := s.db.Query(ctx, query, args...)
if err != nil {
return nil, fmt.Errorf("query audit logs: %w", err)
}
defer rows.Close()
result := make([]AuditLog, 0)
for rows.Next() {
var item AuditLog
if err := rows.Scan(&item.ID, &item.ActorID, &item.ActorType, &item.ActorRole, &item.TenantID, &item.RequestID, &item.Method, &item.Path, &item.Action, &item.StatusCode, &item.RemoteIP, &item.UserAgent, &item.CreatedAt); err != nil {
return nil, fmt.Errorf("scan audit log: %w", err)
}
result = append(result, item)
}
return result, rows.Err()
}
|