Chapter 32Lesson 05~240 minutes

Checkpoint Lab — Artifact Repositories, Nexus/Artifactory Integration, Package Promotion, Build Metadata, and Release Traceability

Publish one uniquely versioned candidate, verify repository digest and metadata, promote the same bytes, and produce an evidence packet tracing release back to Jenkins build/source.

CheckpointEvidence packetPromotionTraceabilityDigest continuityCleanup

Learning objectives

  • Predict state changes before mutating repository state.
  • Publish a unique candidate from a disposable agent.
  • Verify repository bytes independently from workspace bytes.
  • Promote without rebuilding and prove digest continuity.
  • Produce evidence and explicit limitations.

1. Scenario

A synthetic service named trace-widget must create a candidate, publish it into a local candidate repository, attach build metadata, verify it, promote the exact bytes into release state and prove the release maps to one Jenkins build/source SHA. No external account or paid plugin is required.

2. Predict before you run

  1. A new candidate coordinate will appear; nothing existing will be overwritten.
  2. Workspace and candidate SHA-256 will match.
  3. Promotion will not invoke a build tool.
  4. Candidate and release SHA-256 will match.
  5. Metadata will name exact job/build/source.
  6. A second attempt at the same coordinate will fail safely.

3. Preflight inventory

set -euo pipefail
printf 'date_utc='; date -u +%FT%TZ
printf 'source_sha='; git rev-parse HEAD
printf 'job=%s build=%s\n' "${JOB_NAME:-local-checkpoint}" "${BUILD_NUMBER:-0}"
printf 'build_url=%s\n' "${BUILD_URL:-local://build/0}"
printf 'node=%s workspace=%s\n' "${NODE_NAME:-local}" "${WORKSPACE:-$PWD}"
printf 'java='; java -version 2>&1 | head -1 || true
python3 --version
git --version

Also record Jenkins core/LTS and relevant plugin inventory from approved read-only views/API if your permissions allow. Script Console is not required.

4. Checkpoint script

Store as ci/repository-checkpoint.sh. It fails closed when a coordinate exists.

#!/usr/bin/env bash
set -euo pipefail
mkdir -p dist evidence lab-repo/candidates lab-repo/releases
SOURCE_SHA="$(git rev-parse HEAD)"
SHORT_SHA="$(printf '%s' "$SOURCE_SHA" | cut -c1-8)"
BUILD_NO="${BUILD_NUMBER:-0}"
VERSION="1.0.${BUILD_NO}-${SHORT_SHA}"
NAME="trace-widget"
ARTIFACT="dist/${NAME}-${VERSION}.txt"
printf 'name=%s\nversion=%s\nsource=%s\nbuild=%s\n' "$NAME" "$VERSION" "$SOURCE_SHA" "$BUILD_NO" > "$ARTIFACT"
WORKSPACE_SHA="$(sha256sum "$ARTIFACT" | awk '{print $1}')"
printf '%s\n' "$WORKSPACE_SHA" > evidence/workspace.sha256
python3 -c 'import json,os,sys,pathlib; p,d,s=sys.argv[1:]; pathlib.Path("evidence/build-metadata.json").write_text(json.dumps({"artifact":pathlib.Path(p).name,"sha256":d,"job":os.getenv("JOB_NAME","local-checkpoint"),"buildNumber":os.getenv("BUILD_NUMBER","0"),"buildUrl":os.getenv("BUILD_URL","local://build/0"),"sourceSha":s,"node":os.getenv("NODE_NAME","local")},indent=2)+"\\n")' "$ARTIFACT" "$WORKSPACE_SHA" "$SOURCE_SHA"
CAND="lab-repo/candidates/com/example/${NAME}/${VERSION}"
REL="lab-repo/releases/com/example/${NAME}/${VERSION}"
test ! -e "$CAND" || { echo "candidate exists: $CAND" >&2; exit 31; }
test ! -e "$REL" || { echo "release exists: $REL" >&2; exit 32; }
mkdir -p "$CAND"
cp "$ARTIFACT" evidence/build-metadata.json "$CAND/"
CAND_FILE="$CAND/$(basename "$ARTIFACT")"
CAND_SHA="$(sha256sum "$CAND_FILE" | awk '{print $1}')"
test "$CAND_SHA" = "$WORKSPACE_SHA"
mkdir -p "$REL"
cp "$CAND"/* "$REL/"
REL_FILE="$REL/$(basename "$ARTIFACT")"
REL_SHA="$(sha256sum "$REL_FILE" | awk '{print $1}')"
test "$REL_SHA" = "$CAND_SHA"
printf 'candidate=%s\nrelease=%s\nsha256=%s\n' "$CAND" "$REL" "$REL_SHA" > evidence/traceability.txt

5. Checkpoint Jenkinsfile

pipeline {
  agent { label 'repo-lab' }
  options { timestamps(); disableConcurrentBuilds(); buildDiscarder(logRotator(numToKeepStr: '20')) }
  stages {
    stage('Preflight') { steps { sh 'git rev-parse HEAD && java -version && python3 --version' } }
    stage('Publish + verify + promote') { steps { sh 'bash ci/repository-checkpoint.sh' } }
    stage('Negative overwrite test') {
      steps {
        sh '''set -euo pipefail
          set +e
          bash ci/repository-checkpoint.sh > evidence/second-run.txt 2>&1
          rc=$?
          set -e
          printf 'second_run_exit=%s\n' "$rc" >> evidence/second-run.txt
          test "$rc" -ne 0
        '''
      }
    }
  }
  post { always { archiveArtifacts artifacts: 'evidence/**', fingerprint: true, allowEmptyArchive: true } }
}

The negative test is intentional. If it can overwrite the same coordinate, the checkpoint fails.

6. Required evidence packet

Evidence Capture
Controller/runtime Jenkins LTS/core, Java, advisory date, repository plugin versions if installed
Build Job full name, build number/URL/cause, source SHA, Jenkinsfile/library refs
Agent Node/label/executor/workspace and tool versions
Artifact Filename, size, workspace SHA-256
Candidate Exact coordinate and repository SHA-256
Metadata Job/build/source/digest mapping
Promotion Source/target coordinate and actor/response if external
Release Release SHA-256 equal to candidate SHA-256
Negative test Safe non-zero result for duplicate coordinate
Limitations What local simulation does not prove about real Nexus/Artifactory auth, HA, retention or format metadata

7. Verification checklist

  • Job ran on repo-lab, not the built-in node.
  • Source SHA was captured before artifact creation.
  • Candidate coordinate is unique.
  • Workspace SHA-256 equals candidate SHA-256.
  • No build command runs between candidate verification and promotion.
  • Release SHA-256 equals candidate SHA-256.
  • Metadata ties release evidence to one job/build/source.
  • Duplicate-coordinate attempt fails without deleting/modifying release.
  • No real secret appears in logs or evidence.

8. Optional real-server extension

If you already have a disposable local Nexus or Artifactory lab, repeat the same identity chain with fake/scoped credentials. Nexus raw: unique PUT + GET + digest. Artifactory/JFrog: publish Build-Info and perform build promotion or copy/move, then verify digest. Cloud/paid services are not required.

9. Cleanup / rollback

set -euo pipefail
test -d lab-repo
case "$(pwd)" in /|/home|/var|/tmp) echo 'unsafe working directory' >&2; exit 70;; esac
rm -rf -- lab-repo dist
# Keep archived Jenkins evidence while reviewing the checkpoint.

Remove a disposable credential/job/agent only by exact ID/name after confirming no other lab uses it. Never delete repository objects by “latest.”

10. Claims and limits

Supported claim Not supported
Release bytes equal verified candidate bytes by SHA-256. The artifact is vulnerability-free or safe for production.
Coordinates/metadata trace object to one Jenkins build/source SHA. Every repository automatically preserves equivalent metadata.
The script refuses an existing coordinate. All Nexus/Artifactory policies behave exactly like the local simulation.
This promotion did not rebuild. Future promotion implementations will preserve bytes without independent verification.

11. Production model and bridge to Chapter 33

You now have durable artifact identity and lifecycle: unique coordinates, least-privilege publication, build metadata, retrieval verification, promotion without rebuild and consumer traceability. Chapter 33 adds independent testing and quality evidence—JUnit, coverage, SonarQube, Selenium/JMeter and quality gates—without confusing tool execution, report ingestion and policy outcome.

Next chapter

Chapter 33 — Testing and Quality Pipelines: JUnit, Coverage, SonarQube, Selenium, JMeter, and Quality Gates

Carry the verified evidence and operating discipline from this chapter into the next chapter.

Knowledge check

Answer before revealing the explanation.

1. Candidate and release coordinates differ but SHA-256 matches. Is that valid?

2. The duplicate-coordinate negative test exits 0. What next?

3. Why is metadata not a substitute for digest?

4. What bridges repository state to deployment traceability?

Official references and version notes

Repository formats, Jenkins plugins, credentials models and promotion APIs evolve; prefer current primary documentation.

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
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.