Checkpoint Lab — Apache Maven Installation, Wrapper, Settings, Local Repository, and Project Bootstrap
Checkpoint lab: prove a wrapper-first Maven bootstrap with verified distribution integrity, explicit settings, isolated local repository, failure injection, recovery, and cleanup.
Learning objectives
- Bootstrap a disposable Maven project whose normal build entry point is the project wrapper.
- Record and verify wrapper distribution URL/checksum, Maven version, JDK runtime, settings path, and isolated local-repository location.
- Predict and observe how wrapper state, repository state, and project output change during first and repeat builds.
- Inject a broken Central mirror, diagnose the repository-policy failure, and restore the clean settings without changing project source.
- Produce a concise verification record and clean up only disposable Chapter 04 state.
only-script distribution type and pin the Maven
distribution with distributionSha256Sum after the
downloaded archive has first been verified against Apache's published
release checksum/signature. Re-check these versions before applying
the examples to production.
1. Checkpoint scenario and acceptance contract
You are preparing a tiny JVM service for a team that uses ephemeral CI agents. The repository must carry its Maven launch contract, no credentials may be committed, CI must be able to use a fresh local repository, and a mirror outage must be diagnosable without deleting user caches.
Required evidence
[ ] project contains mvnw, mvnw.cmd, and .mvn/wrapper/maven-wrapper.properties
[ ] wrapper selects Maven 3.9.16
[ ] Maven distribution is pinned with distributionSha256Sum after Apache release verification
[ ] ./mvnw -v (or mvnw.cmd -v) records Maven and Java runtime identity
[ ] lab uses explicit -s settings path and isolated maven.repo.local
[ ] first build populates only disposable wrapper/repository state
[ ] project JAR exists under target/
[ ] deliberate broken mirror fails for the predicted repository reason
[ ] clean settings restore succeeds with controlled state
[ ] cleanup removes only the disposable checkpoint directory
2. Setup and preflight
Create a brand-new directory. If it already exists or contains valuable data, stop. Record the installed Java and system Maven used only for wrapper bootstrap.
test ! -e maven-bootstrap-checkpoint
mkdir -p maven-bootstrap-checkpoint/src/main/java/com/example
cd maven-bootstrap-checkpoint
java -version
mvn -v
maven-bootstrap-checkpoint directory. Never
repurpose that command for an existing repository.
3. Create the project model and source
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>maven-bootstrap-checkpoint</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
package com.example;
public final class App {
public static void main(String[] args) {
System.out.println("maven bootstrap checkpoint");
}
}
Prediction 1: before wrapper generation there
should be no mvnw, .mvn/wrapper, isolated
wrapper home, local repository, or target/.
4. Generate and review the wrapper
mvn org.apache.maven.plugins:maven-wrapper-plugin:3.3.4:wrapper \
-Dmaven=3.9.16 \
-Dtype=only-script
git diff --no-index /dev/null .mvn/wrapper/maven-wrapper.properties || true
sed -n '1,160p' .mvn/wrapper/maven-wrapper.properties
From this point forward, treat direct mvn as outside
the checkpoint contract. A reviewer should be able to see the Maven
version/distribution URL change in Git when the project upgrades
Maven.
5. Verify the release and pin distribution SHA-256
Repeat the official release verification workflow from Lesson 2:
download the Maven 3.9.16 binary archive from Apache, download the
published SHA-512 checksum (or verify the Apache signature/KEYS),
require the SHA-512 match, compute SHA-256 of the verified archive,
then write that exact SHA-256 as
distributionSha256Sum in the wrapper properties.
mkdir -p .lab/verify
curl -fL -o .lab/verify/apache-maven-3.9.16-bin.zip \
https://dlcdn.apache.org/maven/maven-3/3.9.16/binaries/apache-maven-3.9.16-bin.zip
curl -fL -o .lab/verify/apache-maven-3.9.16-bin.zip.sha512 \
https://downloads.apache.org/maven/maven-3/3.9.16/binaries/apache-maven-3.9.16-bin.zip.sha512
EXPECTED_SHA512="$(awk '{print $1}' .lab/verify/apache-maven-3.9.16-bin.zip.sha512)"
ACTUAL_SHA512="$(sha512sum .lab/verify/apache-maven-3.9.16-bin.zip | awk '{print $1}')"
test "$EXPECTED_SHA512" = "$ACTUAL_SHA512"
DIST_SHA256="$(sha256sum .lab/verify/apache-maven-3.9.16-bin.zip | awk '{print $1}')"
printf 'Verified distribution SHA-256: %s\n' "$DIST_SHA256"
python - "$DIST_SHA256" <<'PY2'
from pathlib import Path
import sys
p=Path('.mvn/wrapper/maven-wrapper.properties')
lines=[x for x in p.read_text().splitlines() if not x.startswith('distributionSha256Sum=')]
lines.append('distributionSha256Sum='+sys.argv[1])
p.write_text('\n'.join(lines)+'\n')
PY2
grep -E '^(distributionUrl|distributionSha256Sum)=' .mvn/wrapper/maven-wrapper.properties \
| tee .lab-wrapper-contract.tmp
# Move this record into .lab/ after the lab directory is created below.
Prediction 2: changing only the checksum to an incorrect value should be treated as an integrity failure, not as permission to disable checksum enforcement.
6. Create isolated wrapper, settings, and repository state
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
<interactiveMode>false</interactiveMode>
<offline>false</offline>
</settings>
mkdir -p .lab/wrapper-home .lab/m2repo
mv .lab-wrapper-contract.tmp .lab/wrapper-contract.txt
export MAVEN_USER_HOME="$PWD/.lab/wrapper-home"
printf '%s\n' "$PWD/.lab/m2repo" > .lab/local-repository.txt
printf '%s\n' "$PWD/.lab/settings.xml" > .lab/settings-path.txt
./mvnw -s .lab/settings.xml \
-Dmaven.repo.local="$PWD/.lab/m2repo" \
-v | tee .lab/maven-version.txt
java -version 2> .lab/java-version.txt
Prediction 3: the wrapper home and local repository start empty. Wrapper execution populates wrapper-managed Maven state; Maven execution populates plugin/dependency repository state. These are different directories and evidence streams.
7. Capture effective settings without secrets
./mvnw -s .lab/settings.xml \
-Dmaven.repo.local="$PWD/.lab/m2repo" \
org.apache.maven.plugins:maven-help-plugin:3.5.2:effective-settings \
-Doutput=.lab/effective-settings.xml
grep -n "localRepository\|offline\|mirror\|proxy" .lab/effective-settings.xml | head -60
Do not add showPasswords=true. In this lab there are no
credentials anyway, but the operational habit should remain safe
when the same command is used elsewhere.
8. First build — observe cold state
./mvnw -s .lab/settings.xml \
-Dmaven.repo.local="$PWD/.lab/m2repo" \
-B -ntp package | tee .lab/build-first.log
jar tf target/maven-bootstrap-checkpoint-1.0.0-SNAPSHOT.jar \
| tee .lab/jar-contents.txt
find .lab/m2repo -type f | sort > .lab/repository-files.txt
sha256sum target/maven-bootstrap-checkpoint-1.0.0-SNAPSHOT.jar \
| tee .lab/artifact.sha256
Verify that repository files appeared under
.lab/m2repo and project output appeared under
target/. No step should require deleting or writing to
your normal ~/.m2/repository.
9. Repeat build — distinguish cache warmth from output identity
./mvnw -s .lab/settings.xml \
-Dmaven.repo.local="$PWD/.lab/m2repo" \
-B -ntp package | tee .lab/build-repeat.log
sha256sum target/maven-bootstrap-checkpoint-1.0.0-SNAPSHOT.jar \
| tee .lab/artifact-repeat.sha256
Compare transfer activity and the two artifact hashes. If hashes differ, investigate output reproducibility; if they match, that is useful evidence for this tiny project but not a universal guarantee. More rigorous reproducible-build controls appear later in the course.
10. Inject a broken Central mirror
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
<mirrors>
<mirror>
<id>broken-central</id>
<name>Intentional Chapter 04 failure</name>
<url>https://repo.example.invalid/maven2</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
</settings>
rm -rf .lab/broken-repo
mkdir -p .lab/broken-repo
set +e
./mvnw -s .lab/broken-settings.xml \
-Dmaven.repo.local="$PWD/.lab/broken-repo" \
-B -ntp \
org.apache.maven.plugins:maven-help-plugin:3.5.2:effective-pom \
> .lab/broken-mirror.log 2>&1
STATUS=$?
set -e
printf 'exit=%s\n' "$STATUS"
grep -Ei 'broken-central|repo\.example\.invalid|transfer|resolve|plugin' .lab/broken-mirror.log | head -40
test "$STATUS" -ne 0
Expected: the build fails before Java compilation because plugin resolution is routed to the synthetic invalid mirror. Record that causal classification before repairing anything.
11. Restore clean settings and prove recovery
rm -rf .lab/recovery-repo
mkdir -p .lab/recovery-repo
./mvnw -s .lab/settings.xml \
-Dmaven.repo.local="$PWD/.lab/recovery-repo" \
-B -ntp \
org.apache.maven.plugins:maven-help-plugin:3.5.2:effective-pom \
-Doutput=.lab/recovered-effective-pom.xml
test -s .lab/recovered-effective-pom.xml
The repair changed only settings/repository routing; project source and wrapper configuration remained unchanged. That is stronger diagnostic evidence than “I changed several things and it works now.”
12. Verification checklist
test -x mvnw
test -f mvnw.cmd
test -f .mvn/wrapper/maven-wrapper.properties
grep -q '^distributionSha256Sum=' .mvn/wrapper/maven-wrapper.properties
grep -q 'Apache Maven 3.9.16' .lab/maven-version.txt
test -s .lab/effective-settings.xml
test -s .lab/repository-files.txt
test -f target/maven-bootstrap-checkpoint-1.0.0-SNAPSHOT.jar
test -s .lab/broken-mirror.log
test -s .lab/recovered-effective-pom.xml
printf 'CHECKPOINT_OK\n'
A passing checklist proves the checkpoint conditions only. It does not prove the public repository is always available, all Maven plugins are pinned, all dependencies are verified, or later release publishing is secure.
13. Cleanup and rollback
Review the absolute path and preserve any synthetic evidence you want for notes. Then leave the directory and remove only the disposable checkpoint.
pwd
cd ..
ls -ld maven-bootstrap-checkpoint
# rm -rf maven-bootstrap-checkpoint
~/.m2, an existing
repository, or a shared CI cache.
The course intentionally avoids destructive cleanup of normal Maven
state.
Knowledge check
After wrapper generation, CI invokes mvn package.
Which checkpoint invariant did it violate?
The project-wrapper entry-point invariant. CI bypassed the Maven version pinned by the project wrapper.
The first build populates .lab/m2repo. Is that
directory a release repository?
No. It is the disposable Maven local repository containing cached/downloaded and possibly locally installed state.
The broken mirror test fails with an invalid-host transfer error before compilation. What layer should be repaired?
Settings/repository routing, not Java source or compiler configuration.
Why use a fresh .lab/broken-repo for the mirror
failure?
A warm cache could satisfy required plugin/artifact requests and hide the mirror failure, weakening the experiment.
The Maven distribution URL is unchanged but
distributionSha256Sum changes in a pull request. Is
that significant?
Yes. It changes the accepted executable distribution bytes and should receive supply-chain review.
Why record Maven version and Java runtime separately?
The Maven distribution and the Java runtime that launches it are independent identities; either can drift and produce compatibility differences.
Summary and bridge to Chapter 05
The checkpoint established a production-minded Maven bootstrap contract: project-owned wrapper, independently verified distribution pin, explicit Maven/JDK evidence, secret-free alternate settings, isolated resolver state, controlled failure injection, causal recovery, and safe cleanup. Chapter 05 can now assume the Maven executable/environment is understood and focus on the POM, packaging, build lifecycle, phases, and goals.
Official references and version notes
Checkpoint baseline verified against current Apache Maven documentation on 2026-08-23. The mandatory path is local/free and does not require a hosted repository, paid CI, signing service, or production credential.
- Apache Maven — Installation
- Apache Maven — Download and current/preview release status
- Apache Maven Wrapper
- Maven Wrapper Plugin — wrapper:wrapper
- Maven Settings Reference
- Maven — Using Mirrors for Repositories
- Maven Local Repositories
- Maven Help Plugin — help:effective-settings
- Maven Quickstart Archetype
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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.