What's the difference between validating gradle-wrapper.jar and verifying the Gradle distribution via distributionSha256Sum?
answer
- jar = bootstrapper, committed; distro = downloaded zip
- validation-action in CI vs property in .properties
- genuine jar can still fetch bad distro
- tampered jar can ignore the distro checksum
- defense in depth, both needed
basics
~10 sWrapper-jar validation checks the committed bootstrapper jar against Gradle's published checksums. distributionSha256Sum verifies the downloaded Gradle distribution zip. They protect two different artifacts: the jar that runs, and the Gradle it fetches.
solid answer
~50 sThese are two complementary integrity controls covering different links in the chain. **Wrapper-jar validation** (via `gradle/actions/wrapper-validation`) confirms the committed `gradle-wrapper.jar` — the small bootstrapper that executes first — is an unmodified official Gradle jar, by SHA-256. **`distributionSha256Sum`**, a property in `gradle-wrapper.properties`, makes that bootstrapper verify the SHA-256 of the **Gradle distribution zip it downloads** from `distributionUrl` before unpacking and running it. So jar validation protects *the thing that runs locally and is committed*; `distributionSha256Sum` protects *the thing that gets downloaded over the network*. You need both: a genuine jar could still fetch a tampered distribution if `distributionUrl` were hijacked or a mirror compromised, and a pinned distribution checksum is meaningless if the jar enforcing it has been swapped for one that ignores it. In CI you run the validation action; in the repo you pin `distributionSha256Sum`.
code
toml · 7 lines# gradle/wrapper/gradle-wrapper.properties
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/distsgo deeper
Know there are two separate things: the small jar and the downloaded Gradle, each with its own check.
Explain that jar validation runs in CI and distributionSha256Sum is a property the jar enforces at download time.
Articulate why neither alone suffices and how they form defense in depth across the bootstrapper and the distribution.
Define org policy requiring both controls, reason about mirror/registry trust and where each check sits in the build supply chain.
## Two artifacts, two controls The wrapper flow has two trust boundaries: 1. The **bootstrapper jar** (`gradle/wrapper/gradle-wrapper.jar`) — committed to your repo, runs first. 2. The **distribution** (the `gradle-x.y-bin.zip` at `distributionUrl`) — downloaded by that jar, then run as the real Gradle. Each needs its own integrity check. ## Control 1 — validating the wrapper jar This is the CI-side check. `gradle/actions/wrapper-validation` hashes every `gradle-wrapper.jar` in the checkout and compares to Gradle's published known-good SHA-256 set. It answers: *is the bootstrapper genuine and unmodified?* It runs in CI because the jar is a committed artifact and the risk is a tampered commit. ## Control 2 — distributionSha256Sum This is the runtime, repo-pinned check. In `gradle-wrapper.properties`: ```properties distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d ``` When the wrapper downloads the distribution, it computes the zip's SHA-256 and refuses to proceed unless it matches `distributionSha256Sum`. This protects against a compromised mirror, a hijacked `distributionUrl`, or a MITM serving a malicious zip. You can get the official value from Gradle's `-bin.zip.sha256` file, or have the `wrapper` task write it for you with `--gradle-distribution-sha256-sum` (or by setting it before regenerating). ## Why neither alone is enough - **Only jar validation:** the genuine jar will happily download whatever `distributionUrl` points to. If that URL or its host is compromised and no distribution checksum is pinned, you run a malicious Gradle. - **Only distributionSha256Sum:** a tampered jar could simply ignore the property (it's the jar that enforces it). If the bootstrapper itself is malicious, pinning the distribution buys nothing. So defense in depth: validate the jar in CI **and** pin `distributionSha256Sum` in the repo. ## Where each lives | Control | Artifact protected | Where configured | Where enforced | |---|---|---|---| | Wrapper-jar validation | gradle-wrapper.jar (bootstrapper) | CI workflow | CI job, every PR | | distributionSha256Sum | Gradle distribution zip | gradle-wrapper.properties | the wrapper jar at download time | Note: `distributionSha256Sum` is the sibling topic's detail — here the point is only how the two controls relate and why both are required.
- If you only set distributionSha256Sum but never validate the jar, what's the residual risk?A tampered gradle-wrapper.jar could ignore or fake the distribution check, so pinning the distribution gives no protection — the malicious bootstrapper already runs first.
- Where do these two checks actually execute?Jar validation runs in CI (a workflow job hashing the committed jar). distributionSha256Sum is enforced at runtime by the wrapper jar itself when it downloads the distribution, on any machine including local.
saying these in an interview costs you the question
- Saying the two controls are redundant — they protect different artifacts and you need both.
- Claiming distributionSha256Sum protects the wrapper jar (it protects the downloaded distribution).