feat(orchestration/audit): 子代理上下文可审计查询(全量/尾部/关键词定位)+ 主代理代审授权(审计日志+小字)
This commit is contained in:
1 parent
71697ca4f8
commit
8b723009f9
5 files changed
+658
No files matched your search
@@ -0,0 +1,146 @@
|
||||
package audit
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/logger"
|
||||
)
|
||||
|
||||
// newSilentApprover builds an Approver whose audit log is discarded.
|
||||
func newSilentApprover() *Approver {
|
||||
return NewApprover(logger.New(logger.Options{Out: io.Discard}))
|
||||
}
|
||||
|
||||
func TestReviewAndApprove_Records(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ap, err := newSilentApprover().ReviewAndApprove(context.Background(), "worker", "run ls", "list the project dir")
|
||||
if err != nil {
|
||||
t.Fatalf("ReviewAndApprove unexpected error: %v", err)
|
||||
}
|
||||
if ap.Actor != "worker" {
|
||||
t.Fatalf("Actor = %q, want worker", ap.Actor)
|
||||
}
|
||||
if ap.Action != "run ls" {
|
||||
t.Fatalf("Action = %q, want run ls", ap.Action)
|
||||
}
|
||||
if ap.Description != "list the project dir" {
|
||||
t.Fatalf("Description = %q, want list the project dir", ap.Description)
|
||||
}
|
||||
if !ap.Allowed {
|
||||
t.Fatal("Allowed = false, want true")
|
||||
}
|
||||
if ap.Reviewer != "main" {
|
||||
t.Fatalf("Reviewer = %q, want main", ap.Reviewer)
|
||||
}
|
||||
if ap.At.IsZero() {
|
||||
t.Fatal("At is zero, want a timestamp")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApproval_Explain_Allowed(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ap := Approval{Actor: "worker", Allowed: true}
|
||||
if got, want := ap.Explain(), "「worker 想要干什么,我审查后批准了」"; got != want {
|
||||
t.Fatalf("Explain() = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApproval_Explain_Denied(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ap := Approval{Actor: "worker", Allowed: false}
|
||||
if got, want := ap.Explain(), "「worker 想要干什么,我审查后拒绝了」"; got != want {
|
||||
t.Fatalf("Explain() = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReviewAndApprove_Validation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
actor string
|
||||
action string
|
||||
desc string
|
||||
wantErr error
|
||||
}{
|
||||
{name: "blank actor", actor: "", action: "run ls", desc: "list dir", wantErr: ErrUnknownActor},
|
||||
{name: "space actor", actor: " ", action: "run ls", desc: "list dir", wantErr: ErrUnknownActor},
|
||||
{name: "blank action", actor: "worker", action: "", desc: "list dir", wantErr: ErrActionMissing},
|
||||
{name: "blank explain", actor: "worker", action: "run ls", desc: "", wantErr: ErrExplainMissing},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ap, err := newSilentApprover().ReviewAndApprove(context.Background(), tt.actor, tt.action, tt.desc)
|
||||
if err == nil {
|
||||
t.Fatalf("ReviewAndApprove returned nil error, want %v", tt.wantErr)
|
||||
}
|
||||
if !errors.Is(err, tt.wantErr) {
|
||||
t.Fatalf("error = %v, want Is(%v)", err, tt.wantErr)
|
||||
}
|
||||
if ap != nil {
|
||||
t.Fatalf("Approval = %+v, want nil on validation failure", ap)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReviewAndApprove_WritesAuditLog(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var buf bytes.Buffer
|
||||
ap := NewApprover(logger.New(logger.Options{Level: "debug", Format: "json", Out: &buf}))
|
||||
|
||||
_, err := ap.ReviewAndApprove(context.Background(), "worker", "run command", "delete prod db")
|
||||
if err != nil {
|
||||
t.Fatalf("ReviewAndApprove unexpected error: %v", err)
|
||||
}
|
||||
|
||||
got := buf.String()
|
||||
for _, want := range []string{
|
||||
`"source":"orchestration/audit"`,
|
||||
`"actor":"worker"`,
|
||||
`"action":"run command"`,
|
||||
`"explain":"delete prod db"`,
|
||||
`"allowed":true`,
|
||||
`"reviewer":"main"`,
|
||||
} {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Fatalf("audit log missing %s, got: %s", want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReviewAndApprove_CanceledContext(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
_, err := newSilentApprover().ReviewAndApprove(ctx, "worker", "run ls", "list dir")
|
||||
if !errors.Is(err, context.Canceled) {
|
||||
t.Fatalf("error = %v, want context.Canceled", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewApprover_NilLogger(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ap, err := NewApprover(nil).ReviewAndApprove(context.Background(), "worker", "run ls", "list dir")
|
||||
if err != nil {
|
||||
t.Fatalf("ReviewAndApprove with nil logger returned error: %v", err)
|
||||
}
|
||||
if ap == nil || ap.Actor != "worker" || !ap.Allowed {
|
||||
t.Fatalf("Approval with nil logger not recorded: %+v", ap)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user