diff --git a/spindle/ingester.go b/spindle/ingester.go index 7f5fcefc..a5e5a0ed 100644 --- a/spindle/ingester.go +++ b/spindle/ingester.go @@ -21,6 +21,9 @@ type Ingester func(ctx context.Context, e *models.Event) error func (s *Spindle) ingest() Ingester { return func(ctx context.Context, e *models.Event) error { + if e.Kind == models.EventKindAccount { + return s.ingestAccount(ctx, e) + } if e.Kind != models.EventKindCommit { return nil } @@ -287,3 +290,19 @@ func (s *Spindle) ingestMember(ctx context.Context, e *models.Event) error { } return nil } + +func (s *Spindle) ingestAccount(ctx context.Context, e *models.Event) error { + if e.Account == nil || e.Account.Active { + return nil + } + status := "unknown" + if e.Account.Status != nil { + status = *e.Account.Status + } + did, err := syntax.ParseDID(e.Account.Did) + if err != nil { + return fmt.Errorf("parsing account did: %w", err) + } + s.l.Warn("account went inactive, purging its repos", "did", did, "status", status) + return s.WipeOwner(ctx, did, "account "+status) +} diff --git a/spindle/wipe_test.go b/spindle/wipe_test.go index 80eab1a1..70e23166 100644 --- a/spindle/wipe_test.go +++ b/spindle/wipe_test.go @@ -7,7 +7,9 @@ import ( "path/filepath" "testing" + comatproto "github.com/bluesky-social/indigo/api/atproto" "github.com/bluesky-social/indigo/atproto/syntax" + jmodels "github.com/bluesky-social/jetstream/pkg/models" "tangled.org/core/api/tangled" "tangled.org/core/jetstream" "tangled.org/core/log" @@ -298,4 +300,43 @@ func TestWipeOwnerWipesAllOwnedRepos(t *testing.T) { func ptr[T any](v T) *T { return &v } +func TestIngestAccountTakedownWipes(t *testing.T) { + s := newWipeTestSpindle(t) + owner := syntax.DID("did:plc:owner1") + + seedWipeRepo(t, s, "did:plc:repo1", owner) + + status := "takendown" + err := s.ingest()(context.Background(), &jmodels.Event{ + Kind: jmodels.EventKindAccount, + Did: owner.String(), + Account: &comatproto.SyncSubscribeRepos_Account{Did: owner.String(), Active: false, Status: &status}, + }) + if err != nil { + t.Fatalf("ingest account event: %v", err) + } + + var n int + if err := s.db.QueryRow(`select count(*) from repos`).Scan(&n); err != nil { + t.Fatal(err) + } + if n != 0 { + t.Fatalf("expected repos wiped after takedown, got %d", n) + } + seedWipeRepo(t, s, "did:plc:repo1", owner) + err = s.ingest()(context.Background(), &jmodels.Event{ + Kind: jmodels.EventKindAccount, + Did: owner.String(), + Account: &comatproto.SyncSubscribeRepos_Account{Did: owner.String(), Active: true}, + }) + if err != nil { + t.Fatal(err) + } + if err := s.db.QueryRow(`select count(*) from repos`).Scan(&n); err != nil { + t.Fatal(err) + } + if n != 1 { + t.Fatalf("expected active account untouched, got %d", n) + } +}