How do you set up gradle/wrapper-validation in CI, and where in the pipeline should it run?
answer
- gradle/actions/wrapper-validation (was wrapper-validation-action)
- separate early job, build needs it
- trigger on pull_request incl. forks
- scans every gradle-wrapper.jar recursively
- pin action version/SHA
basics
~20 sAdd the official action (gradle/actions/wrapper-validation, formerly gradle/wrapper-validation-action) as one of the first jobs in your CI workflow, running on every push and pull request. It fails the build if any wrapper jar's checksum is unknown.
solid answer
~50 sUse the official `gradle/actions/wrapper-validation` action (the modern home of the old `gradle/wrapper-validation-action`). Add it as an **early, standalone job** — ideally before any job that runs `./gradlew` — so a poisoned jar is caught before it executes with repo secrets in scope. It must trigger on **pull_request** as well as push, including PRs from forks, since the attack vector is precisely a malicious PR adding a tampered jar. The action recursively scans the checkout for every `gradle-wrapper.jar` and fails if any does not match a Gradle-published SHA-256. Keep it independent from the build job (a separate `validation` job that the build `needs`) so the build never starts unless validation passed. Pin the action to a major version (e.g. `@v3`) or a commit SHA. Outside GitHub Actions you replicate this with the `gradle-wrapper-validator` CLI or by scripting the checksum comparison.
code
groovy · 12 linesjobs:
validation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: gradle/actions/wrapper-validation@v3
build:
needs: validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./gradlew build --no-daemongo deeper
Know there's an official GitHub Action you add to CI to check the wrapper jar.
Wire it as an early job triggered on push and pull_request, with the build depending on it, and know it scans every wrapper jar in the repo.
Reason about placement and the fork-PR threat, pin the action, and cover non-GitHub CI via the standalone validator or scripted checksum comparison.
Mandate it as a required status check org-wide, integrate with branch-protection policy, and treat the validator action itself as a pinned, audited dependency.
## The official tooling The canonical control is GitHub's official action. Historically it was `gradle/wrapper-validation-action`; it has since been consolidated into the `gradle/actions` repository as `gradle/actions/wrapper-validation`. Both do the same thing: recursively find every `gradle-wrapper.jar` in the checkout and verify each against the set of SHA-256 checksums Gradle publishes for its releases. ## A minimal workflow ```yaml name: ci on: push: pull_request: jobs: validation: name: Validate Gradle wrapper runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: gradle/actions/wrapper-validation@v3 build: needs: validation # build only runs if validation passed runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: ./gradlew build ``` ## Why placement matters The whole value is **catching the jar before it runs**. If you validate after `./gradlew build` (or in the same job, after the wrapper has already bootstrapped), a malicious jar has already executed with whatever the runner exposes — secrets, tokens, cache write access. So: - Make validation its **own job** that the build `needs`. - Trigger on `pull_request`, not only `push` — the realistic attack is a contributor opening a PR that swaps the jar. Forked-PR runs in particular must validate, because that's untrusted input. ## What it does and doesn't cover - **Covers:** every `gradle-wrapper.jar` in the repo, including nested/sub-project wrappers. It fails on *any* unknown checksum. - **Doesn't cover:** the `distributionUrl` / the Gradle distribution zip (use `distributionSha256Sum`), and your dependencies (use dependency verification). It also doesn't fix anything — it's a gate. ## Outside GitHub Actions On other CI systems you don't have the action, so either: - run the standalone `gradle-wrapper-validator` tool, or - script it: download Gradle's published checksum list and compare `sha256sum gradle/wrapper/gradle-wrapper.jar` against it, failing the pipeline on mismatch. ## Hardening the action itself Pin third-party actions to a major tag (`@v3`) or, for stricter supply-chain hygiene, to an immutable commit SHA, so the validator you rely on can't itself be silently swapped.
- Why must validation run on pull_request events, not just push?The primary attack is a malicious PR that swaps the wrapper jar. If you only validate on push to your branches, a poisoned jar can run during PR CI before you ever merge — so you must validate untrusted PRs, including forked ones.
- How do you do wrapper validation on a CI system that isn't GitHub Actions?Use the standalone gradle-wrapper-validator tool, or script the check: fetch Gradle's published wrapper checksums and compare the SHA-256 of each gradle-wrapper.jar, failing the pipeline on any mismatch.
saying these in an interview costs you the question
- Running validation only after the build, when the wrapper has already executed.
- Validating only on push and skipping pull_request / forked PRs — that's exactly the unprotected path.