fix: harden Windows file-backed locking - #19
Open
mangod12 wants to merge 1 commit into
Open
Conversation
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.
What & why
This fixes a Windows-specific gap in Delego's documented file-backed consistency class.
Relevant spec sections:
spec.md§5, Consistency class:rate_limitexactness depends on a serialized single-writer audit ledger, and implementations MUST document which consistency class they provide.spec.md§11, Concurrency: a single logical chain has one writer at a time; concurrent appenders can fork the chain, so the implementation must be clear about its concurrency guarantees.Delego documents that, without the daemon, file-backed ledger and approval writes are serialized by an OS file lock and are corruption-safe for writers sharing one home on one host. On Windows, the implementation did not reliably provide that behavior.
The Windows lock path used
msvcrt.locking()directly. Under threaded contention,msvcrt.locking(fd, LK_LOCK, 1)can raiseOSError: [Errno 36] Resource deadlock avoided;file_lock()then still attempted_release(fd)even though the lock was never acquired, causingPermissionErrorand aborting the write. In practice, concurrent audit appends and approval creates could be dropped instead of serialized.There was a second Windows fallback issue: CLI
approve/deny/pendingprobe for a daemon before using file-backed state, but daemon probing touchedsocket.AF_UNIXunconditionally. On Windows this crashed before the intended file-backed fallback could run.What changed
file_lock()now serializes same-process threads before taking themsvcrtbyte lock.daemon_running()returnsFalseon platforms without Unix domain sockets, allowing CLI commands to fall back to direct file-backed handling.socket.AF_UNIX.This restores the documented file-backed write-integrity behavior. It does not change the protocol or normative authorization semantics.
Reproduction
On Windows / Python 3.12 before this fix:
Observed failures included:
test_concurrent_appends_keep_chain_valid: expected 25 audit receipts, fewer were present.test_concurrent_approval_creates_are_intact: expected 25 approval records, fewer were present.test_approve_echoes_what_was_approved: crashed withAttributeError("module 'socket' has no attribute 'AF_UNIX'").AI assistance disclosure (required)
Checklist
pytestpasses locally.python examples/demo.pystill shows all eight scenarios + tamper detection.README.mdandCHANGELOG.mdfor any behaviour change.CONTRIBUTING.md/ARCHITECTURE.md):no LLM in the authorization path; no credential custody; fail-closed; approvals
bound to fingerprint + intent and single-use; append-only signed audit chain;
fixed evaluation order.
Protocol / spec impact
and its CTK vectors are updated (or a linked spec PR does so), and
__protocol_version__stays <= the spec version.Local verification
python -m pytest -q-> 67 passed, 7 skipped (daemon tests skipped on Windows: Unix domain sockets unavailable)python examples/demo.py-> all 8 scenarios passed, including tamper detectionpython -m pytest tests/test_cli.py tests/test_concurrency.py -q-> 9 passedpython -m pytest tests/test_concurrency.py -q8 times -> 5 passed each runpython -m compileall -q delego tests-> passedpython conformance.py-> passedpython validate.py-> passed