Checkpoint Lab — Tags, Releases, Release CLI, Changelogs, Evidence, Asset Links, and Release-Orchestration Pipelines
Publish and verify a disposable versioned release from an exact SHA, prove artifact digest and evidence, and safely supersede or remove only that identified release.
Learning objectives
Checkpoint outcomes
- Publish a disposable release whose tag resolves to a pre-recorded exact SHA.
- Verify that the released asset digest equals the digest captured before publication.
- Capture GitLab release/evidence metadata and pipeline/job/tool identity without exposing credentials.
- Demonstrate a safe superseding/update path and an exact guarded cleanup path.
- Produce a compact evidence packet another engineer can independently audit.
1. Mission and success criteria
You are the release engineer for a synthetic project. Build
candidate A once, record its SHA and digest, publish a
disposable version from that exact identity, and prove that a
consumer receives the same bytes. Then simulate a metadata
correction or publish a superseding lab version. Finally, remove
only the identified release record if cleanup is required.
2. Assumptions and preflight
| Item | Mandatory assumption / evidence |
|---|---|
| Project | Disposable project you own/control, or local faithful simulation. |
| Tier | Mandatory path uses Free-capable release/changelog/protected-tag concepts. No Premium-only feature is required. |
| Runner/executor | Any authorized runner capable of Git/shell; record executor/image if using CI. |
| CLI |
Current docs: glab >= 1.58.0 for the
release-keyword path. Record exact version.
|
| Credentials |
Use CI_JOB_TOKEN for supported release API/CLI
calls; examples contain no real secrets.
|
| Namespace |
Only tags matching v0.0.0-ch22-lab.* may be
created/deleted by this lab.
|
git status --short
git rev-parse HEAD
git --version
glab --version || true
printf 'source=%s ref=%s sha=%s pipeline=%s job=%s\n' \
"${CI_PIPELINE_SOURCE:-local}" "${CI_COMMIT_REF_NAME:-local}" \
"${CI_COMMIT_SHA:-$(git rev-parse HEAD)}" "${CI_PIPELINE_ID:-local}" "${CI_JOB_ID:-local}"
3. Predict state changes before execution
| Prediction | Before | After expected | Independent verification |
|---|---|---|---|
| Tag identity | No lab tag |
One exact LAB_TAG points to
TARGET_SHA
|
git rev-parse "$LAB_TAG^{}". |
| Release record | No release for lab tag | One release references the same tag/SHA | glab release view or Releases API. |
| Artifact identity | Local verified digest exists | Consumer download has identical digest | sha256sum -c on re-downloaded asset. |
| Evidence | Only local evidence files | GitLab evidence path + local manifest/pipeline IDs retained | Release API JSON plus evidence packet. |
| Cleanup | No mutation selected | At most one exact release record removed; tag removal separate | GET exact release/tag after action. |
4. Setup exact candidate and evidence manifest
set -eu
mkdir -p release-assets checkpoint-evidence
printf 'chapter22 checkpoint payload\n' > release-assets/checkpoint.txt
git add release-assets/checkpoint.txt
git commit -m "Prepare Chapter 22 checkpoint payload
Changelog: added" || true
TARGET_SHA="$(git rev-parse HEAD)"
ARTIFACT_SHA256="$(sha256sum release-assets/checkpoint.txt | awk '{print $1}')"
LAB_ID="${CI_PIPELINE_ID:-$(date +%Y%m%d%H%M%S)}"
LAB_TAG="v0.0.0-ch22-lab.${LAB_ID}"
printf 'TARGET_SHA=%s\nARTIFACT_SHA256=%s\nLAB_TAG=%s\n' \
"$TARGET_SHA" "$ARTIFACT_SHA256" "$LAB_TAG" \
| tee checkpoint-evidence/identity.env
Do not proceed if git status --short reveals unrelated
uncommitted content that could confuse the candidate.
5. Bind the version to the exact SHA
case "$LAB_TAG" in v0.0.0-ch22-lab.*) ;; *) exit 2 ;; esac
git tag -a "$LAB_TAG" "$TARGET_SHA" -m "Chapter 22 disposable checkpoint"
RESOLVED_SHA="$(git rev-parse "$LAB_TAG^{}")"
printf 'resolved=%s expected=%s\n' "$RESOLVED_SHA" "$TARGET_SHA" \
| tee checkpoint-evidence/tag-resolution.txt
test "$RESOLVED_SHA" = "$TARGET_SHA"
Real GitLab path: after review, push only the exact lab tag. Local simulation: retain the local tag and continue; the evidence packet must state that no server-side release was created.
6. Generate or simulate bounded changelog notes
PREVIOUS_REF="${PREVIOUS_REF:-$(git rev-list --max-parents=0 HEAD)}"
VERSION="${LAB_TAG#v}"
if command -v glab >/dev/null 2>&1 && [ -n "${CI_API_V4_URL:-}" ]; then
glab changelog generate \
--from "$PREVIOUS_REF" \
--to "$TARGET_SHA" \
--version "$VERSION" > checkpoint-evidence/release-notes.md
else
{
printf '## %s (local simulation)\n\n' "$VERSION"
git log "$PREVIOUS_REF..$TARGET_SHA" --format='- %h %s'
} > checkpoint-evidence/release-notes.md
fi
printf '\nSource SHA: `%s`\nArtifact SHA-256: `%s`\n' \
"$TARGET_SHA" "$ARTIFACT_SHA256" >> checkpoint-evidence/release-notes.md
7. Publish the exact disposable release
Use one publication mechanism. This checkpoint uses
glab because it makes exact --ref and
later metadata update behavior visible. In CI, enable job-token
auto-login.
export GLAB_ENABLE_CI_AUTOLOGIN=true
# Guard that the tag target is still the verified candidate.
test "$(git rev-parse "$LAB_TAG^{}")" = "$TARGET_SHA"
RAW_URL="${CI_PROJECT_URL}/-/raw/${TARGET_SHA}/release-assets/checkpoint.txt"
ASSET_JSON=$(printf '[{"name":"checkpoint.txt","url":"%s","link_type":"other"}]' "$RAW_URL")
glab release create "$LAB_TAG" \
--ref "$TARGET_SHA" \
--name "Disposable Chapter 22 $LAB_TAG" \
--notes-file checkpoint-evidence/release-notes.md \
--assets-links "$ASSET_JSON" \
--repo "$CI_PROJECT_PATH"
If the tag is already pushed and exact, --ref remains
useful documentation of intent. If the release already exists
unexpectedly, stop and inspect it; do not treat an update as
equivalent to first publication without understanding the existing
state.
8. Verify server-side release/evidence identity
GLAB_ENABLE_CI_AUTOLOGIN=true \
glab release view "$LAB_TAG" --repo "$CI_PROJECT_PATH" \
| tee checkpoint-evidence/release-view.txt
curl --fail --silent --show-error \
--header "JOB-TOKEN: $CI_JOB_TOKEN" \
"$CI_API_V4_URL/projects/$CI_PROJECT_ID/releases/$LAB_TAG" \
| tee checkpoint-evidence/release.json
# Extract/display only non-secret fields if jq is available.
if command -v jq >/dev/null 2>&1; then
jq '{tag_name,name,commit:.commit.id,evidence_file_path:.assets.evidence_file_path}' \
checkpoint-evidence/release.json
fi
Verify that the API’s commit identity and the tag resolution agree
with TARGET_SHA. Record the evidence file path. Do not
claim the evidence snapshot proves external asset immutability.
9. Consumer verification: re-download and hash
curl --fail --location "$RAW_URL" -o checkpoint-evidence/downloaded.txt
printf '%s %s\n' "$ARTIFACT_SHA256" checkpoint-evidence/downloaded.txt \
> checkpoint-evidence/expected-download.sha256
sha256sum -c checkpoint-evidence/expected-download.sha256
This is the checkpoint’s strongest end-to-end assertion: a consumer using the immutable asset coordinate obtains the same bytes that were hashed before publication.
10. Metadata correction or superseding release
First demonstrate that metadata can change without changing the
tag/SHA. For example, add a clarification to the notes with
glab release create on the same tag (which updates
existing release information) or the Releases API PUT.
Confirm afterward that the resolved tag SHA and artifact digest are
unchanged.
For a true code/artifact correction, do not move
the old public tag. Create a new candidate, new digest, and new
version/tag such as $LAB_TAG.1 in the disposable
namespace, then mark the old notes as superseded if desired.
11. Intentional failure: authorization or wrong cleanup target
Choose one: (A) in an authorized disposable GitLab project, attempt
a protected-tag/release operation as an ineligible actor and
preserve the denial; or (B) locally set
BAD_TAG=v1.0.0 and prove the cleanup guard refuses it.
Option B is mandatory-safe and requires no second account.
BAD_TAG="v1.0.0"
case "$BAD_TAG" in
v0.0.0-ch22-lab.*) echo "unexpectedly allowed"; exit 1 ;;
*) echo "PASS: cleanup guard rejected non-lab tag $BAD_TAG" ;;
esac
12. Bounded cleanup / rollback
Preserve the evidence packet before cleanup. Then delete only the exact release record created by this lab. Remember: the Releases API does not delete the associated Git tag.
case "$LAB_TAG" in v0.0.0-ch22-lab.*) ;; *) exit 2 ;; esac
test "$(git rev-parse "$LAB_TAG^{}")" = "$TARGET_SHA"
curl --fail --request DELETE \
--header "JOB-TOKEN: $CI_JOB_TOKEN" \
"$CI_API_V4_URL/projects/$CI_PROJECT_ID/releases/$LAB_TAG"
# Verify release record is gone (expect not-found response).
# Keep or separately delete the lab tag according to your lab policy.
# Never delete any tag outside the exact chapter namespace.
If you choose to keep the release for course evidence, skip deletion and document that choice. Cleanup must be deliberate, not automatic destruction of useful evidence.
13. Required evidence packet
| File / record | Must contain |
|---|---|
identity.env |
Exact tag, source SHA, artifact SHA-256. |
tag-resolution.txt |
Resolved tag target equals source SHA. |
release-notes.md |
Bounded change description + immutable identity fields. |
release.json |
Release tag/name/commit/evidence path; no tokens. |
| Pipeline/job record | Pipeline source/ref/SHA, pipeline ID, job ID, actor, runner/executor/image/tool version. |
expected-download.sha256 |
Consumer-side verification of exact bytes. |
| Authorization/failure evidence | Denied actor or cleanup-guard refusal, if applicable. |
| Assumptions note | Tier/offering, simulation vs live path, limitations, cleanup decision. |
14. Final verification checklist
-
Release tag was created from or verified against
TARGET_SHA. - Artifact digest was captured before release publication.
- Release publication used an explicit tag/ref and recorded tool/token class.
- Release API commit identity matches tag/source identity.
- Asset coordinate is immutable/versioned and re-download hash matches.
- No secret was printed or embedded in notes/URLs.
- Any superseding release has a new identity rather than a moved production tag.
- Cleanup targets only the exact Chapter 22 lab release/tag namespace.
Knowledge check
Which two predictions must be proven independently before calling the release reproducible?
At minimum, the tag must resolve to the predicted exact source SHA, and a consumer download must match the predicted artifact digest.
Why is the release evidence JSON not sufficient by itself?
It captures GitLab-associated metadata, but the checkpoint also requires independent artifact byte verification and source/tag identity.
If the release notes are wrong but the artifact/tag are correct, what layer should you change?
Release metadata only. Do not rebuild the artifact or move the tag.
If a real artifact defect is found after publication, should you force-move the existing production tag?
No. Preserve the published identity and create a new corrected version/tag, then supersede/deprecate the old one according to policy.
What does deleting the exact release record through the Releases API leave behind?
The associated Git tag remains; tag cleanup is a separate controlled action.
15. What Chapter 22 adds to the production operating model
You now have a release contract that links source SHA, tested artifact digest, version/tag, publication identity, GitLab evidence, asset coordinates, consumer verification, authorization, and recovery. That closes the gap between “pipeline produced something” and “a versioned object can be independently verified later.”
Chapter 23 extends the same contract into GitLab’s Container Registry, Package Registry, Generic Packages, and Dependency Proxy, where immutable versions and digests become the durable distribution layer behind release records.
Version and compatibility note
GitLab and GitLab Runner evolve continuously. Treat version-sensitive YAML, runner/executor behavior, APIs, security features, policy controls, tiers, and deprecations as assumptions to verify against the current official GitLab documentation before production use. Preserve the exact project/ref/SHA, compiled configuration, pipeline/job IDs, runner/tool versions, and external target evidence used for any reproducible lab or incident record.
Official references and version notes
Documentation verification date: 2026-09-12.
Releases, changelogs, the Releases API, release links, base release
evidence, and role-based protected tags are documented across
Free/Premium/Ultimate unless a narrower tier is explicitly called
out. The current YAML release flow uses
glab; current docs require glab 1.58.0 or
later. release-cli was deprecated in GitLab 18.0 and is
planned for removal in 20.0. The checkpoint requires only
Free-capable release primitives or a local simulation.
Paid/admin-only release governance is optional and must remain
inside an authorized disposable project.
- Releases — official reference.
- CI/CD YAML release keyword — official reference.
- GitLab Release CLI migration — official reference.
- glab release create — official reference.
- Changelogs — official reference.
- Release evidence — official reference.
- Project Releases API — official reference.
- Release links API — official reference.
- Protected tags — official reference.
- CI job token — official reference.
Current assumptions used in this chapter: Version-sensitive YAML, Runner/executor behavior, APIs, security features, policy controls, tiers, and deprecations must be verified against the exact GitLab, GitLab Runner, tool, and external-system versions used in production. Preserve the exact project/ref/SHA, compiled configuration, pipeline/job IDs, runner/tool versions, and external target evidence used for reproducible work.
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.