Chapter 28Lesson 05~245 minutes

Checkpoint Lab — REST API, CLI, Script Console, Groovy Administration, Safe Automation, and Administrative Guardrails

Build a small safe administration client that proves the Jenkins controller and exact job identity, triggers only one disposable job, captures queue and build IDs, verifies the terminal result, and refuses an ambiguous destructive target such as “latest” without ever issuing a delete request.

Checkpoint labSafe clientExact jobQueue / build evidenceRefusal guardsCleanup

Learning objectives

  • Build a small safe administration client around an exact disposable Jenkins job.
  • Predict and verify controller/job/queue/build/agent state transitions.
  • Capture request/response and run evidence without exposing the API token.
  • Refuse an ambiguous destructive target before constructing a mutation request.
  • Produce a cleanup/limitations record that distinguishes API acceptance from build success.

1. Checkpoint scenario

Your platform team wants a tiny automation utility that can verify a controller, inspect admin-lab/exact-job, trigger that one job, follow it through the queue, and report the terminal result. A previous prototype also accepted latest for destructive operations. Your replacement must reject that ambiguity before any destructive HTTP request exists.

Authorized disposable lab only. The checkpoint performs one build trigger and no destructive Jenkins API operation. The “delete latest” case is a client-side refusal test, not a delete test.

2. Baseline and assumptions

Component Pinned assumption
Jenkins 2.568.3 LTS
Controller/agent Java 21 (25 also supported by this LTS)
Script Security reference 1422.v06869826dd9b_
CLI jenkins-cli.jar downloaded from this controller; WebSocket mode
Controller built-in executors 0
Agent trusted disposable linux-ci, one executor
Job admin-lab/exact-job
Credential disposable ch28-api API token stored outside workspace/evidence

3. Controller/item/identity preflight

Before the run, capture:

export JENKINS_URL='http://127.0.0.1:8080'
mkdir -p checkpoint-evidence
curl -fsS -D checkpoint-evidence/controller-headers.txt -o /dev/null "$JENKINS_URL/login"
grep -i '^X-Jenkins:' checkpoint-evidence/controller-headers.txt

Verify the disposable agent is online and built-in node has zero executors. Verify ch28-api can read/build the exact lab job but lacks Overall/Administer/Script Console capability. Create the protected auth file as in Lesson 2; record only its mode/path, never contents.

4. Predict state changes before execution

Write these predictions into checkpoint-evidence/predictions.txt:

  1. Controller configuration will not change; only a queue item and one new build record will be created.
  2. The trigger response will identify one queue item, which will later resolve to one numeric build on linux-ci.
  3. The build result/artifact can be verified independently from the trigger response.
  4. The refusal test for latest will terminate client-side and create no Jenkins deletion/cancellation request.

5. Safe client contract

The client accepts no arbitrary job argument in this checkpoint. Its target is an allowlisted full name. It must:

  1. GET the exact job and require fullName == admin-lab/exact-job.
  2. Require buildable == true.
  3. POST only to that job’s /build endpoint using API-token authentication.
  4. Require a queue Location header and follow only that queue item.
  5. Require a concrete executable.number/url before build verification.
  6. Poll the numeric build until terminal result.
  7. Refuse destructive aliases before any request construction.

Use the safe_admin.py implementation from Lesson 2 or an equivalent implementation with these invariants.

6. Execute and capture API evidence

python3 safe_admin.py \
  > checkpoint-evidence/client-stdout.txt \
  2> checkpoint-evidence/client-stderr.txt
STATUS=$?
printf 'client_exit=%s\n' "$STATUS" | tee checkpoint-evidence/client-exit.txt

Because the script deliberately runs the refusal test after verifying the build, a nonzero final exit is expected. Review stdout to prove a concrete queue/build was observed first, then stderr/exit text for REFUSE destructive target. If you separate the refusal into a second command, record both exit codes explicitly.

7. Independently verify Jenkins state

Do not trust the client’s own summary as the only evidence. Query the exact job/build through a second read-only path:

JOB_URL="$JENKINS_URL/job/admin-lab/job/exact-job"
curl --config "$HOME/.config/ch28/curl.conf" -fsS \
  "$JOB_URL/api/json?tree=fullName,lastBuild[number,url,result]" \
  > checkpoint-evidence/job-after.json

java -jar "$HOME/.config/ch28/jenkins-cli.jar" \
  -s "$JENKINS_URL" -webSocket -auth @"$HOME/.config/ch28/cli-auth.txt" who-am-i \
  > checkpoint-evidence/cli-whoami.txt

Open the captured build URL and confirm its console shows linux-ci/workspace identity and the archived result.txt.

8. Prove no ambiguous destructive request was sent

The refusal logic must execute before forming a URL such as /lastBuild/doDelete. Search your source/evidence:

grep -n "REFUSE destructive target" safe_admin.py checkpoint-evidence/client-stderr.txt || true

The client contains no code path that sends a DELETE/POST for latest. This is stronger than sending the request and hoping Jenkins rejects it.

9. Required evidence packet

Evidence What it proves
controller headers/version + base URL target controller identity
automation username/auth method + auth-file mode identity/secret-handling contract without secret value
exact job preflight JSON full item path/buildable state
trigger status/Location (redacted) request accepted and queue item identity
queue JSON task/queue ID and executable transition
numeric build JSON + console/artifact observation terminal run identity/result and execution context
CLI who-am-i independent identity verification
safe client source/hash guard logic actually executed
refusal output/exit ambiguous destructive target blocked client-side
predictions/results/limitations note causal learning and lab boundaries

10. Cleanup and rollback

  1. Revoke the disposable ch28-api token.
  2. Delete ~/.config/ch28/curl.conf and cli-auth.txt; retain only non-secret digests/metadata if needed.
  3. Remove the synthetic admin-lab job/folder using the same controlled lab owner that created it, after preserving desired evidence.
  4. Destroy the disposable agent/controller. Do not copy JENKINS_HOME or auth files into the evidence archive.
  5. Verify the checkpoint created no external deployment/publication state.

11. What Chapter 28 adds to the production operating model

You can now automate Jenkins administration without treating every task as privileged Groovy: identities are scoped, exact resources are named, API/CLI contracts are bounded, CSRF behavior is understood rather than disabled, side effects are followed through queue/build state, credentials stay out of logs, and ambiguous/destructive targets are rejected before mutation.

Next chapter

Security Hardening, CSRF, Agent-to-Controller Controls, Script Security, CSP, TLS, and Reverse Proxies

Chapter 29 turns these interface-level safeguards into a controller-wide hardening model for web, script, agent and reverse-proxy trust boundaries.

Knowledge check

Answer before revealing the explanation.

1. What identities must the checkpoint correlate?

2. Why does the client refuse an ambiguous destructive target instead of asking Jenkins to resolve it?

3. What proves the trigger was bounded to one job?

4. What should be retained from authentication handling?

5. Why is Script Console absent from the checkpoint mutation path?

Official references and version notes

Verified baseline — 17 September 2026. Labs target Jenkins 2.568.3 LTS with Java 21; Jenkins 2.568.3 is tested with Java 21 and 25. The lab uses only Jenkins core Remote API/CLI plus Script Security 1422.v06869826dd9b_ as the current Groovy-sandbox reference. On modern Jenkins, the CLI client defaults to WebSocket; HTTP mode is explicit, and file-based/environment authentication is preferred over exposing a token as a command-line argument. API-token-authenticated requests are exempt from CSRF crumbs; password/session POSTs require the crumb/session flow. Re-check endpoint/plugin/security documentation before reusing automation.

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.