onesvm-browser-server/server/internal/store/audit.go
chii eb972dfa93 feat: 落地 browser-server 控制面并打通 mgr1 海外订阅
单二进制三角色 + Dock 适配器 + Swarm stack 达到可部署态;mgr1 实测订阅经 central-proxy bootstrap,探活 alive=41/52。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 15:05:12 +08:00

67 lines
1.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// audit.go:合规审计表(denied/redact 记录,design-arch §5.4 / §7.2)。
package store
import (
"fmt"
"time"
"onesvm.com/onesvm/browser-server/internal/config"
)
// AuditRow 审计记录。
type AuditRow struct {
ID int64
ConsumerID int64 // 0 = 匿名/未认证
URL string
RuleID string
TS time.Time
}
// AuditAppend 写一条审计(能停能报最低限度)。
func (d *DB) AuditAppend(consumerID int64, url, ruleID string) error {
_, err := d.raw.Exec(
`INSERT INTO audit(consumer_id, url, rule_id, ts) VALUES(?, ?, ?, ?)`,
consumerID, url, ruleID, config.Now().Format(time.RFC3339))
if err != nil {
return fmt.Errorf("store: AuditAppend: %w", err)
}
return nil
}
// AuditRecent 按时间倒序取最近 n 条(运维排查用,禁 SELECT *)。
func (d *DB) AuditRecent(n int) ([]AuditRow, error) {
rows, err := d.raw.Query(
`SELECT id, consumer_id, url, rule_id, ts FROM audit ORDER BY ts DESC, id DESC LIMIT ?`, n)
if err != nil {
return nil, fmt.Errorf("store: AuditRecent: %w", err)
}
defer rows.Close()
var out []AuditRow
for rows.Next() {
var r AuditRow
var ts string
if err := rows.Scan(&r.ID, &r.ConsumerID, &r.URL, &r.RuleID, &ts); err != nil {
return nil, fmt.Errorf("store: AuditRecent scan: %w", err)
}
t, err := time.Parse(time.RFC3339, ts)
if err != nil {
return nil, fmt.Errorf("store: AuditRecent ts 解析: %w", err)
}
r.TS = t
out = append(out, r)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("store: AuditRecent rows: %w", err)
}
return out, nil
}
// AuditCountByRule 统计某规则命中次数(/metrics denied_total{rule_id})。
func (d *DB) AuditCountByRule(ruleID string) (int, error) {
var n int
if err := d.raw.QueryRow(
`SELECT COUNT(id) FROM audit WHERE rule_id = ?`, ruleID).Scan(&n); err != nil {
return 0, fmt.Errorf("store: AuditCountByRule: %w", err)
}
return n, nil
}