Chapter 04Lesson 05~190 minutes

Checkpoint Lab — Hosted, Proxy, and Group Repositories: Design Patterns, Routing, Caching, and Promotion Flows

Build an independent dev/release/public-read topology, publish a synthetic artifact, promote the exact accepted bytes into release, prove checksum identity through the public-read group, exercise proxy caching, capture an evidence packet, and clean up only the disposable lab state.

Checkpoint labDev → releasePublic-read groupChecksum identitySafe cleanup

Learning objectives

  • Build and verify a complete disposable hosted/proxy/group topology from a clean preflight.
  • Predict repository, metadata, blob and cache changes before causing them.
  • Publish to dev and prove the release-read group cannot see the candidate before promotion.
  • Promote by copying the exact Nexus-accepted bytes and prove checksum identity after release.
  • Capture an evidence packet and clean up only the known disposable repositories through supported Nexus controls.

Checkpoint safety boundary: use only a disposable loopback Community instance. Do not run this against employer repositories, production databases/blob stores, real package namespaces, or public endpoints other than the small Maven Central proxy request. The checkpoint has its own academy-ch04-cp-* names and does not depend on Lessons 2–4 being left behind.

1. Exact assumptions and preflight

  • Nexus Repository self-hosted Community Edition baseline: 3.94.1-06; re-check current official download/status/release notes before starting.
  • Java 21; one non-production instance bound to 127.0.0.1:8081.
  • Embedded H2 is acceptable only for this disposable local learning instance; PostgreSQL is the production-oriented choice discussed elsewhere.
  • Default file blob store is used; no direct blob/database files are edited.
  • Administrative credential is temporary for this learning checkpoint. Later security chapters replace it with scoped roles and service identities.
# POSIX/Bash. Windows PowerShell guidance follows this block.
LAB="$HOME/nexus-ch04-checkpoint"
NX_URL="http://127.0.0.1:8081"
mkdir -p "$LAB/evidence" "$LAB/payload" "$LAB/promote"
umask 077
read -rsp "Disposable Nexus admin password: " NX_PASS; printf "\n"
printf 'machine 127.0.0.1 login admin password %s\n' "$NX_PASS" > "$LAB/nexus.netrc"
unset NX_PASS
NETRC="$LAB/nexus.netrc"

# Never print, commit, or reuse this temporary credential file.
curl -fsS "$NX_URL/service/rest/v1/status/writable"   | tee "$LAB/evidence/01-writable.txt"

curl --fail-with-body --silent --show-error --netrc-file "$NETRC"   "$NX_URL/service/rest/v1/repositories"   | tee "$LAB/evidence/02-before.json"

python3 - <<'PY'
import json, pathlib
wanted = {f"academy-ch04-cp-{x}" for x in [
    "dev","release","central","dev-read","public-read"
]}
p=pathlib.Path.home()/"nexus-ch04-checkpoint/evidence/02-before.json"
found={r["name"] for r in json.loads(p.read_text())} & wanted
print("checkpoint collisions:", sorted(found))
PY

Windows PowerShell: keep the same loopback URLs and use curl.exe for the multipart examples. Store credentials in a temporary user-only file or Windows credential mechanism rather than embedding them in command history. Use Get-FileHash -Algorithm SHA256 instead of sha256sum. The repository and HTTP semantics are unchanged.

Proceed only if the five names are absent or you have positively identified them as your own abandoned disposable checkpoint.

2. Write predictions before actions

Record at least these four predictions in $LAB/evidence/predictions.txt before changing Nexus:

  1. Creating the five repositories changes repository configuration but does not create topology-demo component assets.
  2. Publishing com.example.academy:topology-demo:2.0.0 to cp-dev writes component/asset metadata and blob bytes in the hosted repository and makes it readable through cp-dev-read.
  3. Before promotion, cp-public-read returns not-found for the internal artifact because cp-dev is not a member.
  4. After exact-byte promotion to cp-release, cp-public-read returns the same JAR bytes and SHA-256 as the accepted cp-dev artifact.
cat > "$LAB/evidence/predictions.txt" <<'EOF'
1. Repository creation changes configuration only; topology-demo assets remain absent.
2. Dev publication creates hosted component/assets/blob state and dev-read can resolve it.
3. Public-read cannot resolve topology-demo before promotion because dev is not a member.
4. Public-read returns an identical SHA-256 after exact-byte promotion to release.
EOF

3. Create the independent checkpoint topology

Repository Type Configuration Expected role
academy-ch04-cp-dev Maven2 hosted Mixed, strict, default blob Candidate publication.
academy-ch04-cp-release Maven2 hosted Release, strict, allow-once Accepted release publication.
academy-ch04-cp-central Maven2 proxy Maven Central, auto-blocking, default blob Public dependency cache.
academy-ch04-cp-dev-read Maven2 group cp-dev → cp-release → cp-central Development reads.
academy-ch04-cp-public-read Maven2 group cp-release → cp-central Release/public reads.

Create those repositories in Settings → Repository → Repositories using the same field semantics as Lesson 2. For the proxy remote use https://repo1.maven.org/maven2/. Preserve the exact group order shown above. Do not use a Pro-only staging workflow; the checkpoint must be completable on Community Edition.

curl --fail-with-body --silent --show-error --netrc-file "$NETRC"   "$NX_URL/service/rest/v1/repositorySettings"   > "$LAB/evidence/03-settings-after-create.json"

Save a UI screenshot or text note of the two group member lists and the proxy cache settings in addition to the API evidence. This is architecture/runbook evidence, not a substitute for component checks later.

4. Build once and record the candidate identity

The build is intentionally deterministic enough for this exercise because you will not rebuild it later. The crucial invariant is that the exact file produced here becomes the candidate, then the exact file accepted by cp-dev becomes the release input.

python3 - <<'PY'
from pathlib import Path
from zipfile import ZipFile, ZIP_DEFLATED
root=Path.home()/"nexus-ch04-checkpoint/payload"
root.mkdir(parents=True, exist_ok=True)
(root/"NOTICE.txt").write_text("Chapter 04 checkpoint artifact\n", encoding="utf-8")
with ZipFile(root/"topology-demo-2.0.0.jar","w",ZIP_DEFLATED) as z:
    z.write(root/"NOTICE.txt","NOTICE.txt")
(root/"topology-demo-2.0.0.pom").write_text("""<project xmlns="http://maven.apache.org/POM/4.0.0">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example.academy</groupId>
  <artifactId>topology-demo</artifactId>
  <version>2.0.0</version>
</project>
""", encoding="utf-8")
PY

sha256sum "$LAB/payload/topology-demo-2.0.0.jar"   | tee "$LAB/evidence/04-build-sha256.txt"

5. Publish candidate only to cp-dev

curl --fail-with-body --silent --show-error --netrc-file "$NETRC"   -X POST "$NX_URL/service/rest/v1/components?repository=academy-ch04-cp-dev"   -F "maven2.groupId=com.example.academy"   -F "maven2.artifactId=topology-demo"   -F "maven2.version=2.0.0"   -F "maven2.asset1=@$LAB/payload/topology-demo-2.0.0.jar"   -F "maven2.asset1.extension=jar"   -F "maven2.asset2=@$LAB/payload/topology-demo-2.0.0.pom"   -F "maven2.asset2.extension=pom"   -o "$LAB/evidence/05-dev-upload-body.txt"   -w "%{http_code}\n"   | tee "$LAB/evidence/05-dev-upload-status.txt"

curl --fail-with-body --silent --show-error --netrc-file "$NETRC"   "$NX_URL/service/rest/v1/search/assets?repository=academy-ch04-cp-dev&group=com.example.academy&name=topology-demo&version=2.0.0"   > "$LAB/evidence/06-dev-assets.json"

The expected state is now: cp-dev database metadata describes the component/assets; its blob store contains the JAR/POM bytes; cp-release still has no such component; the groups still only own routing configuration.

6. Prove serving path before promotion

ART_PATH="com/example/academy/topology-demo/2.0.0/topology-demo-2.0.0.jar"

curl --fail-with-body --silent --show-error   "$NX_URL/repository/academy-ch04-cp-dev-read/$ART_PATH"   -o "$LAB/evidence/07-dev-read.jar"
sha256sum "$LAB/evidence/07-dev-read.jar"   | tee "$LAB/evidence/07-dev-read-sha256.txt"

curl --silent --show-error   -o "$LAB/evidence/08-public-before-body.txt"   -w "%{http_code}\n"   "$NX_URL/repository/academy-ch04-cp-public-read/$ART_PATH"   | tee "$LAB/evidence/08-public-before-status.txt"

Expected: dev-read succeeds and its checksum matches the build; public-read reports not-found. If public-read succeeds, do not continue. Inspect its member order and check for a stale duplicate artifact in release or an unintended public collision.

7. Promote the exact Nexus-accepted bytes

Do not use the original build files for the release upload. First retrieve the candidate from the authoritative cp-dev hosted repository. That proves the bytes accepted by Nexus are the bytes you promote.

POM_PATH="com/example/academy/topology-demo/2.0.0/topology-demo-2.0.0.pom"

curl --fail-with-body --silent --show-error   "$NX_URL/repository/academy-ch04-cp-dev/$ART_PATH"   -o "$LAB/promote/topology-demo-2.0.0.jar"

curl --fail-with-body --silent --show-error   "$NX_URL/repository/academy-ch04-cp-dev/$POM_PATH"   -o "$LAB/promote/topology-demo-2.0.0.pom"

sha256sum "$LAB/promote/topology-demo-2.0.0.jar"   | tee "$LAB/evidence/09-accepted-dev-sha256.txt"

curl --fail-with-body --silent --show-error --netrc-file "$NETRC"   -X POST "$NX_URL/service/rest/v1/components?repository=academy-ch04-cp-release"   -F "maven2.groupId=com.example.academy"   -F "maven2.artifactId=topology-demo"   -F "maven2.version=2.0.0"   -F "maven2.asset1=@$LAB/promote/topology-demo-2.0.0.jar"   -F "maven2.asset1.extension=jar"   -F "maven2.asset2=@$LAB/promote/topology-demo-2.0.0.pom"   -F "maven2.asset2.extension=pom"   -o "$LAB/evidence/10-release-upload-body.txt"   -w "%{http_code}\n"   | tee "$LAB/evidence/10-release-upload-status.txt"

This is a teaching simulation of the promotion invariant, not a claim that manual copy/upload is the preferred enterprise workflow. Nexus Repository Pro staging can provide richer lifecycle controls. The Community exercise intentionally focuses on the invariant that the release receives the accepted candidate bytes.

8. Verify exact identity through the public-read group

curl --fail-with-body --silent --show-error   "$NX_URL/repository/academy-ch04-cp-public-read/$ART_PATH"   -o "$LAB/evidence/11-public-after.jar"

sha256sum   "$LAB/payload/topology-demo-2.0.0.jar"   "$LAB/promote/topology-demo-2.0.0.jar"   "$LAB/evidence/11-public-after.jar"   | tee "$LAB/evidence/12-three-way-sha256.txt"

curl --fail-with-body --silent --show-error --netrc-file "$NETRC"   "$NX_URL/service/rest/v1/search/assets?repository=academy-ch04-cp-release&group=com.example.academy&name=topology-demo&version=2.0.0"   > "$LAB/evidence/13-release-assets.json"

All three JAR checksums must match. If they do not, stop: the checkpoint has demonstrated a supply-chain identity break. Do not “fix” it by editing checksums or overwriting release state. Determine which bytes changed and repeat the controlled release process with a fresh disposable coordinate if necessary.

9. Exercise the proxy and prove cached state

PUBLIC_PATH="org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar"

curl --fail-with-body --silent --show-error   "$NX_URL/repository/academy-ch04-cp-public-read/$PUBLIC_PATH"   -o "$LAB/evidence/14-public-dependency.jar"

curl --fail-with-body --silent --show-error --netrc-file "$NETRC"   "$NX_URL/service/rest/v1/search/assets?repository=academy-ch04-cp-central&group=org.apache.commons&name=commons-lang3&version=3.12.0"   > "$LAB/evidence/15-proxy-assets.json"

sha256sum "$LAB/evidence/14-public-dependency.jar"   | tee "$LAB/evidence/15-public-dependency-sha256.txt"

This evidence proves the public artifact flowed through the group into the proxy cache. It does not imply the internal com.example.academy namespace should ever fall through to Maven Central; production topology should protect owned namespaces with routing/client governance.

10. Required evidence packet and independent verification

Your packet should contain:

  • preflight status and repository inventory;
  • repository settings/member-order evidence;
  • written predictions;
  • build, accepted-dev and public-release SHA-256 evidence;
  • cp-dev and cp-release repository-scoped asset search responses;
  • public-read HTTP status before and retrieval after promotion;
  • proxy repository asset evidence for the public dependency;
  • a short runbook note explaining which repository was authoritative for each artifact and which group served each consumer.

Independently verify at least two predictions by comparing the evidence packet rather than relying on UI memory. The strongest pair is the pre-promotion public-read 404 and the three-way checksum identity after promotion.

11. Safe cleanup and rollback

Cleanup must be exact and supported. In the Nexus UI, first verify each repository name begins with academy-ch04-cp- and contains only this lab’s synthetic/cache content. Delete the two groups first, then the two hosted repositories and the proxy. Do not delete database files, blob-store files or the shared default blob store.

After repository deletion, verify the five names are absent from the repository inventory. Then remove only the local checkpoint directory, including the temporary netrc credential file. If your operating system cannot safely confirm the exact local path, delete the directory manually rather than using a broad recursive command copied from a lesson.

curl --fail-with-body --silent --show-error --netrc-file "$NETRC"   "$NX_URL/service/rest/v1/repositories"   > "$LAB/evidence/16-before-local-cleanup.json"

python3 - <<'PY'
import json, pathlib
p=pathlib.Path.home()/"nexus-ch04-checkpoint/evidence/16-before-local-cleanup.json"
remaining=[r["name"] for r in json.loads(p.read_text()) if r["name"].startswith("academy-ch04-cp-")]
print("remaining checkpoint repositories:", remaining)
PY

# After the UI shows no academy-ch04-cp-* repositories:
rm -f "$NETRC"
unset NETRC

The local evidence directory may be retained for study after the credential file is removed. Repository deletion may mark/reclaim storage according to Nexus cleanup/blob semantics rather than instantly producing the exact filesystem free-space change you expect; Chapter 18 teaches cleanup/reclamation in detail.

Knowledge check

Why did the checkpoint download the candidate from cp-dev before uploading to cp-release?

Public-read returned the candidate before promotion. What should you inspect first?

All three SHA-256 values match after promotion. What does that prove—and not prove?

Why are the checkpoint groups deleted before their member repositories?

A public dependency is cached in cp-central. Does that make cp-central authoritative for your organization’s release?

If a release checksum differs, why should you not overwrite the release to “make it match”?

12. What Chapter 04 adds to the production operating model

You can now describe an artifact platform as explicit publication origins, controlled upstream proxies and ordered consumer views. You can prove which repository owns bytes, distinguish cache availability from authority, protect internal namespaces from unsafe fallback, and require release promotion to preserve artifact identity.

Chapter 05 moves below that routing graph. It asks where the database and blob bytes live, how capacity and data separation work, and why storage design must preserve the relationship between metadata and binary content.

13. Checkpoint summary

A successful checkpoint ends with five disposable repositories created and removed safely, a synthetic artifact promoted without rebuild, identical checksums across candidate/release retrieval, proxy cache evidence, and a concise runbook explaining the routing graph.

Next chapter

Blob Stores, Storage Layout, Database Choices, Capacity Planning, and Data Separation

Follow repository requests into persistent database and blob state, then design storage and capacity without confusing metadata with binary content.

Official references and version notes

Version-sensitive statements were rechecked against Sonatype primary documentation on 2026-08-26. The mandatory path pins the same self-hosted Community lab baseline used by Chapters 02–03: Nexus Repository 3.94.1-06, Java 21, one loopback single-node instance, embedded H2 only for disposable learning, and the default file blob store. Production database/storage decisions are deferred to Chapter 05. Re-check the current download/status/release-note pages before execution.

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.