Repository navigation
Persist user PATCH before publishing it to the live user map - #81
Merged
Merged
Conversation
Call the handler preparation step without touching storage and require the live user to stay unchanged. The targeted test fails on the original implementation: the live email is after@example.com instead of before@example.com (cargo test exit 101). Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
Prepare email changes on a cloned user using value-only insert_email. Keep UPDATE_LOCK across preparation, metadata read/write, and publication; only update the live user map after put_metadata succeeds. Preserve active sessions and the existing validation order and HTTP errors. Validation: three targeted PATCH tests pass; cargo fmt --check and cargo clippy -- -D warnings pass; cargo test --lib -q passes (1024 passed, 2 ignored). Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
Copying the live user into parseable.json also wrote live-only state such as OAuth tokens. The stored entry now gets only the patched email, and the live user is replaced in place, so a user removed concurrently is not recreated. Drops the now unused Users::put_email. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
VibeSWE
commented
Oct 25, 2026
VibeSWE
left a comment
Author
There was a problem hiding this comment.
Adversarial review of PR #81 (at 1b85d00a, fixes in 8fa492a0)
One Sol 6.1 and one Opus 5.5 reviewer. Neither found anything blocking or newly introduced.
Both confirmed:
- Every error path (validation, missing user, API-key user, storage read or write) returns before the live map is touched.
- The HTTP contract and validation order are identical to main.
- Every handler that mutates a live
UserholdsUPDATE_LOCKfrom read to publish, so nothing changes the user between the clone and the publish. - No other handler publishes before persisting.
| Severity | Finding | Outcome |
|---|---|---|
| Medium (pre-existing) | PATCH wrote the whole live user into parseable.json. For a logged-in OAuth user that includes bearer tokens, and it caused an extra metadata write on the next OIDC reconcile |
Fixed: the stored entry now gets only the patched email (UpdateUser::apply) |
| Low | mut_users().insert after an .await could recreate a user removed concurrently (latent: the only unlocked remover has no callers) |
Fixed: new Users::replace_user updates the live user in place and never recreates one; test added |
| Low | Nothing tests that the change is published after a successful persist | Partly covered: replace_user is tested directly. The handler's storage paths can't be reached from tests |
| Low (pre-existing) | A Query-node PATCH is never synced to ingestors | Follow-up: profile changes don't affect authorization |
| Nit | Users::put_email is now unused |
Removed |
Local at 8fa492a0: fmt and clippy -- -D warnings clean; cargo test --lib 1026 passed, 0 failed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up from the #77 review (pre-existing, Medium): user PATCH changed the live user before persisting.
PATCH /user/{userid}(inrbac.rs, shared by the Query and standalone servers) calledUpdateUser::update(). That writes the change, such as the email viaUsers.put_email, into the live map beforeget_metadata/put_metadatarun.Fix:
UPDATE_LOCK.UpdateUser::update()had no other production callers. The ingestor sync handlers are separate.Tests
The preparation step is factored out so it can be tested without storage:
Verification
cargo fmt --check✅,cargo clippy -- -D warnings✅cargo test --lib: 1024 passed, 0 failed, 2 ignored🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.