Unauthorized actors no longer grab leases; controlled PATCH projects through DocGov so author_last_edited and audit survive, with idempotent retry on failure. Co-authored-by: Cursor <cursoragent@cursor.com>
122 lines
3.7 KiB
Go
122 lines
3.7 KiB
Go
package docgov_test
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"chat-agent-system/internal/docgov"
|
|
)
|
|
|
|
func TestEditLeaseMutexAndCommentGate(t *testing.T) {
|
|
engine := docgov.NewGovernanceEngine(nil)
|
|
ctx := context.Background()
|
|
docID := "doc_lease_test_001"
|
|
|
|
_, err := engine.CreateOrGetDocument(ctx, docID, 1, "intake", "摸底纪要", "V0.1", "",
|
|
1, "作者", 2, "审核", 3, "批准")
|
|
if err != nil {
|
|
t.Fatalf("create: %v", err)
|
|
}
|
|
|
|
doc, err := engine.AcquireLease(ctx, docgov.LeaseAcquireRequest{
|
|
DocID: docID,
|
|
HolderType: docgov.LeaseHolderSquad,
|
|
HolderID: "run_1",
|
|
TTL: 5 * time.Minute,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("acquire: %v", err)
|
|
}
|
|
if !doc.HasActiveLease(time.Now()) {
|
|
t.Fatal("expected active lease")
|
|
}
|
|
|
|
_, err = engine.AcquireLease(ctx, docgov.LeaseAcquireRequest{
|
|
DocID: docID,
|
|
HolderType: docgov.LeaseHolderHuman,
|
|
HolderID: "42",
|
|
TTL: 5 * time.Minute,
|
|
})
|
|
if !errors.Is(err, docgov.ErrDocumentBusy) {
|
|
t.Fatalf("expected ErrDocumentBusy, got %v", err)
|
|
}
|
|
|
|
_, err = engine.AddComment(ctx, docID, 2, "审核人", docgov.RoleReviewer, "## 结论", docgov.CommentGeneral, "请补充")
|
|
if !errors.Is(err, docgov.ErrDocumentBusy) {
|
|
t.Fatalf("comment should be blocked while leased, got %v", err)
|
|
}
|
|
|
|
_, err = engine.CheckModificationPermission(ctx, docID, docgov.RoleSystem)
|
|
if !errors.Is(err, docgov.ErrDocumentBusy) {
|
|
t.Fatalf("modification check should be busy, got %v", err)
|
|
}
|
|
|
|
if _, err := engine.ReleaseLease(ctx, docID, string(docgov.LeaseHolderSquad), "run_1"); err != nil {
|
|
t.Fatalf("release: %v", err)
|
|
}
|
|
|
|
_, err = engine.AddComment(ctx, docID, 2, "审核人", docgov.RoleReviewer, "## 结论", docgov.CommentGeneral, "请补充")
|
|
if err != nil {
|
|
t.Fatalf("comment after release should succeed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSameHolderRenewLease(t *testing.T) {
|
|
engine := docgov.NewGovernanceEngine(nil)
|
|
ctx := context.Background()
|
|
docID := "doc_lease_renew_001"
|
|
_, _ = engine.CreateOrGetDocument(ctx, docID, 1, "intake", "摸底", "V0.1", "", 1, "a", 2, "b", 3, "c")
|
|
|
|
_, err := engine.AcquireLease(ctx, docgov.LeaseAcquireRequest{
|
|
DocID: docID, HolderType: docgov.LeaseHolderHuman, HolderID: "1", TTL: time.Minute,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
doc, err := engine.AcquireLease(ctx, docgov.LeaseAcquireRequest{
|
|
DocID: docID, HolderType: docgov.LeaseHolderHuman, HolderID: "1", TTL: 10 * time.Minute,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("renew should succeed: %v", err)
|
|
}
|
|
if doc.LeaseExpiresAt == nil || time.Until(*doc.LeaseExpiresAt) < 5*time.Minute {
|
|
t.Fatalf("expected renewed TTL, expires=%v", doc.LeaseExpiresAt)
|
|
}
|
|
}
|
|
|
|
func TestAssertHumanCanEdit_ChecksDutyBeforeLease(t *testing.T) {
|
|
engine := docgov.NewGovernanceEngine(nil)
|
|
ctx := context.Background()
|
|
docID := "doc_assert_order_001"
|
|
_, err := engine.CreateOrGetDocument(ctx, docID, 1, "intake", "摸底", "V0.1", "",
|
|
1, "作者", 2, "审核", 3, "批准")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Non-author must fail without becoming lease holder.
|
|
if err := engine.AssertHumanCanEdit(ctx, docID, 99, docgov.RoleAuthor); err == nil {
|
|
t.Fatal("non-author AssertHumanCanEdit must fail")
|
|
}
|
|
doc, err := engine.GetDocument(ctx, docID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if doc.HasActiveLease(time.Now()) && doc.LeaseHolderID == "99" {
|
|
t.Fatal("unauthorized actor must not hold human lease")
|
|
}
|
|
|
|
if err := engine.AssertHumanCanEdit(ctx, docID, 1, docgov.RoleAuthor); err != nil {
|
|
t.Fatalf("author AssertHumanCanEdit: %v", err)
|
|
}
|
|
doc, err = engine.GetDocument(ctx, docID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !doc.HasActiveLease(time.Now()) || doc.LeaseHolderType != docgov.LeaseHolderHuman || doc.LeaseHolderID != "1" {
|
|
t.Fatalf("author should hold human lease after assert, got type=%s id=%s", doc.LeaseHolderType, doc.LeaseHolderID)
|
|
}
|
|
}
|