mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-19 16:54:15 +00:00
201 lines
5.7 KiB
Go
201 lines
5.7 KiB
Go
package labeler
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
comatproto "github.com/bluesky-social/indigo/api/atproto"
|
|
)
|
|
|
|
// stubPurger captures purge calls so we can assert what the subscriber routed.
|
|
type stubPurger struct {
|
|
mu sync.Mutex
|
|
manifestCalls []string
|
|
userLevelCalls []string
|
|
purgeManifestErr error
|
|
purgeUserError error
|
|
manifestOutcome PurgeOutcome
|
|
userLevelOutcome PurgeOutcome
|
|
}
|
|
|
|
func (s *stubPurger) PurgeManifestRecords(_ context.Context, uri string) (PurgeOutcome, error) {
|
|
s.mu.Lock()
|
|
s.manifestCalls = append(s.manifestCalls, uri)
|
|
s.mu.Unlock()
|
|
return s.manifestOutcome, s.purgeManifestErr
|
|
}
|
|
|
|
func (s *stubPurger) PurgeUserManifests(_ context.Context, did string) (PurgeOutcome, error) {
|
|
s.mu.Lock()
|
|
s.userLevelCalls = append(s.userLevelCalls, did)
|
|
s.mu.Unlock()
|
|
return s.userLevelOutcome, s.purgeUserError
|
|
}
|
|
|
|
func (s *stubPurger) snapshot() (manifests, users []string) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
return append([]string(nil), s.manifestCalls...), append([]string(nil), s.userLevelCalls...)
|
|
}
|
|
|
|
func TestApplyLabelManifestTakedownPurges(t *testing.T) {
|
|
cache := newTestCache(t)
|
|
purger := &stubPurger{}
|
|
// Use a did:web identifier directly so we control exactly what Src must
|
|
// match — derived URL is https://labeler.example.com.
|
|
sub := NewSubscriber("did:web:labeler.example.com", cache, purger)
|
|
|
|
uri := "at://did:plc:alice/io.atcr.manifest/abc"
|
|
cts := time.Now().UTC().Format(time.RFC3339)
|
|
|
|
sub.applyLabel(1, &comatproto.LabelDefs_Label{
|
|
Src: "did:web:labeler.example.com",
|
|
Uri: uri,
|
|
Val: TakedownLabelValue,
|
|
Cts: cts,
|
|
})
|
|
|
|
manifests, users := purger.snapshot()
|
|
if len(manifests) != 1 || manifests[0] != uri {
|
|
t.Fatalf("manifest purges = %v, want [%q]", manifests, uri)
|
|
}
|
|
if len(users) != 0 {
|
|
t.Fatalf("expected no user-level purges, got %v", users)
|
|
}
|
|
if _, ok := cache.IsTakenDown(uri); !ok {
|
|
t.Fatalf("cache should record the takedown")
|
|
}
|
|
}
|
|
|
|
func TestApplyLabelUserLevelTakedownPurgesAllManifests(t *testing.T) {
|
|
cache := newTestCache(t)
|
|
purger := &stubPurger{}
|
|
sub := NewSubscriber("did:web:labeler.example.com", cache, purger)
|
|
|
|
uri := "at://did:plc:alice"
|
|
sub.applyLabel(1, &comatproto.LabelDefs_Label{
|
|
Src: "did:web:labeler.example.com",
|
|
Uri: uri,
|
|
Val: TakedownLabelValue,
|
|
Cts: time.Now().UTC().Format(time.RFC3339),
|
|
})
|
|
|
|
manifests, users := purger.snapshot()
|
|
if len(users) != 1 || users[0] != "did:plc:alice" {
|
|
t.Fatalf("user-level purges = %v, want [did:plc:alice]", users)
|
|
}
|
|
if len(manifests) != 0 {
|
|
t.Fatalf("expected no per-manifest purges, got %v", manifests)
|
|
}
|
|
if _, ok := cache.IsTakenDown("at://did:plc:alice/io.atcr.manifest/anything"); !ok {
|
|
t.Fatalf("user-level entry should mask any manifest URI for that DID")
|
|
}
|
|
}
|
|
|
|
func TestApplyLabelNegationDropsCacheNoPurge(t *testing.T) {
|
|
cache := newTestCache(t)
|
|
uri := "at://did:plc:alice/io.atcr.manifest/abc"
|
|
if err := cache.Set(uri, "did:web:labeler.example.com", time.Now()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
purger := &stubPurger{}
|
|
sub := NewSubscriber("did:web:labeler.example.com", cache, purger)
|
|
|
|
sub.applyLabel(2, &comatproto.LabelDefs_Label{
|
|
Src: "did:web:labeler.example.com",
|
|
Uri: uri,
|
|
Val: TakedownLabelValue,
|
|
Neg: new(true),
|
|
Cts: time.Now().UTC().Format(time.RFC3339),
|
|
})
|
|
|
|
if _, ok := cache.IsTakenDown(uri); ok {
|
|
t.Fatalf("negation should drop the takedown from cache")
|
|
}
|
|
manifests, _ := purger.snapshot()
|
|
if len(manifests) != 0 {
|
|
t.Fatalf("negation must not trigger purge, got %v", manifests)
|
|
}
|
|
}
|
|
|
|
func TestApplyLabelIgnoresUntrustedSource(t *testing.T) {
|
|
cache := newTestCache(t)
|
|
purger := &stubPurger{}
|
|
// Subscriber is configured for did:web:operator; a label whose Src is a
|
|
// different DID must be ignored (today's single-DID trust model).
|
|
sub := NewSubscriber("did:web:operator", cache, purger)
|
|
|
|
sub.applyLabel(1, &comatproto.LabelDefs_Label{
|
|
Src: "did:web:rogue",
|
|
Uri: "at://did:plc:alice/io.atcr.manifest/abc",
|
|
Val: TakedownLabelValue,
|
|
Cts: time.Now().UTC().Format(time.RFC3339),
|
|
})
|
|
|
|
manifests, users := purger.snapshot()
|
|
if len(manifests) != 0 || len(users) != 0 {
|
|
t.Fatalf("untrusted source must not trigger purge: manifests=%v users=%v", manifests, users)
|
|
}
|
|
}
|
|
|
|
func TestSubscriberStoresDID(t *testing.T) {
|
|
tests := []string{
|
|
"did:web:labeler.atcr.io",
|
|
"did:web:172.28.0.4%3A5002",
|
|
"did:plc:4zul2zfigjltl24ti24xj3hy",
|
|
}
|
|
for _, did := range tests {
|
|
t.Run(did, func(t *testing.T) {
|
|
sub := NewSubscriber(did, nil, nil)
|
|
if sub.labelerDID != did {
|
|
t.Errorf("labelerDID = %q, want %q", sub.labelerDID, did)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestApplyLabelIgnoresNonTakedownValues(t *testing.T) {
|
|
cache := newTestCache(t)
|
|
purger := &stubPurger{}
|
|
sub := NewSubscriber("did:web:labeler.example.com", cache, purger)
|
|
|
|
sub.applyLabel(1, &comatproto.LabelDefs_Label{
|
|
Src: "did:web:labeler.example.com",
|
|
Uri: "at://did:plc:alice/io.atcr.manifest/abc",
|
|
Val: "spam",
|
|
Cts: time.Now().UTC().Format(time.RFC3339),
|
|
})
|
|
|
|
manifests, users := purger.snapshot()
|
|
if len(manifests) != 0 || len(users) != 0 {
|
|
t.Fatalf("non-takedown labels must not trigger purge: manifests=%v users=%v", manifests, users)
|
|
}
|
|
}
|
|
|
|
func TestClassifyURI(t *testing.T) {
|
|
tests := []struct {
|
|
uri string
|
|
kind uriKind
|
|
did string
|
|
}{
|
|
{"at://did:plc:alice/io.atcr.manifest/abc", uriKindManifest, "did:plc:alice"},
|
|
{"at://did:plc:alice", uriKindUser, "did:plc:alice"},
|
|
{"at://did:plc:alice/io.atcr.repo/myimage", uriKindOther, "did:plc:alice"},
|
|
{"https://example.com", uriKindOther, ""},
|
|
{"", uriKindOther, ""},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.uri, func(t *testing.T) {
|
|
got := classifyURI(tt.uri)
|
|
if got.Kind != tt.kind {
|
|
t.Fatalf("kind = %s, want %s", got.Kind, tt.kind)
|
|
}
|
|
if got.DID != tt.did {
|
|
t.Fatalf("did = %s, want %s", got.DID, tt.did)
|
|
}
|
|
})
|
|
}
|
|
}
|