Files
Agent-System-Backend/internal/server/audit_scope_test.go
T
weichen e0b1c27f1f
ci / vet-and-test (pull_request) Successful in 42s
Scope command audit storage and queries to the requesting owner
Why: GET /api/commands/audit leaked every tenant's audit rows (command ids, entrances, conversation ids, param digests) to any authenticated user; owner was never recorded nor filtered.
Evidence: Red run at a7cc69b FAIL (alice sees bob's row); after fix go test ./... 32/32 packages ok, including TestCommandAuditOwnerScoping and the v18 backfill test (rows recorded on the task card).
Impact: v18 migration adds command_audit.owner with actor-based backfill (empty-actor rows stay invisible via API, kept in-table); AppendAudit/ListAudits gain owner params; cmdbus port and fakes updated; handler passes authenticated owner. No public extension surface change.
Refs: Task card R1; U0 proposal section 5 C7 finding.
2026-10-08 14:02:19 +00:00

69 lines
2.1 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.
package server
import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
agentcommand "agent-command"
)
// 命令审计按租户作用域(回归:GET /api/commands/audit 曾返回全租户审计行——
// ListAudits 无 owner 条件、command_audit 无 owner 列;多用户档下任何登录
// 用户可读他人命令 ID、入口、会话 ID 与参数摘要)。
// 经真实认证中间件(API key → owner)请求,断言每个租户只见本租户的行。
func TestCommandAuditOwnerScoping(t *testing.T) {
srv, st := newAuthTestServer(t)
h := srv.Handler()
aliceKey, err := st.CreateAPIKey("alice", "e2e")
if err != nil {
t.Fatal(err)
}
bobKey, err := st.CreateAPIKey("bob", "e2e")
if err != nil {
t.Fatal(err)
}
// 两租户各产生一条命令审计(owner 列=v18 起的归属依据;Actor 仅为信封内容)。
if err := st.AppendAudit("alice", agentcommand.AuditEnvelope{
CommandID: "cmd.alice", Actor: "alice", State: agentcommand.StateCommitted,
}); err != nil {
t.Fatal(err)
}
if err := st.AppendAudit("bob", agentcommand.AuditEnvelope{
CommandID: "cmd.bob", Actor: "bob", State: agentcommand.StateCommitted,
}); err != nil {
t.Fatal(err)
}
get := func(key string) []map[string]any {
t.Helper()
req := httptest.NewRequest(http.MethodGet, "/api/commands/audit", nil)
req.Header.Set("Authorization", "Bearer "+key)
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("audit query: %d %s", rec.Code, rec.Body.String())
}
var out struct {
Audits []map[string]any `json:"audits"`
}
if err := json.Unmarshal(rec.Body.Bytes(), &out); err != nil {
t.Fatal(err)
}
return out.Audits
}
for key, owner := range map[string]string{aliceKey: "alice", bobKey: "bob"} {
rows := get(key)
if len(rows) != 1 {
t.Fatalf("owner %s: audit rows = %d, want 1(跨租户行不得返回;got=%v)", owner, len(rows), rows)
}
if rows[0]["actor"] != owner || rows[0]["commandId"] != "cmd."+owner {
t.Fatalf("owner %s: wrong row %v", owner, rows[0])
}
}
}