fix(mcp-oauth): keep the refresh-fence sidecar when removing token state

flock is bound to an inode, not a path. Unlinking `<srv>.json.refresh.lock`
from `remove()` while a peer still holds the fence lets the next acquirer
open and lock a brand-new inode, so two processes hold "the" fence at once
and the single-use refresh token can be consumed twice. On Windows the unlink
of a locked file raises PermissionError straight out of `remove()`/`restore()`.

A 0-byte 0600 sidecar in a 0700 directory is harmless, so leave it in place.
It stays out of `_state_paths()` so `restore(only_if_absent=True)` still keys
off real token state only.
This commit is contained in:
kshitijk4poor
2026-09-15 00:56:29 +05:30
committed by kshitij
parent 60262f71bd
commit 2e89c5da48

View File

@@ -566,7 +566,9 @@ class HermesTokenStorage:
def remove(self) -> None:
"""Delete all stored OAuth state for this server."""
for p in (*self._state_paths(), self._cimd_rejected_path(), _refresh_lock_path(self._tokens_path())):
# The ``.refresh.lock`` sidecar is deliberately kept: flock is inode-bound, so unlinking it
# while a peer holds the fence would let the next acquirer lock a fresh inode (two holders).
for p in (*self._state_paths(), self._cimd_rejected_path()):
p.unlink(missing_ok=True)
def snapshot(self) -> dict[str, bytes]: