Files
Agent-System-Backend/internal/store/audit.go
T
weichen f1302ed5b3 Enable canonical versioned Go module consumption
Why: Allow consumers to download an immutable module revision without nested source checkouts or local path replacements.

Evidence: SELF package tests and the prior canonical-path rejection are recorded in the Dev dependency-workspace task card; remote consumption is replayed against the committed candidate.

Impact: Change the module identity and its Go imports while preserving API behavior. Existing historical submodule revisions remain buildable.

Refs: Versioned dependencies U1/U3; feature/dependency-workspace
2026-10-13 15:47:16 +00:00

65 lines
2.3 KiB
Go

package store
import (
"database/sql"
"encoding/json"
"time"
agentcommand "git-ssh.u1680832.nyat.app/weichen/Agent-Command.git"
)
// AppendAudit 追加命令审计信封(cmdbus 端口;v7 建表,v18 增加 owner 列)。
// owner 是租户身份(认证注入),与信封里的 Actor(发起主体)语义不同:查询按
// owner 过滤,跨租户审计不可见。
func (s *Store) AppendAudit(owner string, env agentcommand.AuditEnvelope) error {
raw, err := json.Marshal(env)
if err != nil {
return err
}
_, err = s.db.Exec(s.q(`INSERT INTO command_audit (time, command_id, source, entrance, state, operation_id, conversation_id, owner, payload)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`),
env.Time.UTC().Format(time.RFC3339Nano), env.CommandID, string(env.Source), env.Entrance, string(env.State),
env.OperationID, env.ConversationID, owner, string(raw))
return err
}
// ListAudits 审计查询(owner 作用域,时间倒序;conversationID 空 = 该租户全局)。
// owner 为空视为无作用域:不返回任何行(防调用方漏传租户时把未归属存量行
// 全部泄出——服务端认证层恒注入非空 owner,这里是纵深防御)。
// v18 回填时 actor 为空的存量行 owner 保持空串,不匹配任何租户:这些行不再经
// API 返回(数据保留在表内,可直查数据库取证)——见 v18 迁移注释。
func (s *Store) ListAudits(owner, conversationID string, limit int) ([]agentcommand.AuditEnvelope, error) {
if owner == "" {
return []agentcommand.AuditEnvelope{}, nil
}
if limit <= 0 || limit > 500 {
limit = 100
}
var (
rows *sql.Rows
err error
)
if conversationID == "" {
rows, err = s.db.Query(s.q(`SELECT payload FROM command_audit WHERE owner=? ORDER BY time DESC LIMIT ?`), owner, limit)
} else {
rows, err = s.db.Query(s.q(`SELECT payload FROM command_audit WHERE owner=? AND conversation_id=? ORDER BY time DESC LIMIT ?`), owner, conversationID, limit)
}
if err != nil {
return nil, err
}
defer rows.Close()
out := []agentcommand.AuditEnvelope{}
for rows.Next() {
var raw string
if err := rows.Scan(&raw); err != nil {
return nil, err
}
var env agentcommand.AuditEnvelope
if err := json.Unmarshal([]byte(raw), &env); err != nil {
return nil, err
}
out = append(out, env)
}
return out, rows.Err()
}