Files
Agent-System-Backend/internal/server/audit_scope_test.go
T
weichen adcd8fefd2 Fence U3 account writes and stabilize directory cursors
Why: Account disable could be followed by late Backend business writes, API key creation could implicitly create users, account bootstrap locks could invert, and directory cursors were process-local or leaked out-of-scope changes.

Evidence: Local go test ./... and isolated PostgreSQL package suites passed on the staged candidate; exact committed-head SELF replay and stage 6 human review remain pending.

Impact: Adds final account transactions and external-effect checks across HTTP, Host, Bus and run manager; tightens API key issuance and persists versioned cursor signing. Delegated RDM rename still needs the separately proposed real-operator contract, so A1 and stage 6 are not complete.

Refs: Documents U3 r1, approved A1-A4 amendment fb3a821, pending delegated-projection amendment 5783940, Dev feature/iam-u3-account-directory-recovery.
2026-10-14 07:33:54 +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 := createLegacyAPIKeyFixture(t, st, "alice", "e2e")
if err != nil {
t.Fatal(err)
}
bobKey, err := createLegacyAPIKeyFixture(t, st, "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])
}
}
}