oficina / memoria Public

🤖 test: exercise sibling custody across document routes

Known-red regression evidence pending independent design approval. Search control passes; list, document and manual deletion routes reproduce the inherited release finding.
Co-Authored-By: Codex <noreply@openai.com>
Paul Campbell pushed by paul@keymail.dev e4b178f89659694ca36e96bd5ba831fac7454e72 parent 6a1e05b
1 file changed, +150 −0
  • internal/memoriatest/custody_routes_test.go +150 −0

CI failed — run details

diff --git a/internal/memoriatest/custody_routes_test.go b/internal/memoriatest/custody_routes_test.go
new file mode 100644
index 0000000..6e19678
--- /dev/null
+++ b/internal/memoriatest/custody_routes_test.go
@@ -0,0 +1,150 @@
+package memoriatest
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "log/slog"
+ "net/http"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/carlosframework/rastrillo/db"
+
+ memoria "amadan.net/oficina/memoria/internal/memoria"
+ "amadan.net/oficina/memoria/internal/memoria/sibling"
+ "amadan.net/oficina/suite"
+)
+
+type routeCustody struct {
+ answer suite.Authorization
+ asks []suite.Subject
+ pairs []suite.ItemRevision
+}
+
+func (c *routeCustody) Sibling(source string) (sibling.Sibling, bool) {
+ return sibling.Sibling{Name: "Docs"}, source == "Docs"
+}
+
+func (c *routeCustody) Rule(_ context.Context, who suite.Subject, candidates []sibling.Candidate) []sibling.Disposition {
+ c.asks = append(c.asks, who)
+ out := make([]sibling.Disposition, len(candidates))
+ for i, candidate := range candidates {
+ c.pairs = append(c.pairs, candidate.Item)
+ out[i] = sibling.Decide(c.answer)
+ }
+ return out
+}
+
+func custodyRouteApp(t *testing.T, custody memoria.Custody) (http.Handler, *memoria.Store, int64, int64) {
+ t.Helper()
+ logger := slog.New(slog.NewTextHandler(io.Discard, nil))
+ d, err := db.Open(filepath.Join(t.TempDir(), "app.db"), logger)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Cleanup(func() { d.Close() })
+ h, app, err := memoria.AppForTest(d, testOrigin, testDEK(t), logger)
+ if err != nil {
+ t.Fatal(err)
+ }
+ app.AsPerson("reader@example.test")
+ app.UseSiblings(custody)
+ s := app.Store()
+ siblingDoc, err := s.Ingest(context.Background(), memoria.IngestSpec{
+ Source: "Docs", Key: "route-sibling", Title: "SiblingTitleCanary",
+ Body: "## SiblingHeadingCanary\n\nSiblingBodyCanary quarterly planning.",
+ ItemID: "sibling-item-route", SiblingRevision: 19,
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ localDoc, err := s.Ingest(context.Background(), memoria.IngestSpec{
+ Source: "upload", Key: "route-local", Title: "LocalTitleControl",
+ Body: "LocalBodyControl quarterly planning.",
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ return h, s, siblingDoc, localDoc
+}
+
+// Baseline regression evidence: these HTTP routes ingest actual sibling
+// coordinates, while retaining local content as a positive control.
+// Independent reviewer mutations will be recorded after design approval.
+func TestSiblingDocumentHTTPRequiresCustody(t *testing.T) {
+ for _, answer := range []suite.Authorization{suite.NOT_VISIBLE, suite.STALE, suite.UNKNOWN, suite.VISIBLE} {
+ for _, route := range []string{"/", "/?q=quarterly", "/search?q=quarterly", "/documents/%d"} {
+ t.Run(string(answer)+route, func(t *testing.T) {
+ custody := &routeCustody{answer: answer}
+ h, _, id, localID := custodyRouteApp(t, custody)
+ target := route
+ if strings.Contains(route, "%d") {
+ target = fmt.Sprintf(route, id)
+ }
+ r := get(t, h, target)
+ body := r.Body.String()
+ if answer == suite.VISIBLE {
+ if r.Code != http.StatusOK || !strings.Contains(body, "SiblingTitleCanary") {
+ t.Errorf("visible document not rendered: status %d", r.Code)
+ }
+ } else {
+ for _, secret := range []string{"SiblingTitleCanary", "SiblingHeadingCanary", "SiblingBodyCanary"} {
+ if strings.Contains(body, secret) {
+ t.Errorf("unruled sibling field rendered: %s", secret)
+ }
+ }
+ }
+ if len(custody.asks) == 0 {
+ t.Error("route did not obtain custody ruling")
+ }
+ for _, who := range custody.asks {
+ if who.Kind != suite.SubjectAddress || who.Value != "reader@example.test" {
+ t.Errorf("wrong requester: %#v", who)
+ }
+ }
+ for _, pair := range custody.pairs {
+ if pair.ItemID != "sibling-item-route" || pair.Revision != 19 {
+ t.Errorf("wrong source coordinate: %#v", pair)
+ }
+ }
+ if route != "/documents/%d" && !strings.Contains(body, "LocalTitleControl") {
+ t.Error("local list control absent")
+ }
+ local := get(t, h, fmt.Sprintf("/documents/%d", localID))
+ if local.Code != http.StatusOK || !strings.Contains(local.Body.String(), "LocalBodyControl") {
+ t.Error("local document control absent")
+ }
+ })
+ }
+ }
+}
+
+func TestSiblingDocumentHTTPManualDeleteHasNoAuthority(t *testing.T) {
+ custody := &routeCustody{answer: suite.NOT_VISIBLE}
+ h, s, id, localID := custodyRouteApp(t, custody)
+ before, err := s.Count()
+ if err != nil {
+ t.Fatal(err)
+ }
+ r := post(t, h, fmt.Sprintf("/documents/%d/delete", id), nil)
+ if r.Code != http.StatusNotFound {
+ t.Errorf("sibling delete status %d, want404", r.Code)
+ }
+ _, body, err := s.Body(context.Background(), id)
+ if err != nil || !strings.Contains(body, "SiblingBodyCanary") {
+ t.Errorf("sibling document removed: %v", err)
+ }
+ after, err := s.Count()
+ if err != nil || before != after {
+ t.Errorf("index changed on refused deletion: before%d after%d err%v", before, after, err)
+ }
+ local := post(t, h, fmt.Sprintf("/documents/%d/delete", localID), nil)
+ if local.Code != http.StatusSeeOther {
+ t.Errorf("local deletion status%d", local.Code)
+ }
+ if _, _, err := s.Body(context.Background(), localID); err == nil {
+ t.Error("local deletion did not remove row")
+ }
+}