Skip to content

VOL 00 / CH 08 / LESSON 02

8.2 Making CI Repeatable and Verifiable ​

Prerequisites: From Source to Runnable Artifact

Estimated time: 20 minutes

Reading note: this workflow demonstrates permissions and structure; replace every action SHA placeholder before use

You are ready to continue when: you can distinguish CI, continuous delivery, and continuous deployment, and review the minimum permission GitHub Actions workflow

You manually completed the build, verification, image creation, and cleanup sequence. The next day, a one-line change required every command again. Those repeatable steps are good automation targets; people must still design permissions and release conditions.

Keep the Three Terms Separate ​

  • Continuous Integration (CI): Frequent merging of changes, with automatic compilation, testing, and verification.
  • Continuous Delivery: Candidate versions are always in a deployable state, and production releases may require manual approval.
  • Continuous Deployment: Once a gate is cleared, the release is automatically moved into production.

CD may refer to the latter two, so write the intended term in full.

Start with Read-Only CI ​

The following is a structural template. <FULL_COMMIT_SHA> must be replaced with the full commit SHA of the corresponding official action's release; GitHub notes that the full SHA is an immutable reference. This example keeps the placeholders visible for instruction; do not present it as directly runnable.

yaml
name: ci

on:
  pull_request:
  push:
    branches: [main]

permissions:
  contents: read

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@<FULL_COMMIT_SHA>
        with:
          persist-credentials: false
      - uses: actions/setup-java@<FULL_COMMIT_SHA>
        with:
          distribution: temurin
          java-version: "17"
          cache: maven
      - run: ./mvnw --batch-mode verify

Save the complete workflow as .github/workflows/ci.yml. It assumes the repository contains an executable Maven Wrapper, POM, source, and tests. Checkout does not retain Git credentials, reducing their exposure to later build scripts. ubuntu-latest still changes; record the runner image and JDK version when diagnosing environment differences.

CI does not require packages: write and should not use production secrets. Untrusted code in a pull request may read the working directory, network, and runner status; be particularly cautious with forks and self-hosted runners.

Publish Images within a Separate Permission Boundary ​

Run this job only on protected branches or release tags, and grant the minimum necessary permissions at the job level:

yaml
permissions:
  contents: read
  packages: write

Use a short-lived GITHUB_TOKEN to log in to GHCR. Do not print the token in the logs. Tag the image with at least the commit SHA, and record the digest returned by the push. :latest can serve as a human-friendly alias, but deployment cannot rely solely on it for version identification.

yaml
- name: Push an already built image
  env:
    GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    IMAGE_NAME: ghcr.io/owner/repo
  run: |
    printf '%s' "$GH_TOKEN" | docker login ghcr.io \
      --username "$GITHUB_ACTOR" --password-stdin
    docker push "$IMAGE_NAME:sha-${GITHUB_SHA}"

This steps fragment belongs to a publishing job and assumes an earlier step built and tagged that image. GitHub provides GITHUB_ACTOR and GITHUB_SHA, but GH_TOKEN must be explicitly mapped as shown; the platform does not create that alias. Replace owner/repo with an authorized lowercase image path. See GitHub Token usage. Do not write the real token into shell history or the repository.

Deployment Jobs Need Access Controls ​

Production jobs should reference a GitHub environment, such as production. Environments can restrict branches, require approvals, and expose environment secrets only after the protection rules pass. Use a concurrency group per target environment to prevent overlapping deployments. Set cancel-in-progress: false so an active release can finish; cancel deployments only when interruption and recovery are known to be safe. Concurrency is not a complete release queue: inspect how pending runs can be replaced in the GitHub concurrency documentation.

Before deployment, you must have: candidate digest, migration compatibility, rollback version, health check, observation window, and a responsible person. After deployment, first verify instance health, critical requests, and error rates before gradually increasing traffic.

Supply Chain Boundaries ​

  • Pin third-party actions to a full commit SHA and verify that the SHA comes from the original repository.
  • GITHUB_TOKEN grants only the scope required for the job; permissions not listed become none.
  • Avoid using long-lived cloud credentials as a primary option; use OIDC to exchange for short-term credentials when the platform supports it.
  • Artifact attestation can prove which workflow, commit, and event built the artifact, but it does not prove that the artifact is free of vulnerabilities.
  • For production deployment, prefer to reference the digest and retain records of the commit, testing, SBOM, signatures, and approvals.

Common Failures ​

PhenomenonCheck
workflow not triggeredpath .github/workflows/, event, branch filtering, YAML
Passes locally, fails in CIJDK/Maven version, locked dependencies, case sensitivity, time zone and uncommitted files
GHCR 403job's packages: write, package and repository access relationship, event source
secret is emptysecret scope, environment access control, fork event restrictions
two deployments overlapenvironment and concurrency strategy

GitHub environment, approvals, and concurrency strategies may be affected by the repository plan and account plan. Check GitHub deployment environment documentation before implementation; cloud credentials prioritize OIDC configuration guide.

Remote registry and production permissions vary by project. First, clarify artifacts, images, health checks, and rollback decisions locally.

→ Next Step: Local Deployment of Experiment

Built with VitePress | Software Systems Atlas