From b907bf93ec36e1fab5eee9365ba85922e89a5d2f Mon Sep 17 00:00:00 2001 From: kppcn.tngl.sh Date: Wed, 08 Apr 2026 06:57:31 +0000 Subject: [PATCH] knotserver/xrpc: defer plc submission until repo setup succeeds Previously, CreateRepo submitted the PLC DID before the remaining local setup steps had completed. If RBAC setup or hook installation failed after that point, the handler cleaned up local state but still left behind a published DID with no corresponding repo on disk. Move PLC submission to the end of the create flow so the DID is only published after local repo setup succeeds. Also roll back repo RBAC state during cleanup, and treat hook setup failure as fatal instead of silently continuing. --- knotserver/xrpc/create_repo.go | 46 +++++++++++++++++++++++++++++----------------- 1 file(s) changed, 29 insertion(s)(+), 17 deletion(s)(-) diff --git a/knotserver/xrpc/create_repo.go b/knotserver/xrpc/create_repo.go --- a/knotserver/xrpc/create_repo.go +++ b/knotserver/xrpc/create_repo.go @@ -145,6 +145,7 @@ repoPath, _ := securejoin.SecureJoin(h.Config.Repo.ScanPath, repoDid) rbacPath := repoDid + repoAddedToRBAC := false cleanup := func() { if rmErr := os.RemoveAll(repoPath); rmErr != nil { @@ -153,6 +154,11 @@ } cleanupAll := func() { + if repoAddedToRBAC { + if rmErr := h.Enforcer.RemoveRepo(actorDid.String(), rbac.ThisServer, rbacPath); rmErr != nil { + l.Error("failed to clean up repo permissions", "error", rmErr.Error()) + } + } cleanup() if delErr := h.Db.DeleteRepoKey(repoDid); delErr != nil { l.Error("failed to clean up repo key", "error", delErr.Error()) @@ -195,6 +201,29 @@ } } + // add perms for this user to access the repo + err = h.Enforcer.AddRepo(actorDid.String(), rbac.ThisServer, rbacPath) + if err != nil { + l.Error("adding repo permissions", "error", err.Error()) + cleanupAll() + writeError(w, xrpcerr.GenericError(err), http.StatusInternalServerError) + return + } + repoAddedToRBAC = true + + if err := hook.SetupRepo( + hook.Config( + hook.WithScanPath(h.Config.Repo.ScanPath), + hook.WithInternalApi(h.Config.Server.InternalListenAddr), + ), + repoPath, + ); err != nil { + l.Error("setting up repo hooks", "error", err.Error()) + cleanupAll() + writeError(w, xrpcerr.GenericError(err), http.StatusInternalServerError) + return + } + if prepared != nil { plcCtx, plcCancel := context.WithTimeout(context.Background(), 30*time.Second) defer plcCancel() @@ -205,23 +234,6 @@ return } } - - // add perms for this user to access the repo - err = h.Enforcer.AddRepo(actorDid.String(), rbac.ThisServer, rbacPath) - if err != nil { - l.Error("adding repo permissions", "error", err.Error()) - cleanupAll() - writeError(w, xrpcerr.GenericError(err), http.StatusInternalServerError) - return - } - - hook.SetupRepo( - hook.Config( - hook.WithScanPath(h.Config.Repo.ScanPath), - hook.WithInternalApi(h.Config.Server.InternalListenAddr), - ), - repoPath, - ) // HACK: request crawl for this repository // Users won't want to sync entire network from their local knotmirror. -- tangled.sh