Checkpoint Lab — Artifacts, Retention, Cross-Job Data, and Workflow Result Management
The checkpoint combines the chapter into one auditable transfer. A tiny build file is uploaded, its identity and digests are carried downstream, an intentional name mismatch is preserved as the first failure, the workflow is repaired to download by artifact ID, and the final evidence packet records run/SHA/retention/provenance before optional cleanup.
Learning objectives
- Predict artifact identity, retention, runner and consumer state before executing the checkpoint.
- Preserve a deliberate name-selection failure as first-failure evidence rather than overwriting history.
- Repair the pipeline by transporting artifact ID and verifying artifact/file digests downstream.
- Record REST metadata tying artifact ID/digest/expiry to the exact producing workflow run and SHA.
- Perform optional exact-ID deletion only after the final evidence packet is retained.
1. Checkpoint scenario and invariant
You own a disposable repository
gha-artifact-checkpoint. One job creates a tiny build
manifest and uploads it. A second job must consume exactly that
artifact and prove its content came from the current source SHA. The
first run is intentionally broken by a name mismatch. You preserve
the failure, repair the workflow to pass the artifact ID explicitly,
rerun, verify digest/content/retention metadata, then optionally
delete only the repaired lab artifact.
Delivery invariant: a downstream job may accept build evidence only when artifact identity, producing run/SHA, integrity and retention metadata all reconcile.
2. Current assumptions and preflight
| Item | Checkpoint assumption |
|---|---|
| Platform | GitHub.com; no GHES artifact-v7 backend assumption |
| Runner | ubuntu-24.04 |
| Upload action |
actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
— v7.0.1
|
| Download action |
actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
— v8.0.1
|
| Credentials |
only ephemeral GITHUB_TOKEN; Actions read for
metadata, optional Actions write for exact-ID cleanup
|
| External systems | none |
| Retention |
one-day disposable artifact; verify actual
expires_at
|
| Sensitive data | none; synthetic manifest only |
Before running, predict: (1) the producer creates exactly one artifact record with a unique ID/digest tied to the run; (2) the intentionally broken consumer fails despite the artifact existing because it requests the wrong name; (3) after repair, the consumer downloads the exact ID and the extracted file SHA equals the producer's file SHA; (4) optional cleanup deletes the artifact record only after evidence is captured.
3. Attempt 1 — intentionally broken name selection
name: artifact-checkpoint
on:
workflow_dispatch:
permissions: {}
jobs:
build:
runs-on: ubuntu-24.04
outputs:
artifact_id: ${{ steps.upload.outputs.artifact-id }}
artifact_digest: ${{ steps.upload.outputs.artifact-digest }}
file_sha256: ${{ steps.hash.outputs.sha256 }}
steps:
- name: Create build manifest
shell: bash
run: |
mkdir -p dist
printf 'sha=%s
run=%s
attempt=%s
' "$GITHUB_SHA" "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > dist/manifest.txt
- id: hash
shell: bash
run: |
sha="$(sha256sum dist/manifest.txt | awk '{print $1}')"
echo "sha256=$sha" >> "$GITHUB_OUTPUT"
- id: upload
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: manifest-${{ github.run_id }}
path: dist/manifest.txt
if-no-files-found: error
retention-days: 1
include-hidden-files: false
consume:
needs: build
runs-on: ubuntu-24.04
steps:
- name: Broken selection — preserve this failure
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: manifest
path: ${{ runner.temp }}/incoming
Do not “fix” Attempt 1 by renaming the artifact in the UI or deleting/re-uploading it. Save the run ID, attempt, head SHA, producer logs, upload artifact ID/digest, and the consumer's not-found selection error.
4. Repair — consume the artifact identity, not a naming assumption
Keep the producer unchanged. Replace the consumer with ID-based
selection and explicit verification. Add a metadata inspection step
with only actions: read.
consume:
needs: build
runs-on: ubuntu-24.04
permissions:
actions: read
env:
GH_TOKEN: ${{ github.token }}
ARTIFACT_ID: ${{ needs.build.outputs.artifact_id }}
UPLOAD_DIGEST: ${{ needs.build.outputs.artifact_digest }}
EXPECTED_FILE_SHA: ${{ needs.build.outputs.file_sha256 }}
steps:
- name: Download by exact artifact ID
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
artifact-ids: ${{ needs.build.outputs.artifact_id }}
path: ${{ runner.temp }}/incoming
digest-mismatch: error
- name: Verify source/content
shell: bash
run: |
file="$RUNNER_TEMP/incoming/manifest.txt"
test -f "$file"
grep -Fx "sha=$GITHUB_SHA" "$file"
actual="$(sha256sum "$file" | awk '{print $1}')"
test "$actual" = "$EXPECTED_FILE_SHA"
- name: Record GitHub artifact metadata
shell: bash
run: |
gh api -H 'X-GitHub-Api-Version: 2026-03-10' "repos/$GITHUB_REPOSITORY/actions/artifacts/$ARTIFACT_ID" --jq '{id,name,size_in_bytes,digest,expired,created_at,expires_at,workflow_run}'
5. Optional cleanup after evidence retention
After the repaired run is verified and the evidence packet is
copied, you may add a separate manual/boolean-gated cleanup job with
actions: write. It must delete only the exact artifact
ID received from the producer.
cleanup:
if: ${{ inputs.delete_after && needs.consume.result == 'success' }}
needs: [build, consume]
runs-on: ubuntu-24.04
permissions:
actions: write
env:
GH_TOKEN: ${{ github.token }}
ARTIFACT_ID: ${{ needs.build.outputs.artifact_id }}
steps:
- shell: bash
run: |
test -n "$ARTIFACT_ID"
gh api --method DELETE -H 'X-GitHub-Api-Version: 2026-03-10' "repos/$GITHUB_REPOSITORY/actions/artifacts/$ARTIFACT_ID"
If your workflow does not define delete_after, perform
cleanup through the Actions UI or an explicitly authorized local
gh api command instead. Cleanup is not part of the
correctness proof.
6. Prediction and reconciliation table
| Prediction | Attempt 1 expected | Repaired run expected | Independent verification |
|---|---|---|---|
| Artifact publication | producer succeeds; one artifact exists | producer succeeds; one new artifact record exists | upload outputs + run UI/REST |
| Consumer selection |
fails because manifest name does not exist
|
succeeds by exact artifact ID | download log + ID |
| Integrity | artifact digest exists even though consumer fails | download digest validation passes | upload digest + download action + REST digest |
| Source binding | artifact belongs to Attempt 1 SHA | new artifact belongs to repaired run SHA | REST workflow_run.head_sha + manifest line |
| Retention | one-day request | one-day request | REST expires_at |
| Deletion | none before evidence | optional exact-ID deletion only | DELETE 204 + later metadata no longer available |
7. Required evidence packet
| Evidence | Record |
|---|---|
| Workflow manifest | exact action SHAs, path/name, retention, hidden-file policy and permissions |
| Attempt 1 identity | run ID, attempt, event, ref/head SHA |
| Attempt 1 first failure | download name requested and not-found/error log; producer artifact ID/digest retained |
| Repaired identity | new run ID/attempt and exact source SHA |
| Artifact identity | artifact ID, name, upload digest, URL if useful |
| Content integrity | producer file SHA and consumer recomputed file SHA |
| Artifact metadata | size, REST digest, created_at, expires_at, expired, workflow_run.id/head_sha |
| Runner/tool evidence |
ubuntu-24.04, action SHAs, optional
gh --version for API inspection
|
| Cleanup | whether retained to expiry or exact-ID deletion was performed, with authorization/response |
| Limitations | GitHub.com artifact backend; no cache, release, cloud, deployment or attestation generated in this checkpoint |
8. Free/local faithful simulation
If Actions is unavailable, simulate the transport contract locally:
create manifest.txt, compute SHA-256, copy it into an
ID-named temporary directory, persist a JSON metadata record
containing fake artifact ID/run/SHA/expiry, copy the file into a
fresh consumer directory, and compare hashes. This proves the
architecture of explicit identity + durable file transport, but it
does not validate GitHub artifact service IDs,
retention enforcement, action digest behavior or API permissions.
Record those limitations.
9. Cleanup and rollback
Delete only disposable resources. If the artifact remains, let one-day retention expire or delete its exact ID after saving evidence. Delete the throwaway repository when finished. No external deployment, package, cloud resource, self-hosted runner or real credential exists, so there is no hidden infrastructure rollback.
10. What Chapter 13 adds to the operating model
You can now treat files as governed run outputs: the producer and source revision are recorded, the artifact has a service identity and digest, consumers select an exact record, retention/sensitivity are deliberate, and cleanup happens after evidence rather than instead of evidence. Chapter 14 turns to Dependency Caching, Cache Keys, Restore Strategies, and Performance—a deliberately different persistence mechanism optimized for speed rather than provenance.
Knowledge check
Why must Attempt 1 remain available after the repair?
It is the first-failure evidence proving the original problem was name selection, not missing producer output. A repaired run is new evidence, not a rewrite of history.
Why does the repaired consumer use
artifact-ids?
The producer already has the exact artifact service ID. Passing it explicitly removes hidden coupling to a naming convention.
What two different digests/hashes are useful in the checkpoint?
The upload/service artifact digest for artifact integrity and the file SHA-256 for the extracted manifest content expected by the consumer.
Does optional cleanup prove the pipeline is correct?
No. Correctness is build/upload/identity/download/verification/metadata reconciliation. Cleanup only tests lifecycle deletion after evidence is retained.
What concept does Chapter 14 intentionally separate from this checkpoint?
Caching: reusable acceleration state selected by keys/restore semantics, not authoritative run evidence with artifact identity/retention.
Official references and version notes
- GitHub Docs — Workflow artifacts — artifact purpose, cache distinction and attestation context.
- GitHub Docs — Store and share data with workflow artifacts — upload/download, retention, cross-job transfer and digest validation.
- GitHub REST API — Actions artifacts — artifact ID, size, digest, expiration, download and delete endpoints.
-
actions/upload-artifact v7.0.1
— upload action pinned to
043fb46d1a93c77aae656e7c1c64a875d1fc6a0a. -
actions/download-artifact v8.0.1
— download action pinned to
3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c. - GitHub Docs — Artifact attestations — signed provenance is separate from ordinary artifact storage/digest verification.
Version-sensitive behavior was rechecked on
2026-09-09. Mandatory examples target GitHub.com
and ubuntu-24.04.
actions/upload-artifact v7.0.1 and
actions/download-artifact v8.0.1 are pinned by full
commit SHA. Upload v7 excludes dot-prefixed hidden files by
default, supports compression levels 0–9, returns artifact
ID/URL/SHA-256 digest, and treats overwrite as delete-and-create
rather than in-place mutation. Download v8 can select by artifact
ID and defaults digest mismatch handling to error.
Artifact/log retention is policy bounded: GitHub documents 1–90
days for public repositories and up to 400 days for private
repositories when repository/organization/enterprise policy
permits. Upload-artifact v4+ is not supported on GitHub Enterprise
Server; GHES users must use an appliance-compatible artifact
action/backend and must not copy GitHub.com majors blindly.
Artifact attestations are introduced conceptually here but
generated and verified comprehensively in Chapter 23.
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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.