🛠️ Lab 7 — Ship It Automatically: Build Your Capstone CI/CD Pipeline (50 pts)

Goal: Add a GitHub Actions workflow to your capstone repository that automatically lints/tests your code, builds your capstone's Docker image, and pushes a versioned image to GitHub Container Registry (GHCR) on every push — with zero hardcoded credentials. All tools used are free (GitHub Actions free minutes + GHCR are free for public repos, and free-tier minutes apply to private repos too). Steps:

  1. Confirm your capstone has a working Dockerfile. If you built one in an earlier week, make sure docker build . still succeeds locally. If not, write a minimal Dockerfile now (base image, copy source, install dependencies, set entrypoint).
  2. Add a basic automated test. Even one meaningful unit test (e.g., a function that validates an API response shape, or a smoke test that your app starts) is enough — the point is that the pipeline has something real to run, not that your test suite is exhaustive.
  3. Create the workflow file at .github/workflows/ci.yml in your capstone repo. Structure it as separate jobs so stages can fail fast and run independently:
  4. Authenticate to GHCR without hardcoding anything. In the build-and-push job, log in using the built-in GITHUB_TOKEN (automatically provided by GitHub Actions — no manual secret setup required for GHCR):
- name: Log in to GHCR
  uses: docker/login-action@v3
  with:
    registry: ghcr.io
    username: ${{ github.actor }}
    password: ${{ secrets.GITHUB_TOKEN }}
  1. Build and push with caching, following Docker's official "Docker Build GitHub Actions" guide. Use docker/build-push-action with cache-from/cache-to set to type=gha so repeated builds reuse layers instead of rebuilding from scratch:
- name: Build and push
  uses: docker/build-push-action@v6
  with:
    context: .
    push: true
    tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
    cache-from: type=gha
    cache-to: type=gha,mode=max
  1. Version the image. Tag it with at minimum the commit SHA (${{ github.sha }}) so every push produces a traceable, unique image; optionally also tag latest on pushes to main.
  2. Trigger it. Set the workflow to run on: push (and optionally pull_request for the lint-test job only, so PRs get feedback before merge without pushing an image).
  3. Verify end-to-end. Push a commit, watch the Actions tab until the pipeline goes green, then confirm the image appears under your GitHub profile's "Packages" tab (this is GHCR).
  4. Audit for hardcoded secrets. Search your entire repo (git grep for anything that looks like a key or token) and confirm the only credential references in ci.yml are ${{ secrets.* }} expressions — nothing in plain text.

Deliverables: Submit (a) the URL to your capstone repo's .github/workflows/ci.yml file, (b) a screenshot of a green pipeline run in the Actions tab, and (c) a screenshot of the resulting versioned image in your GHCR Packages tab, along with a short written reflection (150–250 words) on one decision you made while building the pipeline and why.