Skip to content

Managed builds are not bit-for-bit reproducible (blocks OSSF Silver's build_repeatable) #61

Description

@JVBotelho

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

  1. Reproduce with dotnet build -bl (binary log) on two runs and diff the logs for any non-deterministic input (file ordering, embedded paths, timestamps).
  2. If it's an SDK bug, narrow down to a minimal repro and check/file upstream against dotnet/roslyn or dotnet/sdk.
  3. Once fixed, verify with a script that builds twice and compares SHA-256, and consider wiring that check into CI as a regression guard.

Metadata

Metadata

Assignees

No one assigned

    Labels

    .NETPull requests that update .NET codehelp wantedExtra attention is needed

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions