Skip to content

fix: make plugin hashes reproducible so the fork-PR verify gate can pass - #674

Merged
Hirogen merged 1 commit into
Developmentfrom
fix/deterministic-plugin-hashes
Jul 28, 2026
Merged

fix: make plugin hashes reproducible so the fork-PR verify gate can pass#674
Hirogen merged 1 commit into
Developmentfrom
fix/deterministic-plugin-hashes

Conversation

@Hirogen

Copy link
Copy Markdown
Collaborator

The Verify Plugin Hashes (fork PRs) step in build_dotnet.yml regenerates PluginHashGenerator.Generated.cs and runs git diff --exit-code on it. That gate could never pass, for two independent reasons.

First, the generator embedded DateTime.UtcNow in the file, so every regeneration produced a diff even when no hash had changed.

Second, the SDK queries git and feeds the commit sha into every assembly by two routes: appended to InformationalVersion, and into the SourceLink map in the portable PDB, whose checksum is embedded in the DLL. So the hashes you commit describe the parent commit's binaries and go stale the instant they land - committing them changes HEAD, which changes the binaries again. Only first-party assemblies moved; the NuGet-supplied DLLs alongside them never did.

That made the gate unwinnable rather than merely awkward: PR #673 burned two attempts re-pasting hashes, and every push produced a different set again.

On Development the same churn was absorbed by the sibling auto-commit step, which is why chore: update plugin hashes [skip ci] landed after nearly every merge. It also meant the committed table always described a different build than the one it shipped in, so Release plugin verification never matched its own binaries.

Drop the timestamp, stop the SDK's source-control queries, and regenerate. Verified: two clean Release builds at different commits now produce identical plugin hashes, and git diff --exit-code on the generated file is clean.

The `Verify Plugin Hashes (fork PRs)` step in build_dotnet.yml regenerates
PluginHashGenerator.Generated.cs and runs `git diff --exit-code` on it. That
gate could never pass, for two independent reasons.
First, the generator embedded `DateTime.UtcNow` in the file, so every
regeneration produced a diff even when no hash had changed.
Second, the SDK queries git and feeds the commit sha into every assembly by two
routes: appended to InformationalVersion, and into the SourceLink map in the
portable PDB, whose checksum is embedded in the DLL. So the hashes you commit
describe the parent commit's binaries and go stale the instant they land -
committing them changes HEAD, which changes the binaries again. Only
first-party assemblies moved; the NuGet-supplied DLLs alongside them never did.
That made the gate unwinnable rather than merely awkward: PR #673 burned two
attempts re-pasting hashes, and every push produced a different set again.
On Development the same churn was absorbed by the sibling auto-commit step,
which is why `chore: update plugin hashes [skip ci]` landed after nearly every
merge. It also meant the committed table always described a different build
than the one it shipped in, so Release plugin verification never matched its
own binaries.
Drop the timestamp, stop the SDK's source-control queries, and regenerate.
Verified: two clean Release builds at different commits now produce identical
plugin hashes, and `git diff --exit-code` on the generated file is clean.
@Hirogen
Hirogen merged commit 5e5cf3c into DevelopmentJul 28, 2026
1 check passed
@Hirogen
Hirogen deleted the fix/deterministic-plugin-hashes branch July 28, 2026 10:34
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Hirogen