domain: frozen-slug invariant not enforced in update_post, web editor can rename a live permalink #55

Open
opened 2026-07-03 01:41:45 +00:00 by rosa · 0 comments
Owner

Found during a code review of the domain crate.

Location: crates/domain/src/services.rs:920 (update_post); invariant in CONTEXT.md and crates/domain/src/models/post.rs:505
Severity: Correctness — documented invariant bypassed

Problem

CONTEXT.md and the PostEdit doc state the slug is frozen once set. Only the Micropub path enforces it (by copying the old slug); update_post never checks edit.slug == old_post.slug(), and the web edit form builds PostEdit from a user-editable slug field, so a web edit silently renames a live post permalink.

Failure scenario

A user edits a published post in the web editor and changes the slug. update_post writes the new slug, so every external link, feed entry, and previously-sent webmention source pointing at the old permalink now 404s.

Suggested fix

Either drop slug from PostEdit (derive it from the loaded post) or reject edit.slug != old_post.slug() in update_post. If renaming is actually intended, update the domain docs and model it explicitly. Note: the doc comment cites ADR-0004, but ADR-0004 does not mention slugs — fix that citation too.

Found during a code review of the `domain` crate. **Location:** `crates/domain/src/services.rs:920` (`update_post`); invariant in `CONTEXT.md` and `crates/domain/src/models/post.rs:505` **Severity:** Correctness — documented invariant bypassed ## Problem CONTEXT.md and the `PostEdit` doc state the slug is frozen once set. Only the Micropub path enforces it (by copying the old slug); `update_post` never checks `edit.slug == old_post.slug()`, and the web edit form builds `PostEdit` from a user-editable slug field, so a web edit silently renames a live post permalink. ## Failure scenario A user edits a published post in the web editor and changes the slug. `update_post` writes the new slug, so every external link, feed entry, and previously-sent webmention source pointing at the old permalink now 404s. ## Suggested fix Either drop `slug` from `PostEdit` (derive it from the loaded post) or reject `edit.slug != old_post.slug()` in `update_post`. If renaming is actually intended, update the domain docs and model it explicitly. Note: the doc comment cites ADR-0004, but ADR-0004 does not mention slugs — fix that citation too.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
rosa/vernier#55
No description provided.