Repository navigation
PATCH user managed=false: implicitly unlock + reconcile - #27
Merged
Merged
Conversation
Enforce the invariant that an unmanaged user is never locked at the DB
level. When PATCH /v1/users/{user} flips ``managed`` to false on a
currently-locked user, clear ``manual_lock`` first, audit a
``user.unlock`` row with ``reason: managed_to_unmanaged`` (so the trail
reads unlock-then-update), and schedule a plugin reconcile so external
state (smart plugs, DNS sinkhole, etc.) follows the unlocked state. The
reverse direction (``managed=true``) is left as a pure flag flip — the
operator chose to manage; we don't auto-anything.
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
/v1/users/{user}withmanaged: falseon a currently-locked user clearsmanual_lock, auditsuser.unlockwithpayload={"reason": "managed_to_unmanaged"}, and dispatches a plugin reconcile viaBackgroundTasksso external state (smart plug, DNS sinkhole, etc.) follows.user.unlockthenuser.updateso the operator can read the trail as "unlocked them as part of unmanaging them".managed: true) is unchanged — pure flag flip, no auto-lock, no auto-anything. Operator chose to manage; we don't decide for them.managed=truedoesn't touch a stale lock row.Test plan
just checkclean (254 Python tests + 23 web tests + lint + mypy + build)managed: false, confirm/statusreports unlocked, audit log showsuser.unlockthenuser.update, and reftest plugin sentinel cleared if assigned