fix: the move endpoint validates its source path, and two comments say what their branch does

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ruben Fiszel
2026-09-15 20:44:59 +02:00
co-authored by Claude Opus 5
parent 9abd8fa7aa
commit 46817d8a90
3 changed files with 13 additions and 13 deletions
+4 -2
View File
@@ -657,8 +657,10 @@ async fn move_draft(
};
// Validate before authorizing: `require_can_write_path` is not a format check
// (an admin returns immediately, and a user returns early inside their own
// namespace), so without this a malformed destination is stored as-is, and an
// over-long or NUL-bearing one reaches Postgres as a raw server error.
// namespace), so without this a malformed path is stored as-is, and an over-long
// or NUL-bearing one reaches Postgres as a raw server error. The source is a URL
// segment and arrives decoded, so it needs the same check as the destination.
check_proper_path(path)?;
check_proper_path(new_path)?;
// A summary-only edit is a legitimate use of this endpoint: the drawer edits
// both fields, and for a draft-only script the path it posts back is the row
@@ -497,13 +497,10 @@
onOpenOthersDrafts={() => (othersModalOpen = true)}
onDeploy={({ version, head, headBy, headAt }) => {
// The editor stays open across a deploy and pins what it wrote onto the value
// itself; the prompt's own pair is what the loader knows, and this deploy
// consumed the draft it described, so the route holds no base until it loads
// again (the deploy guard covers that window).
// Keep the base the editor just pinned when this deploy is the head: the
// prompt has no draft to describe either way, and the drawer needs it to
// keep offering Take latest. A raced deploy leaves it unknown, since the
// pair would then differ and open the prompt on a draft that is gone.
// itself. Keep that as the prompt's base while this deploy is the head, so
// the pair still describes the draft the next edit starts; a raced deploy
// leaves it unknown, or the pair would differ and open the prompt on the
// draft this deploy consumed.
draftBaseVersion = version != null && version === head ? String(version) : undefined
draftSavedAt = undefined
if (head != null) {
@@ -578,10 +578,11 @@
onDeploy={(e) => {
// "Deploy & Stay here" / lib: stay on the editor (just confirm).
if (e.stay) {
// The editor is now on the version it just wrote, and so is the draft the
// builder re-pinned. Without this the prompt and the drawer keep comparing
// the pre-deploy pair, so Diff offers Take latest against a head the next
// draft is already on.
// `e.hash` is the hash the create call returned, so it names this deploy's own
// version with nothing to attribute (unlike an app, which has to read its
// version back). The builder re-pinned the draft to it, so the pair moves
// here too: otherwise Diff offers Take latest against a head the draft is
// already on.
draftBaseHash = e.hash
deployedHeadHash = e.hash
sendUserToast('Deployed')