Repository navigation
fix: fail closed when the audit lock cannot be reclaimed - #96
Merged
Merged
Conversation
acquireFileLock's stale-lock branch removed the lock path and continued without checking the deadline. When the path was something os.Remove cannot delete, such as a non-empty directory with an old timestamp, the loop spun forever. The hook then never answered, and Claude Code lets a PreToolUse call through when its command hook times out, so the call ran with no decision and no audit record. Code running as the user could plant such a directory at .nomos/claude-code-hook.jsonl.lock. The deadline now bounds every path through the loop, only a stale regular file is reclaimed (Lstat, so a symlink is never followed or removed), and a lock that cannot be taken fails the write. The hook already exits 2 on an audit write failure, which blocks the call. Found while researching how to keep the hook authoritative against code the agent runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HnquYGTpTSAvnvp7UJTVpv
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.
Problem And Change
Research into keeping the hook authoritative against code the agent runs found a fail-open in the audit writer.
acquireFileLock(internal/audit/filechain.go) treats a lock older than 30 seconds as stale. Its stale-lock branch removed the lock path and thencontinued without checking the deadline. Whenos.Removecannot delete the path, such as a non-empty directory with an old timestamp, the loop spins forever. Then:command,http, ormcp_toolhook doesn't block the tool call")Code running as the user can plant such a directory at
.nomos/claude-code-hook.jsonl.lock. The agent's own tool calls can't, since v0.19.1 protects.nomos/, but a script it runs can.The change:
Lstatis used, so a symlink is never followed or removed.Verification
TestAcquireFileLockFailsClosedOnUnremovableStaleLockplants a non-empty lock directory with an old timestamp.filechain.go, it hangs and fails at its 10-second guard. I reproduced that failure locally, then restored the fix.TestFileChainRecorderFailsOnPlantedLockDirectorychecks the same case end to end throughWriteEvent, which now fails after the 3-second lock timeout.TestFileChainRecorderWaitsForStaleLock, the stale regular-file case, still reclaims the lock.go test ./...passes andgo test -race ./internal/audit ./cmd/nomospasses.go vet ./...,gofmt -l ., andpython3 scripts/check_docs.pyare clean.Compatibility And Docs
fix:title cuts v0.19.2.🤖 Generated with Claude Code
https://claude.ai/code/session_01HnquYGTpTSAvnvp7UJTVpv
Generated by Claude Code