World map

 

BM: Baca dalam Bahasa Melayu

World C2: Container Pipelines · Boss challenge

Green line

You will learn: to make every PR build, test and scan, and every merge ship a tagged image.

Checked with GitHub Actions 2026-10 on 31 Oct 2026

The problem

Pick an event. Press Run and watch the line.

A pull request from a fork runs the line. The build tries to push to ghcr.io and is denied.

What happened on GitHub

Workflow file .github/workflows/green-line.yml

name: Green line
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
packages: write
jobs:
image:
runs-on: ubuntu-latest
steps:
- uses: docker/setup-buildx-action@v4
- uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v7
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}

The line

Pull request from a fork · stranger:feature → main

Boss: the green line! Mei sends her first PR from a fork. The line turns red. Press Run and read the red line.

Check

Plain words: a PR tried to push, with a read-only key. Should a PR push an image at all?

Pick one answer.

Try it

Room 1: fix the yellow line. PRs should only build. Main should push.

The line is red. Fix the yellow lines, then run again.

What happened on GitHub

Workflow file .github/workflows/green-line.yml

name: Green line
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
packages: write
jobs:
image:
runs-on: ubuntu-latest
steps:
- uses: docker/setup-buildx-action@v4
- uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v7
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}

Yellow: lines 21–21. You can change these.

Pick a fix

The line

Pull request from a fork · stranger:feature → main

Check

Room 2: what happens where on the green line?

Drag a card into a box. Or tap the card, then tap the box.

      Try it

      Room 3: the API tests need Postgres, and they can’t find it. Give the job a database.

      The line is red. Fix the yellow lines, then run again.

      What happened on GitHub

      Workflow file .github/workflows/test.yml

      name: Test
      on:
      pull_request:
      permissions:
      contents: read
      jobs:
      test:
      runs-on: ubuntu-latest
      steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
      with:
      node-version: 24
      - run: npm ci
      - run: npm test
      env:
      DATABASE_URL: postgres://postgres:test@localhost:5432/postgres
      

      Yellow: lines 8–8. You can change these.

      Pick a fix

      The line

      Pull request · feature → main

      Check

      Room 4: a PR’s image has a CRITICAL CVE. What should the line do?

      Pick one answer.

      Predict

      Final room: the whole line, with a CRITICAL CVE in the image. Tap the station that will stop it, then press Run.

      Which station will stop the line? Tap it, then press Run.

      What happened on GitHub

      Workflow file .github/workflows/green-line.yml

      name: Green line
      on:
      push:
      branches: [main]
      pull_request:
      permissions:
      contents: read
      jobs:
      test:
      runs-on: ubuntu-latest
      steps:
      - uses: actions/checkout@v7
      - run: docker compose up -d --wait
      - run: docker compose run --rm api npm test
      image:
      needs: test
      runs-on: ubuntu-latest
      permissions:
      contents: read
      packages: write
      steps:
      - uses: docker/setup-buildx-action@v4
      - id: meta
      uses: docker/metadata-action@v6
      with:
      images: ghcr.io/${{ github.repository }}
      - uses: docker/build-push-action@v7
      with:
      load: true
      tags: kedai-kancil:scan
      cache-from: type=gha
      cache-to: type=gha,mode=max
      - uses: aquasecurity/trivy-action@v0.36.0
      with:
      image-ref: kedai-kancil:scan
      severity: CRITICAL
      exit-code: '1'
      - if: github.event_name != 'pull_request'
      uses: docker/login-action@v4
      with:
      registry: ghcr.io
      username: ${{ github.actor }}
      password: ${{ secrets.GITHUB_TOKEN }}
      - uses: docker/build-push-action@v7
      with:
      push: ${{ github.event_name != 'pull_request' }}
      tags: ${{ steps.meta.outputs.tags }}
      labels: ${{ steps.meta.outputs.labels }}
      cache-from: type=gha
      

      The line

      Pull request · feature → main

      You did it!

      You can now check every PR and ship every merge.

      Go deeper (optional)

      Here is the whole green line. Compose runs the tests. Then the image is built and scanned. Only main logs in and pushes. The scan comes before the push, so a bad pack never ships. Mission 2 puts this line in your own repo.

      Pick an event. Press Run and watch the line.

      The whole green line. On a PR: tests, build, scan, no push. On main: the same, plus login and push.

      What happened on GitHub

      Workflow file .github/workflows/green-line.yml

      name: Green line
      on:
      push:
      branches: [main]
      pull_request:
      permissions:
      contents: read
      jobs:
      test:
      runs-on: ubuntu-latest
      steps:
      - uses: actions/checkout@v7
      - run: docker compose up -d --wait
      - run: docker compose run --rm api npm test
      image:
      needs: test
      runs-on: ubuntu-latest
      permissions:
      contents: read
      packages: write
      steps:
      - uses: docker/setup-buildx-action@v4
      - id: meta
      uses: docker/metadata-action@v6
      with:
      images: ghcr.io/${{ github.repository }}
      - uses: docker/build-push-action@v7
      with:
      load: true
      tags: kedai-kancil:scan
      cache-from: type=gha
      cache-to: type=gha,mode=max
      - uses: aquasecurity/trivy-action@v0.36.0
      with:
      image-ref: kedai-kancil:scan
      severity: CRITICAL
      exit-code: '1'
      - if: github.event_name != 'pull_request'
      uses: docker/login-action@v4
      with:
      registry: ghcr.io
      username: ${{ github.actor }}
      password: ${{ secrets.GITHUB_TOKEN }}
      - uses: docker/build-push-action@v7
      with:
      push: ${{ github.event_name != 'pull_request' }}
      tags: ${{ steps.meta.outputs.tags }}
      labels: ${{ steps.meta.outputs.labels }}
      cache-from: type=gha
      

      The line

      Pull request · feature → main