User Interface, Search, Browse, Components, Assets, Tags, Uploads, and Repository Navigation: Guided Hands-On Workflow and Core Operations
Use the disposable Community Edition instance from Chapter 02 to inventory repositories, create one synthetic hosted Maven repository, upload a harmless component with multiple assets, and prove the resulting state independently through Browse, Search, REST, and direct retrieval.
Learning objectives
- Inventory the current repository list and distinguish format/type before creating any disposable state.
- Create one hosted Maven repository with write-once behavior and explain each configuration field rather than treating JSON as a recipe.
- Upload one synthetic Maven component containing two assets through the Components API and predict database/blob changes first.
- Verify the same artifact through Search, Assets API and direct repository retrieval, including checksum comparison.
- Cleanly separate mandatory CE actions from optional Pro-only tagging.
Disposable instance only. This lesson assumes the
Chapter 02 single-node lab remains on 127.0.0.1:8081.
Do not run repository-creation or upload commands against an
employer instance. The Maven format is used only because its
group/name/version model makes component-versus-assets visible;
Chapter 06 teaches Maven repository administration in depth.
1. Preflight and evidence boundary
Before creating anything, confirm readiness, capture repository inventory and create the temporary credential file. If the instance, version or repository list differs from Chapter 02, record that discrepancy rather than silently adapting production-like commands.
LAB="$HOME/nexus-ch03-lab"
NX_URL="http://127.0.0.1:8081"
mkdir -p "$LAB/evidence" "$LAB/payload"
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 commit or print $NETRC. Delete it when the lab ends.
curl -fsS "$NX_URL/service/rest/v1/status" | tee "$LAB/evidence/01-status.txt"
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" \
"$NX_URL/service/rest/v1/repositories" \
| tee "$LAB/evidence/02-repositories-before.json"
# Optional readable formatting without jq:
python3 -m json.tool "$LAB/evidence/02-repositories-before.json" \
> "$LAB/evidence/03-repositories-before.pretty.json"
In the UI, open Browse and inspect whatever repositories the current install already has. Do not assume a tutorial-era default list is universal. Record each observed repository's name, format and type; those three fields determine which operations make sense.
2. Predict the mutation before creating it
| Prediction | Expected state change | Independent proof |
|---|---|---|
| P-01 Create hosted repository |
A repository configuration record named
academy-ch03-hosted; no learner component yet.
|
Repositories API + Browse repository list. |
| P-02 Upload component |
One component record for
com.example.academy:ui-demo:1.0.0 plus JAR/POM
assets and blob bytes.
|
Search API + Assets API + direct GET + checksum. |
| P-03 Repeat same release upload |
With ALLOW_ONCE, a conflicting redeploy should
be rejected rather than silently replacing release bytes.
|
Preserved HTTP response and unchanged downloaded SHA-256. |
3. Create one disposable hosted repository
The Repositories API is used because it gives a reproducible payload
and an observable HTTP result. hosted means this
repository is an organization-controlled publication target.
ALLOW_ONCE is intentionally chosen to make the lab's
release coordinate immutable after first deployment.
cat > "$LAB/maven-hosted.json" <<'JSON'
{
"name": "academy-ch03-hosted",
"online": true,
"storage": {
"blobStoreName": "default",
"strictContentTypeValidation": true,
"writePolicy": "ALLOW_ONCE"
},
"maven": {
"versionPolicy": "RELEASE",
"layoutPolicy": "STRICT",
"contentDisposition": "INLINE"
}
}
JSON
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" \
-H 'Content-Type: application/json' \
-X POST "$NX_URL/service/rest/v1/repositories/maven/hosted" \
--data-binary @"$LAB/maven-hosted.json"
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" \
"$NX_URL/service/rest/v1/repositories/maven/hosted/academy-ch03-hosted" \
| tee "$LAB/evidence/04-hosted-config.json"
No artifact bytes should exist because repository creation changes configuration, not package content. If Browse immediately shows learner files, stop and investigate whether you reused a non-disposable name or an old data directory.
4. Build harmless local payloads and record identity
The JAR contains only a text file and the POM uses the reserved example namespace. The SHA-256 values recorded before upload become the independent byte identities used after retrieval.
python3 - <<'PY'
from pathlib import Path
from zipfile import ZipFile, ZIP_DEFLATED
root = Path.home() / "nexus-ch03-lab" / "payload"
root.mkdir(parents=True, exist_ok=True)
(root / "README.txt").write_text("synthetic Chapter 03 artifact\n", encoding="utf-8")
with ZipFile(root / "ui-demo-1.0.0.jar", "w", ZIP_DEFLATED) as z:
z.write(root / "README.txt", "README.txt")
(root / "ui-demo-1.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>ui-demo</artifactId>
<version>1.0.0</version>
</project>
""", encoding="utf-8")
PY
sha256sum "$LAB/payload/ui-demo-1.0.0.jar" "$LAB/payload/ui-demo-1.0.0.pom" \
| tee "$LAB/evidence/05-local-sha256.txt"
Creating the local files changes only the learner workstation. Nexus still knows nothing about the component at this point.
5. Upload one component with two assets
The Components API accepts format-specific multipart fields. For
Maven, group ID, artifact ID and version identify the component,
while each assetN field identifies a file attached to
that component. A successful upload currently returns HTTP 204 with
no response body.
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" \
-X POST "$NX_URL/service/rest/v1/components?repository=academy-ch03-hosted" \
-F maven2.groupId=com.example.academy \
-F maven2.artifactId=ui-demo \
-F maven2.version=1.0.0 \
-F maven2.asset1=@"$LAB/payload/ui-demo-1.0.0.jar" \
-F maven2.asset1.extension=jar \
-F maven2.asset2=@"$LAB/payload/ui-demo-1.0.0.pom" \
-F maven2.asset2.extension=pom
After this request, the database should contain component/asset metadata and the default blob store should contain the uploaded bytes. Do not search the blob-store filesystem for filenames; Nexus blob internals are not the operator API.
6. Verify through three independent views
Q='repository=academy-ch03-hosted&group=com.example.academy&name=ui-demo&version=1.0.0'
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" \
"$NX_URL/service/rest/v1/search?$Q" \
| tee "$LAB/evidence/07-search.json"
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" \
"$NX_URL/service/rest/v1/assets?repository=academy-ch03-hosted" \
| tee "$LAB/evidence/08-assets.json"
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" \
"$NX_URL/repository/academy-ch03-hosted/com/example/academy/ui-demo/1.0.0/ui-demo-1.0.0.jar" \
-o "$LAB/evidence/downloaded-ui-demo-1.0.0.jar"
sha256sum "$LAB/evidence/downloaded-ui-demo-1.0.0.jar" \
| tee "$LAB/evidence/09-downloaded-sha256.txt"
Now use the browser: Browse → academy-ch03-hosted →
navigate the Maven path and select the component/assets. Then use
Search for group com.example.academy, name
ui-demo, version 1.0.0. Compare the UI
labels with the REST JSON and direct URL. The views should describe
the same component identity, but each exposes different details.
The asset response may include multiple checksum algorithms. The local SHA-256 comparison proves whether the bytes you downloaded match the bytes created for the lab; it does not prove origin trust or vulnerability safety.
8. Challenge: choose the correct control
You need a second file attached to the already published
1.0.0 release. Should you retry the same generic
upload, change the hosted repository write policy, use a native
Maven publication, or publish a new version? Because this lab
deliberately uses ALLOW_ONCE, do not weaken the
repository to make a release mutable. Treat the artifact as
immutable and publish 1.0.1 for a changed release
payload. Chapter 06 will examine Maven publication semantics in
depth.
Knowledge check
Why did the lesson create a Maven hosted repository instead of uploading to a proxy repository?
Uploads belong to hosted repositories. Proxy repositories mediate upstream content and are not authoritative publication targets.
The Components API returned HTTP 204. Where should you look for proof that two assets actually exist?
Query Search/Components and Assets APIs, inspect Browse, and retrieve the expected paths. A status code alone is not enough evidence.
The downloaded JAR SHA-256 matches the local JAR. What has been proven?
Byte identity for those two files under the tested request. It has not proven trusted provenance, absence of vulnerabilities, or authorization correctness.
Why is the tag-simulation file acceptable in Community Edition?
It teaches the semantic distinction—component-level metadata association—without falsely presenting a Pro-only product capability as free or mandatory.
A repeat upload of 1.0.0 fails under ALLOW_ONCE. Should you switch to an allow-redeploy policy?
Not merely to make the command succeed. The failure is useful policy evidence. Publish a new version for changed release bytes unless your real versioning policy deliberately permits mutation.
9. Summary
You created configuration, then content, and proved the causal difference. Repository creation produced no learner assets; component upload produced one logical component with multiple assets and blob content; Search, Assets and direct retrieval independently exposed the result.
Official references and version notes
- Download Nexus Repository — the official download page used to pin the same 3.94.1-06 self-hosted lab baseline as Chapter 02 while current indexes are rechecked before execution.
- Browsing Repositories — browse-tree behavior, 10,000-component-per-level UI limit, HTML view, and browse/read privilege distinctions.
- Searching for Components — current UI search behavior, first-300-result display, SQL-search semantics, tokenization, exact phrases, and wildcard rules.
- Search API — component/asset search endpoints and continuation-token pagination.
- Viewing Component Information — component identifiers and the relationship to associated assets.
- Viewing Asset Information — asset path, content type, size, blob timestamps/reference, checksums, uploader metadata, and format-specific attributes.
- Uploading Components — hosted-only UI upload boundary and required upload/browse/read privileges.
- Components API — list/get/delete components and format-specific multipart component upload.
- Assets API — paginated asset listing, asset details, paths, download URLs and checksums.
- Repositories API — repository inventory and format/type-specific repository configuration endpoints.
- Privileges — current browse, read, add, edit, delete and search privilege semantics.
- Tagging and Self-Hosted Feature Matrix — component tagging is currently a Pro feature; mandatory Chapter 03 work does not require it.
Version-sensitive statements were rechecked against Sonatype primary documentation on 2026-08-26. The mandatory path remains self-hosted, Community/free-compatible and disposable. The chapter keeps the Chapter 02 lab baseline at Nexus Repository 3.94.1-06 because Sonatype's current download and versions-status pages still present 3.94.1 as the current downloadable/GA line; learners are told to re-check those pages before running the lab.
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.