Why:
Membership could be revoked while a tool waited for confirmation or a queued
HITL reply waited for consumption. Publication replacement also crossed an
empty project scope or another plugin's source namespace for the same Ref.
Evidence:
SELF replay of all four independent review reproductions failed before the
fix and passed unchanged afterward. Committed regressions cover direct and
queued HITL, yes/session confirmation, direct artifact writes, protected vectors,
exact empty project scopes, literal wildcard IDs and unregistered compatibility.
SELF uncached go test ./..., isolated PostgreSQL Store tests and static build passed.
Impact:
Recheck trusted live owner/project authorization when HITL resumes and at write
boundaries. Registered publishers replace only exact owner/project/ref/plugin
rows and vectors; ordinary unregistered publication semantics are preserved.
Refs:
Dev project-member-access implementation plan r1 Task 1; independent Backend
review findings against b9bea5bee0
71 lines
3.2 KiB
Go
71 lines
3.2 KiB
Go
package store
|
|
|
|
import (
|
|
core "agent-system-core"
|
|
"context"
|
|
"testing"
|
|
)
|
|
|
|
func TestAuthorizedKnowledgeFiltersBeforeTopK(t *testing.T) {
|
|
st := openTestStore(t)
|
|
docs := []core.KnowledgeDoc{}
|
|
for i := 0; i < 20; i++ {
|
|
docs = append(docs, core.KnowledgeDoc{Owner: "alice", ProjectID: "domain", Source: "private", Chunk: "sharedterm sharedterm sharedterm sharedterm"})
|
|
}
|
|
docs = append(docs, core.KnowledgeDoc{ID: "published", Owner: "alice", ProjectID: "domain", Source: "plugin:rdm:published", Chunk: "sharedterm plus additional explanatory words for this lower scoring published source"})
|
|
if err := st.AddKnowledge(docs...); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
hits, err := st.SearchKnowledgeSharedAuthorized("bob", core.RetrievalQuery{Text: "sharedterm", ProjectID: "domain", TopK: 1}, func(d core.KnowledgeDoc) bool { return d.ID == "published" })
|
|
if err != nil || len(hits) != 1 || hits[0].Doc.ID != "published" {
|
|
t.Fatalf("denied rows consumed top-k: %+v %v", hits, err)
|
|
}
|
|
}
|
|
|
|
func TestPluginProjectPublicationDeleteUsesExactScope(t *testing.T) {
|
|
st := openTestStore(t)
|
|
ctx := context.Background()
|
|
docs := []core.KnowledgeDoc{{ID: "unscoped", Owner: "alice", Source: "plugin:rdm", Ref: "same", Chunk: "unscoped"}, {ID: "scoped", Owner: "alice", ProjectID: "domain", Source: "plugin:rdm:published", Ref: "same", Chunk: "scoped"}, {ID: "foreign", Owner: "alice", Source: "plugin:other", Ref: "same", Chunk: "foreign"}, {ID: "other_owner", Owner: "bob", Source: "plugin:rdm", Ref: "same", Chunk: "other owner"}}
|
|
if err := st.AddKnowledge(docs...); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, d := range docs {
|
|
if err := st.UpsertKnowledgeVector(ctx, d.Owner, d.ID, d.Ref, []float32{1, 0}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if err := st.DeletePluginProjectKnowledgeByRef(ctx, "alice", "", "same", "rdm"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, table := range []string{"knowledge", "knowledge_vectors"} {
|
|
var count int
|
|
if err := st.db.QueryRow("SELECT COUNT(*) FROM " + table).Scan(&count); err != nil || count != 3 {
|
|
t.Fatalf("exact empty-project namespace %s count=%d error=%v", table, count, err)
|
|
}
|
|
}
|
|
if err := st.DeletePluginProjectKnowledgeByRef(ctx, "alice", "domain", "same", "rdm"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, id := range []string{"foreign", "other_owner"} {
|
|
var count int
|
|
if err := st.db.QueryRow(st.q(`SELECT COUNT(*) FROM knowledge WHERE id=?`), id).Scan(&count); err != nil || count != 1 {
|
|
t.Fatalf("protected row %s count=%d error=%v", id, count, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPluginPublicationNamespaceIsLiteral(t *testing.T) {
|
|
st := openTestStore(t)
|
|
docs := []core.KnowledgeDoc{{ID: "owned", Owner: "alice", Source: "plugin:rdm_%", Ref: "same", Chunk: "owned"}, {ID: "owned_suffix", Owner: "alice", Source: "plugin:rdm_%:published", Ref: "same", Chunk: "owned suffix"}, {ID: "protected", Owner: "alice", Source: "plugin:rdmXYZ:published", Ref: "same", Chunk: "protected"}}
|
|
if err := st.AddKnowledge(docs...); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := st.DeletePluginProjectKnowledgeByRef(context.Background(), "alice", "", "same", "rdm_%"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var id string
|
|
if err := st.db.QueryRow(`SELECT id FROM knowledge`).Scan(&id); err != nil || id != "protected" {
|
|
t.Fatalf("wildcards broadened namespace: id=%s error=%v", id, err)
|
|
}
|
|
}
|