Hash the hook with normalized line endings: CRLF checkouts attested as edited (0.22.0) - #39
Merged
Merged
Conversation
…s edited (0.22.0) Two Windows installs of 0.21.0 on 2026-09-17 reported different hook hashes for the same unmodified bin/govern.mjs. The first (LF) seeded the registry's first-seen hash; the second, whose Git for Windows had the default core.autocrlf=true and checked the file out as CRLF, was flagged hook.attestation.hash_mismatch and paged the founder for an edit that never happened. Verified byte for byte: sha256 of the LF file is the registry value, sha256 of the same file with CRLF is the reported one. The hook now strips CRLF to LF before hashing itself (byte-transparent latin1 round trip, so an LF file hashes exactly as before and no existing first-seen hash changes). lib/attestation.mjs carries the same normalizeEol so the tests pin it. A .gitattributes pins eol=lf so future checkouts do not convert in the first place. Tests: unit (CRLF == LF, LF unchanged, lone CR kept) and end to end (a CRLF copy of the real hook, run at SessionStart against a stub gateway, reports the LF hash).
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 happened
Two Windows installs of 0.21.0 on 2026-09-17 reported different hook hashes for the same unmodified
bin/govern.mjs. The first (LF) seeded the registry's first-seen hash for 0.21.0. The second machine had Git for Windows at its defaultcore.autocrlf=true, checked the file out as CRLF, and was flaggedhook.attestation.hash_mismatchat its first session start, with a founder page for an edit that never happened.Verified byte for byte against
origin/main:bin/govern.mjs, LFcedbe165…= registry first-seen for 0.21.0d4c90fe1…= the flagged machine's reported hashEvery default-settings Windows install of every version attests as an edited hook unless it happens to be the first machine seen for that version. The trust-on-first-use baseline is set by whichever OS attests first.
Change
bin/govern.mjs:sha256FileHexstrips CRLF to LF before hashing. Byte-transparent latin1 round trip, so an LF file hashes exactly as before and no existing first-seen hash changes. Lone CRs are kept.lib/attestation.mjs:normalizeEolandsha256FileHexmirror the inline logic so the tests pin it..gitattributes:eol=lffor every text file, so future checkouts do not convert in the first place.plugin.json,.claude-plugin/marketplace.json,PLUGIN_VERSION.Tests
SessionStartagainst a stub gateway, reports the LF release hash, and the lib copy agrees with the inline copy.node --checkandvalidate-manifestclean.After merge
platformHookRegistry/claude-code-plugin.latestto0.22.0so 0.21.0 machines get the stale-hook notice.