Context
OSSF Best Practices Silver requires build_repeatable: rebuilding from the same source must produce byte-identical output. ContinuousIntegrationBuild is already conditionally set in src/Directory.Build.props:27, and Roslyn's Deterministic flag defaults to true — but that's
not enough today.
What I found
Built Rasp.Core.csproj (Release, CI=true, -p:ContinuousIntegrationBuild=true) three times in a row, clean between each (rm -rf bin obj). Three different SHA-256 hashes for the same net8.0/Rasp.Core.dll:
Build 1: 041306259acc23609b92c8c9d5a62b8dd5af134c344656a1262d4eeaf2d54374
Build 2: 036e82b372176678e5b0ba159cd7130813e6bfd7e0c6178e24f19480050ee3bc
Build 3: d122e783f48165e3bba1530a7049bde6254e8a07bf527016def6955a52330435
File size is identical (67072 bytes) across builds. Byte-diffing two of them shows ~200 differing bytes in two clusters:
- Offset ~0x88: 4 bytes — looks like the PE COFF header
TimeDateStamp field.
- Offset ~0xdac8: 16 bytes with a GUID-like pattern — likely the MVID or the Portable PDB ID in the debug directory.
Possibly relevant
Rasp.Core.csproj applies Rasp.SourceGenerators as an OutputItemType="Analyzer" — worth checking whether generator output ordering/content is stable across runs.
EmbedUntrackedSources / SourceLink is enabled (src/Directory.Build.props) — shouldn't affect tracked files, but worth ruling out.
- MinVer computes the assembly version from git state — worth confirming it's not injecting anything non-deterministic when the working tree has uncommitted changes.
Suggested approach
- Reproduce with
dotnet build -bl (binary log) on two runs and diff the logs for any non-deterministic input (file ordering, embedded paths, timestamps).
- If it's an SDK bug, narrow down to a minimal repro and check/file upstream against dotnet/roslyn or dotnet/sdk.
- Once fixed, verify with a script that builds twice and compares SHA-256, and consider wiring that check into CI as a regression guard.
Context
OSSF Best Practices Silver requires
build_repeatable: rebuilding from the same source must produce byte-identical output.ContinuousIntegrationBuildis already conditionally set in src/Directory.Build.props:27, and Roslyn'sDeterministicflag defaults totrue— but that'snot enough today.
What I found
Built
Rasp.Core.csproj(Release,CI=true,-p:ContinuousIntegrationBuild=true) three times in a row, clean between each (rm -rf bin obj). Three different SHA-256 hashes for the samenet8.0/Rasp.Core.dll:File size is identical (67072 bytes) across builds. Byte-diffing two of them shows ~200 differing bytes in two clusters:
TimeDateStampfield.Possibly relevant
Rasp.Core.csprojappliesRasp.SourceGeneratorsas anOutputItemType="Analyzer"— worth checking whether generator output ordering/content is stable across runs.EmbedUntrackedSources/ SourceLink is enabled (src/Directory.Build.props) — shouldn't affect tracked files, but worth ruling out.Suggested approach
dotnet build -bl(binary log) on two runs and diff the logs for any non-deterministic input (file ordering, embedded paths, timestamps).