Checkpoint Lab — Conan, Ansible Galaxy, Terraform, Swift, and Emerging Repository Formats
Evaluate Ansible Galaxy and Terraform as two current emerging formats, stand up disposable repositories, publish synthetic content, configure isolated clients/fixtures, record evidence and limitations, and produce an operator adoption checklist without paid features.
Checkpoint outcomes
- Produce a current adoption matrix for Ansible Galaxy and Terraform on Nexus 3.95.2 Community Edition.
- Stand up disposable native repositories and publish one synthetic collection/module.
- Configure isolated client/registry state without exposing credentials in command history.
- Verify repository, component/asset, checksum, authentication, and client-routing evidence.
- Document limitations, recovery dependencies, revalidation triggers, and cleanup.
Checkpoint safety. Use only a disposable local Nexus instance and synthetic namespaces. The checkpoint does not require public package publication, cloud accounts, Pro features, real CI secrets, production identity systems, or manual blob/database changes. If a command prerequisite is absent, use the documented fixture path and record that it was simulated.
1. Scenario and acceptance criteria
You operate a small engineering platform. The automation team wants Ansible collections; the platform team wants Terraform modules. Both want Nexus as the controlled boundary. Your task is to prove whether the current 3.95.2 Community instance can support the required workflow, not merely to make two uploads succeed.
| Evidence | Pass condition |
|---|---|
| Feature matrix | Version, edition, client/protocol, proxy/hosted/group, auth and operational gaps recorded. |
| Ansible publication | Synthetic collection appears in hosted repository and can be addressed through the group/client fixture. |
| Terraform publication | Synthetic module uploaded through Terraform registry path and visible as repository assets. |
| Identity | Collection namespace/name/version and Terraform module namespace/name/provider/version are explicit; checksums captured. |
| Security | No real secrets, no credentials in command arguments or committed files; temp config is permission-restricted. |
| No bypass | Client configs point to Nexus; public upstream is not an alternate source for the internal namespace. |
| Cleanup | Disposable repositories and temp files removed through supported operations. |
2. Preflight and prediction
export NX_URL="http://127.0.0.1:8081"
export LAB="${TMPDIR:-/tmp}/nexus-ch12-checkpoint"
rm -rf "$LAB"
mkdir -p "$LAB"/{evidence,ansible-src,ansible-home,terraform-src,terraform-home}
chmod 700 "$LAB"
curl -fsS "$NX_URL/service/rest/v1/status" > "$LAB/evidence/status.txt"
curl -fsS "$NX_URL/service/rest/v1/repositories" > "$LAB/evidence/repos-before.json"
Predict before acting:
- Publishing the Ansible collection should create component/asset metadata plus blob content in the hosted repository; the group should reference the member rather than duplicate an authoritative hosted copy.
-
Uploading the Terraform module under
/v1/modules/...should create format-specific module assets and metadata; a checksum of the source archive should remain stable when the same bytes are downloaded. - Activating a token realm changes security configuration, not package content.
3. Record the feature matrix you are actually testing
reviewed_at: 2026-08-26
nexus:
version: 3.95.2
edition: Community
formats:
ansible:
introduced: 3.93.0
proxy: true
hosted: true
group: true
api: Galaxy v3
auth: Ansible Galaxy Bearer Token Realm when protected
terraform:
proxy_since: 3.88.0
hosted_since: 3.89.0
group_since: 3.90.0
opentofu_coder_since: 3.94.0
non_url_auth_since: 3.95.0
operations:
export_assets: "not mandatory; current self-hosted feature matrix marks Pro"
import_external_files: "not mandatory; current self-hosted feature matrix marks Pro"
backup_restore: "required production concern; separate from repository export"
4. Create the disposable repositories
Using the Nexus UI, create:
| Repository | Recipe | Configuration |
|---|---|---|
academy-ch12cp-ansible-hosted |
ansiblegalaxy (hosted) | Synthetic collection origin. |
academy-ch12cp-ansible-group |
ansiblegalaxy (group) | Member: hosted only. This intentionally proves no public fallback for the internal namespace. |
academy-ch12cp-terraform-hosted |
terraform (hosted) | Synthetic module origin. |
academy-ch12cp-terraform-group |
terraform (group) | Member: hosted only. Optional client read endpoint; no public fallback. |
Create one disposable lab identity with only the repository read/browse/add privileges needed for these hosted/group paths. If using native token endpoints, enable only the required Ansible/Terraform token realms and record that change.
5. Create the temporary authentication boundary
read -r -p 'Disposable Nexus username: ' NX_USER
read -r -s -p 'Disposable Nexus password: ' NX_PASS; echo
export NX_AUTH_FILE="$LAB/nexus.netrc"
umask 077
printf 'machine 127.0.0.1 login %s password %s\n' "$NX_USER" "$NX_PASS" > "$NX_AUTH_FILE"
unset NX_PASS
6. Build and publish the Ansible collection
cd "$LAB/ansible-src"
if command -v ansible-galaxy >/dev/null 2>&1; then
ansible-galaxy collection init learner_example.adoption_probe
cd learner_example/adoption_probe
printf '# Nexus Chapter 12 checkpoint\n' > README.md
ansible-galaxy collection build --output-path "$LAB/ansible-src/dist" | tee "$LAB/evidence/ansible-build.txt"
sha256sum "$LAB/ansible-src/dist/"*.tar.gz | tee "$LAB/evidence/ansible-sha256.txt"
else
printf 'ansible-galaxy unavailable: use synthetic collection fixture/UI walkthrough
' > "$LAB/evidence/ansible-client-fixture.txt"
fi
Upload the generated collection archive to
academy-ch12cp-ansible-hosted through the Nexus upload
UI. Then verify supported repository state:
curl -fsS --netrc-file "$NX_AUTH_FILE" "$NX_URL/service/rest/v1/components?repository=academy-ch12cp-ansible-hosted" | tee "$LAB/evidence/ansible-components.json"
curl -fsS --netrc-file "$NX_AUTH_FILE" "$NX_URL/service/rest/v1/assets?repository=academy-ch12cp-ansible-hosted" | tee "$LAB/evidence/ansible-assets.json"
7. Configure a clean Ansible client without public fallback
The group has only the hosted repository, so the internal namespace cannot fall through to Galaxy. If authentication is required, put the reversible Base64 token in a temporary file only:
export ANSIBLE_CONFIG="$LAB/ansible-home/ansible.cfg"
export ANSIBLE_COLLECTIONS_PATH="$LAB/ansible-home/collections"
mkdir -p "$ANSIBLE_COLLECTIONS_PATH"
read -r -p 'Disposable Nexus username: ' A_USER
read -r -s -p 'Disposable Nexus password: ' A_PASS; echo
A_TOKEN="$(printf '%s:%s' "$A_USER" "$A_PASS" | base64 | tr -d '\n')"
umask 077
cat > "$ANSIBLE_CONFIG" <<EOF
[defaults]
collections_path = $ANSIBLE_COLLECTIONS_PATH
[galaxy]
server_list = nexus_internal
[galaxy_server.nexus_internal]
url = $NX_URL/repository/academy-ch12cp-ansible-group/
token = $A_TOKEN
EOF
cat > "$LAB/ansible-home/requirements.yml" <<EOF
---
collections:
- name: learner_example.adoption_probe
version: "1.0.0"
source: http://127.0.0.1:8081/repository/academy-ch12cp-ansible-group/
token: "$A_TOKEN"
EOF
chmod 600 "$ANSIBLE_CONFIG" "$LAB/ansible-home/requirements.yml"
unset A_USER A_PASS A_TOKEN
if command -v ansible-galaxy >/dev/null 2>&1; then
ansible-galaxy collection install -r "$LAB/ansible-home/requirements.yml" | tee "$LAB/evidence/ansible-install.txt"
fi
8. Build and publish a Terraform module
mkdir -p "$LAB/terraform-src/module"
cat > "$LAB/terraform-src/module/main.tf" <<'EOF'
variable "checkpoint" { type = string; default = "chapter12" }
output "checkpoint" { value = var.checkpoint }
EOF
cat > "$LAB/terraform-src/module/versions.tf" <<'EOF'
terraform { required_version = ">= 1.0" }
EOF
(cd "$LAB/terraform-src/module" && zip -q -r "$LAB/terraform-src/adoption-probe-1.0.0.zip" .)
sha256sum "$LAB/terraform-src/adoption-probe-1.0.0.zip" | tee "$LAB/evidence/terraform-sha256-before.txt"
curl --fail --silent --show-error --netrc-file "$NX_AUTH_FILE" -X PUT "$NX_URL/repository/academy-ch12cp-terraform-hosted/v1/modules/learner-example/adoption-probe/local/1.0.0/adoption-probe-1.0.0.zip" -H 'Content-Type: application/zip' --data-binary "@$LAB/terraform-src/adoption-probe-1.0.0.zip" -o /dev/null -w 'HTTP %{http_code}\n' | tee "$LAB/evidence/terraform-upload.txt"
curl -fsS --netrc-file "$NX_AUTH_FILE" "$NX_URL/service/rest/v1/assets?repository=academy-ch12cp-terraform-hosted" | tee "$LAB/evidence/terraform-assets.json"
Do not rebuild the archive and call the result “the same module.” The SHA-256 you captured is an exact-byte identity for this lab artifact; it is not a signature or provenance attestation.
9. Exercise or simulate current Terraform authentication
If the Terraform Token Realm is enabled, request a 3.95+ bearer token into a protected file and generate an isolated CLI config. Do not print the token:
export TF_CLI_CONFIG_FILE="$LAB/terraform-home/terraform.rc"
curl -fsS --netrc-file "$NX_AUTH_FILE" "$NX_URL/repository/academy-ch12cp-terraform-group/v1/api/token" > "$LAB/terraform-home/token.json"
chmod 600 "$LAB/terraform-home/token.json"
python - <<'PYI'
from pathlib import Path
import json, os
lab=Path(os.environ['LAB'])
token=json.loads((lab/'terraform-home/token.json').read_text())['token']
text="""credentials "127.0.0.1:8081" {
token = "__TOKEN__"
}
host "academy-ch12.local" {
services = {
modules.v1 = "http://127.0.0.1:8081/repository/academy-ch12cp-terraform-group/v1/modules/"
}
}
"""
text=text.replace("__TOKEN__", token)
p=lab/'terraform-home/terraform.rc'
p.write_text(text); p.chmod(0o600)
PYI
rm -f "$LAB/terraform-home/token.json"
The fixture proves the safer credential model without requiring local DNS or a full Terraform infrastructure project. The dedicated Terraform course should own deeper provider/module client behavior.
10. Build the evidence packet
curl -fsS --netrc-file "$NX_AUTH_FILE" "$NX_URL/service/rest/v1/repositories" > "$LAB/evidence/repos-after.json"
python - <<'PYI'
from pathlib import Path
import os, json
lab=Path(os.environ['LAB'])
summary={
'nexus':'3.95.2 baseline; record actual server evidence separately',
'ansible_repo':'academy-ch12cp-ansible-hosted -> academy-ch12cp-ansible-group',
'terraform_repo':'academy-ch12cp-terraform-hosted -> academy-ch12cp-terraform-group',
'public_fallback_for_internal_namespace':False,
'manual_blob_or_database_edits':False,
'pro_only_export_import_used':False,
}
(lab/'evidence/adoption-summary.json').write_text(json.dumps(summary, indent=2)+'\n')
PYI
find "$LAB/evidence" -maxdepth 1 -type f -printf '%f\n' 2>/dev/null | sort > "$LAB/evidence/files.txt" || true
cat "$LAB/evidence/files.txt"
Review evidence files before sharing. Do not include
nexus.netrc, ansible.cfg, or
terraform.rc in a support bundle because they can
contain credentials.
11. Verification checklist
- The server version/edition and client versions are recorded.
- Ansible hosted/group recipes exist on the pinned build and the synthetic collection is visible.
- The Ansible group contains only hosted for the internal namespace; no accidental Galaxy fallback is required.
-
The Terraform module was uploaded under a documented
/v1/modulespath and its assets are visible. - Source archive checksum is captured and no claim confuses checksum with signature/provenance.
- Any token realm activation is documented as security configuration.
- No credential is printed, embedded in a repository URL, committed, or included in evidence.
- Export/import is not treated as a Community prerequisite.
12. Cleanup through supported operations
Delete the four disposable repositories through the Nexus UI after reviewing their names carefully. Do not delete blob-store files or database rows manually. Remove only the local lab directory after repository deletion is verified.
rm -f "$LAB/nexus.netrc" "$LAB/ansible-home/ansible.cfg" "$LAB/ansible-home/requirements.yml" "$LAB/terraform-home/terraform.rc"
unset NX_AUTH_FILE ANSIBLE_CONFIG ANSIBLE_COLLECTIONS_PATH TF_CLI_CONFIG_FILE
rm -rf "$LAB"
13. Operator adoption checklist
| Question | Ansible result | Terraform result |
|---|---|---|
| Protocol/client minimum | Galaxy v3; ansible-galaxy 2.9+ documented | Terraform CLI 0.13+; 1.x supported in current docs |
| Hosted/proxy/group | All three from 3.93 | Proxy 3.88 / hosted 3.89 / group 3.90 |
| Current auth | Ansible bearer realm; protected Base64 token field | Terraform Token Realm; non-URL bearer auth from 3.95 |
| Internal publication | Hosted collection archive | Hosted module/provider registry path |
| Public fallback control | Internal-only group for private namespace | Internal-only group/host service for private namespace |
| Migration caveat | Do not assume CE export/import | Do not assume CE export/import |
| Revalidate | Nexus/Ansible upgrades and realm changes | Nexus/Terraform/OpenTofu/upstream changes |
14. Knowledge check
Why does the checkpoint use hosted-only groups for the internal namespaces?
To prove internal content cannot silently fall through to a public upstream. It makes routing intent observable.
What state changes when a token realm is activated?
Security/authentication configuration. It does not create or modify package content by itself.
Why is the Terraform checksum useful but insufficient for trust?
It proves byte equality for the captured artifact, but does not prove trusted origin, authorization, provenance, or vulnerability safety.
Why are Export Assets and Import External Files absent from the mandatory workflow?
The current self-hosted feature matrix marks them Pro-only. Community learning must not depend on paid capabilities.
What makes the checkpoint complete rather than just two successful uploads?
It records compatibility assumptions, client routing, auth boundaries, repository state, identity/checksums, operational gaps, evidence, and safe cleanup.
15. Chapter summary and bridge to Chapter 13
You now have a repeatable way to adopt a format whose Nexus support is new or evolving: identify the protocol, pin versions, verify recipes and edition, isolate client/auth state, test synthetic content, record operational gaps, and revalidate after changes.
Chapter 13 narrows the focus from format adoption to proxy behavior itself: cache ages, negative cache, remote health, routing rules, repository health, and failure semantics.
Official references and version notes
- Sonatype: Download and 3.95.0–3.95.2 release notes.
- Sonatype: Self-Hosted feature matrix.
- Sonatype: Conan Repositories.
- Sonatype: Ansible Repositories, repository creation, and client configuration.
- Sonatype: Terraform Repositories, repository creation, client configuration, and CLI usage.
- Sonatype: Swift Repositories, repository creation, and SPM configuration.
- Sonatype: Nexus Repository API Reference.
- Sonatype: Repository Export and Repository Import — verify current Pro entitlement and format coverage before adoption.
Version-sensitive statements were rechecked on 2026-08-26. The mandatory lab pins Nexus Repository 3.95.2, which Sonatype's current download page lists as the latest downloadable self-hosted release and whose release notes date it to 2026-08-21. Java 21 remains the current Nexus runtime requirement. The mandatory path uses Community-compatible Ansible Galaxy and Terraform behavior and avoids depending on Pro-only export/import, user-token, staging, HA, or content-replication features.
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.