Chapter 28Lesson 04~320 minutes

Dependency Verification, Checksums, Signatures, Repository Content Filtering, and Supply-Chain Security: Diagnostics, Failure Modes, Security, and Performance

Diagnose tampered bytes, repository confusion, broad plugin trust, stale verification baselines, compromised credentials, and poisoned caches as supply-chain incidents. Preserve evidence first; never make the error disappear by disabling the control.

Incident responseDependency confusionPlugin trustCache poisoningEvidence

Learning objectives

  • Preserve verification and repository evidence before changing caches or metadata.
  • Diagnose generated-but-unreviewed metadata, checksum mismatch, repository confusion, and plugin repository sprawl.
  • Respond to credential/artifact compromise as an incident rather than a local-cache problem.
  • Use isolated fresh state to distinguish cache corruption from remote/repository policy failure.
  • Apply the least destructive correction and prove the trust invariant again.

Incident rule. A verification failure is evidence. Do not delete caches, regenerate checksums, disable verification, change repository order, or rotate credentials before recording the failing coordinate, expected/actual digest, repository origin, Wrapper/JDK identities, and relevant logs.

1. Diagnostic sequence for supply-chain failures

Step Question Evidence
1. Preserve What exactly failed before intervention? Log/report, expected/actual digest, coordinate, repository URL/name, timestamps.
2. Tool identity Did Wrapper/JDK/build-tool identity change? Wrapper properties/JAR digest, --version, JDK version.
3. Declared policy What repositories/verification rules were intended? settings/build/POM/settings.xml + verification metadata diff.
4. Resolution graph Which module/plugin and transitive path selected it? dependency report / dependencyInsight / Maven dependency tree.
5. State/origin Which cache/repository supplied the bytes? Isolated fresh user home/local repo; resolver logs.
6. Verify externally Do independent release digests/key fingerprints match? Publisher/approved-manager evidence.
7. Correct What smallest change restores intended trust? Restore immutable bytes, fix exclusive routing, rotate credentials, reviewed metadata update.
8. Rebuild Does strict clean-room verification pass? Fresh isolated build + artifact identity checks.

2. Failure: verification metadata was auto-accepted

A dependency bot updates a version and runs --write-verification-metadata sha256; CI commits the resulting file automatically. The build is green, but nobody verified whether the new checksums correspond to the intended publisher.

Diagnosis: inspect the dependency/version diff and verification metadata together. Determine the origin of every new artifact/key. Repair: independently validate the new digest/fingerprint, annotate the review, then run strict verification. If you cannot establish provenance, reject the upgrade rather than accepting the generated baseline.

3. Failure: checksum mismatch

The strict build reports expected digest A and actual digest B for the same coordinate. Possible causes include repository mutation, compromised mirror, inconsistent repository copies, local cache corruption, or an intentional rebuild published under an immutable version.

# Preserve before cleanup:
cp checksum-mismatch.log incident-checksum-mismatch.log
sha256sum path/to/suspect.jar | tee incident-actual.sha256
cp gradle/verification-metadata.xml incident-verification-metadata.xml
cat gradle/wrapper/gradle-wrapper.properties > incident-wrapper.properties

# Then compare in isolated disposable cache state, not normal ~/.gradle:
GRADLE_USER_HOME="$PWD/.incident-gradle-home" \
  ./gradlew --refresh-dependencies --dependency-verification strict compileJava

If fresh state returns the same unexpected bytes, cache corruption is unlikely. Investigate repository/mirror origin. If fresh state returns the expected bytes, preserve the bad cached artifact before removing only the disposable incident cache.

4. Broken “repair”: turn verification off

This command is diagnostic only and unsafe as a release fix:

# Anti-pattern for a release gate — do not normalize this:
./gradlew --dependency-verification off build

It answers “would the build continue if we ignore the security control?” It does not answer whether the dependency is safe. Restore strict mode and investigate the artifact.

5. Failure: repository order permits dependency confusion

An internal group is declared in a private repository, but a broad public repository is also eligible. An attacker publishes the same coordinate publicly. Normal repository order is operational state and can change with refactors or plugins.

Repair: make the namespace exclusive (or enforce central routing in a repository manager) and prove that removing the internal artifact causes resolution failure rather than public fallback. Do not rely on “our internal repository happens to be first.”

6. Failure: plugin resolution is unrestricted

A project carefully scopes normal dependencies but pluginManagement.repositories includes multiple broad repositories and plugin versions drift. Because plugins execute during build configuration, that is a direct code-execution trust gap.

Repair: pin plugin versions, reduce/scoped plugin repositories, verify plugin artifacts, and review marker/implementation coordinates. Remember that project dependency repository policy does not automatically govern plugin repositories.

7. Failure: suspected repository credential compromise

Do not respond only by clearing caches. Preserve access/audit logs where available, revoke/rotate the credential through the repository/CI system, block or quarantine the affected publication path, verify whether immutable coordinates were overwritten, and rebuild from independently trusted inputs. Project files should never contain the real secret used for this exercise.

8. Failure: compromised artifact is reused from cache

Cache reuse changes where bytes are read from; it does not change the trust requirement. If a less-trusted job can populate a shared dependency/build cache consumed by privileged jobs, treat that cache as an input boundary. Dependency verification catches altered external dependency bytes only if verification remains enabled and the cache path still goes through verified resolution. Build-cache outputs need their own trust model from Chapter 24.

9. Maven-specific diagnostic boundary

With Maven, capture effective settings/mirrors, repository IDs, checksum policy, dependency tree, Wrapper properties, and isolated local-repository results. A repository checksum failure should not be “fixed” with checksumPolicy=ignore. If signature authenticity is required, use an independently anchored signature verification/repository-manager policy rather than claiming Maven core checksum transport alone proves the publisher.

10. Performance is secondary to correctness

Verification and repository scoping can add network/CPU overhead, especially on first resolution. Measure cold and warm behavior separately. Do not broaden repositories, trust all sources/javadocs, disable verification, or weaken key scope merely to shave seconds from CI. First optimize repository topology, caching, and parallelism without changing the acceptance policy.

11. Interpret the intentionally broken local example

In Lesson 2 the same 1.0.0 coordinate was overwritten. The expected outcome is a non-zero build with a dependency verification failure. The important artifact is not the return code by itself; it is the preserved tuple:

coordinate=dev.academy.internal:policy-lib:1.0.0
repository=academyInternal (trusted-repo)
expected_sha256=<from reviewed verification metadata>
actual_sha256=<from changed artifact>
wrapper=Gradle 9.7.1 + verified wrapper/distribution
jdk=21 runtime / Java 17 target
action=restore trusted immutable bytes; do not accept new checksum

12. Least-destructive repair principle

Fix the trust boundary that failed. Restore artifact bytes if immutability was broken; narrow repository eligibility if routing was wrong; update a checksum/key only after independent review when the dependency upgrade was intentional; rotate credentials if exposure occurred. Then rerun strict verification from isolated state and compare the resolved graph/artifact identity to the intended baseline.

Knowledge check

Why preserve the suspect JAR before clearing a disposable cache?

What does dependency-verification off prove?

How do you prove repository exclusivity works?

What additional evidence should accompany a signing-key rotation?

Why is credential compromise not a cache-cleanup problem?

Official references and version notes

Version-sensitive behavior was rechecked against primary documentation on 2026-08-24. Mandatory labs are local/free and use synthetic artifacts only. No production repository, credential, signing key, shared cache, or hosted CI service is required.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.