From 02499287483bb9c8910f3263e83f0706cd797fcd Mon Sep 17 00:00:00 2001 From: Eli Mallon Date: Thu, 1 Oct 2026 17:11:17 -0700 Subject: [PATCH] auto-vod: preserve commit watermark when consent deletion fails --- js/e2e-web/README.md | 3 ++- pkg/atproto/auto_publish_vod_test.go | 23 ++++++++++++++++++++++- pkg/atproto/firehose.go | 1 + 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/js/e2e-web/README.md b/js/e2e-web/README.md index 092e56e6e..5002fe3f0 100644 --- a/js/e2e-web/README.md +++ b/js/e2e-web/README.md @@ -61,7 +61,8 @@ accepting an unseen tap. then holds a recording opt-out request to verify another privacy toggle cannot overwrite it while saving. Deleting the node's settings record also withdraws automatic publishing consent; the PDS-backed regression for that index deletion -lives in `pkg/atproto/auto_publish_vod_test.go`. +lives in `pkg/atproto/auto_publish_vod_test.go`. It also injects a deletion failure +and checks that the commit watermark advances only after successful reprocessing. ## OAuth over real HTTPS diff --git a/pkg/atproto/auto_publish_vod_test.go b/pkg/atproto/auto_publish_vod_test.go index 6127e5ccf..09bc75b7f 100644 --- a/pkg/atproto/auto_publish_vod_test.go +++ b/pkg/atproto/auto_publish_vod_test.go @@ -3,16 +3,19 @@ package atproto import ( "bytes" "context" + "errors" "testing" "time" indigoatproto "github.com/bluesky-social/indigo/api/atproto" "github.com/bluesky-social/indigo/atproto/syntax" "github.com/stretchr/testify/require" + "gorm.io/gorm" "stream.place/streamplace/pkg/comatproto" "stream.place/streamplace/pkg/devenv" "stream.place/streamplace/pkg/model" "stream.place/streamplace/pkg/placestream" + "stream.place/streamplace/pkg/reposync" "stream.place/streamplace/pkg/spid" "stream.place/streamplace/pkg/statedb" ) @@ -126,13 +129,31 @@ func TestDeletedServerSettingsWithdrawAutoPublishConsent(t *testing.T) { require.NoError(t, err) blocks, err := comatproto.SyncGetRepo(ctx, user.XRPC, user.DID, "") require.NoError(t, err) + before, err := mod.GetRepo(user.DID) + require.NoError(t, err) evt := &indigoatproto.SyncSubscribeRepos_Commit{ Repo: user.DID, Time: time.Now().UTC().Format(time.RFC3339), Blocks: blocks, + Since: &before.Version, Rev: reposync.TIDForTime(time.Now().Add(time.Hour)), Ops: []*indigoatproto.SyncSubscribeRepos_RepoOp{ repoOp("delete", "place.stream.server.settings/"+atsync.CLI.BroadcasterHost), }, } - require.True(t, atsync.handleIndexedOps(ctx, evt)) + db := mod.(*model.DBModel).DB + require.NoError(t, db.Callback().Delete().Before("gorm:delete").Register("fail_settings_delete", func(tx *gorm.DB) { + tx.Error = errors.New("settings deletion unavailable") + })) + t.Cleanup(func() { + require.NoError(t, db.Callback().Delete().Remove("fail_settings_delete")) + }) + atsync.handleCommitEventOps(ctx, evt) + after, err := mod.GetRepo(user.DID) + require.NoError(t, err) + require.Equal(t, before.Version, after.Version, "a failed consent deletion must not advance the commit watermark") + require.NoError(t, db.Callback().Delete().Remove("fail_settings_delete")) + atsync.handleCommitEventOps(ctx, evt) + after, err = mod.GetRepo(user.DID) + require.NoError(t, err) + require.Equal(t, evt.Rev, after.Version, "successful reprocessing can advance the watermark") settings, err = mod.GetServerSettings(ctx, atsync.CLI.BroadcasterHost, user.DID) require.NoError(t, err) require.Nil(t, settings, "deleting the record must withdraw indexed consent") diff --git a/pkg/atproto/firehose.go b/pkg/atproto/firehose.go index 3de213c58..4cfa1a999 100644 --- a/pkg/atproto/firehose.go +++ b/pkg/atproto/firehose.go @@ -685,6 +685,7 @@ func (atsync *ATProtoSynchronizer) handleIndexedOps(ctx context.Context, evt *in if collection.String() == constants.PLACE_STREAM_SERVER_SETTINGS { if err := atsync.Model.DeleteServerSettings(ctx, rkey.String(), evt.Repo); err != nil { log.Error(ctx, "failed to delete server settings", "err", err) + return false } } -- knotmirror 0.0.1