Skip to content

Feat/001 reproducible build timestamp - #2

Open
hendrikebbers wants to merge 10 commits into
mainfrom
feat/001-reproducible-build-timestamp
Open

Feat/001 reproducible build timestamp#2
hendrikebbers wants to merge 10 commits into
mainfrom
feat/001-reproducible-build-timestamp

Conversation

@hendrikebbers

Copy link
Copy Markdown
Contributor

This pull request implements and documents reproducible builds for all Java projects inheriting from this parent POM. The main change is to fix the project.build.outputTimestamp property as a literal in the parent pom.xml, maintained by release.sh for each release. This ensures that any third party can rebuild artifacts from a release tag and obtain byte-identical results, without needing insider knowledge or special build flags. The release and snapshot workflows are updated to remove timestamp overrides, and comprehensive documentation is added to the README and specs.

Reproducible Build Infrastructure:

  • Added <project.build.outputTimestamp> as a fixed property in the parent pom.xml, with detailed comments explaining its purpose, inheritance, and maintenance by release.sh (pom.xml).
  • Updated release.sh to automatically set and verify the timestamp property to the release date before building artifacts, aborting if the property is not correctly set. Also clarified that the timestamp is not updated for snapshot bumps, and added comments for clarity (release.sh). [1] [2]

CI Workflow Updates:

  • Removed all command-line overrides of project.build.outputTimestamp from both the release and snapshot GitHub Actions workflows, ensuring the build process matches what is documented for external users (.github/workflows/release.yml, .github/workflows/snapshot.yml). [1] [2]

Documentation Improvements:

  • Added a comprehensive "Reproducible builds" section to the README.md, describing the guarantees, verification process, limitations, and the distinction between the timestamp property and actual build time. Updated the build conventions section and clarified the release process to include timestamp pinning (README.md). [1] [2]
  • Marked the reproducible build timestamp spec as "done" in the specs index (docs/specs/INDEX.md).
  • Added a detailed implementation steps and verification document for reproducible builds, including measured results and coverage of all related behaviors (docs/specs/001-reproducible-build-timestamp/steps.md).

hendrikebbers and others added 10 commits August 28, 2026 09:54
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Add a fixed, date-granular timestamp literal to the parent properties. It is
inherited by every child project, so a third party can rebuild a release
byte-identically from the tag with a plain `./mvnw -Pfull-build clean verify`
and no build flags.

The value describes the java-parent release an artifact was built against, not
the time the build ran; Git-Commit-Time remains the deterministic answer to
"when did this source state come into being".

Refs docs/specs/001-reproducible-build-timestamp

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both workflows computed the timestamp from the tag commit and passed it as
-Dproject.build.outputTimestamp. That flag is invisible outside this
organisation, so a third party checking out a release tag could never arrive at
the published bytes — the reproducibility claim failed on first contact with an
external verifier.

The value now comes from the parent POM, so CI runs the same command the README
documents, apart from deployment arguments.

Refs docs/specs/001-reproducible-build-timestamp

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
release.sh now rewrites project.build.outputTimestamp to the release date before
the verification build, so the bytes verified locally are the bytes CI publishes,
and the release commit carries version and timestamp together.

versions:set-property performs no sanity checks — measured: it exits 0 and
changes nothing when the property is absent, so `set -e` would not catch it.
An explicit guard re-reads the value and aborts on mismatch, which prevents
tagging a release whose published artifacts no rebuild could ever match.

The next-snapshot bump deliberately leaves the timestamp alone.

Refs docs/specs/001-reproducible-build-timestamp

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Describe how a third party verifies a release with no build flags, warn that a
-D flag or a child-POM override silently defeats that, and record Git-Commit-Time
as the deterministic replacement for any buildTime field.

The promise is deliberately narrow: same source plus same toolchain. Behaviour
across differing JDK patch versions has not been measured, so it is not claimed.
Known limitations point at docs/TODO.md.

Refs docs/specs/001-reproducible-build-timestamp

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
14 checks on a throwaway fixture inheriting the modified parent, all passing:
five artifacts byte-identical across two flagless builds, inherited stamp
confirmed, override precedence confirmed as CLI > child POM > parent POM, and a
build without .git succeeding with an identical stamp.

Also note in the README that Git-* manifest entries are present but empty when
building outside a Git checkout — deterministic, but only meaningful for builds
from a checkout.

Refs docs/specs/001-reproducible-build-timestamp

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The README claimed the verification command is "exactly what CI runs", but CI
runs `clean deploy` with deployment arguments. In a document whose entire purpose
is external verifiability, an imprecise claim is the wrong thing to wave through.

The steps.md coverage table marked "a child pinning an older parent is
unaffected" as documented in the README, which it was not. Added it to the known
limitations — it is the current state of both downstream consumers.

Also record the measured timezone/locale result, which moves that scenario from
inspection to execution.

Refs docs/specs/001-reproducible-build-timestamp

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The guard compares help:evaluate output against an expected string. Without -B,
Maven may emit progress or colour output into that stream and the comparison
would fail a release for no reason. Batch mode makes the value deterministic.

Refs docs/specs/001-reproducible-build-timestamp

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to 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