CI/CD Fundamentals · Module 03 of 12

Events, jobs, steps and runners

Control execution order, isolate work into jobs and understand the trust boundary created by hosted and self-hosted runners.

Learning objectives

By the end of this module, you should be able to:

  • Use needs to model job dependencies.
  • Explain that jobs are isolated runner executions.
  • Recognize the operational risk of exposing self-hosted runners to untrusted contributions.

Jobs are parallel unless you connect them

Independent jobs can run concurrently. Use needs when a downstream job must wait for a successful prerequisite, such as package waiting for test.

Steps share a job workspace, jobs do not automatically share files

Steps in one job execute in the same job workspace. Separate jobs should exchange durable outputs through supported mechanisms such as job outputs or artifacts rather than assuming the filesystem is shared.

Runner placement is a trust decision

GitHub-hosted runners are ephemeral managed environments. Self-hosted runners provide network and tool control but must be isolated carefully, especially when workflows can execute code from untrusted branches or forks.

Worked examples

See the idea in practice.

Sequence test before package

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: ./test.sh
  package:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - run: ./package.sh
  • package starts only after test succeeds.
  • A separate job should not assume files from test are present unless transferred.
Hands-on lab

Lab — Model dependency order locally

Goal: Create separate test and package scripts and prove packaging is blocked by a failed test.

STEP 1

Prepare scripts

mkdir -p ~/gnu-cicd-labs/module03 && cd ~/gnu-cicd-labs/module03
printf '#!/usr/bin/env bash\nset -e\ntest -f ready.txt\n' > test.sh
printf '#!/usr/bin/env bash\nset -e\ntar -czf app.tgz ready.txt\n' > package.sh
chmod +x test.sh package.sh
STEP 2

Create the prerequisite

printf 'ready\n' > ready.txt
STEP 3

Run dependent stages

./test.sh && ./package.sh
STEP 4

Verify artifact

tar -tzf app.tgz

Verify

  • package.sh runs only after test.sh returns success.
  • The archive contains ready.txt.

Expected outcome

  • Execution order is explicit and failure propagates.

If it fails

  • If the package step runs after a failing test, check that commands are connected with && or a fail-fast driver.
  • In Actions, check the needs graph in the workflow run UI.
Real-world connection

Separating fast validation, expensive builds and deployments into jobs creates clearer dependencies and failure ownership.

Avoid these traps

Common mistakes

  • Assuming jobs execute in YAML order.
  • Assuming files automatically persist across jobs.
  • Putting sensitive self-hosted runners behind workflows triggered by untrusted code without isolation.
Knowledge check

Can you explain it without looking back?

Open each answer only after you have tried to answer the question yourself.

1How do you make one GitHub Actions job wait for another?

Use the needs keyword.

2Do different jobs automatically share a filesystem?

No. Transfer required data explicitly, for example with artifacts or outputs.

3Why are self-hosted runners a security boundary?

Workflow code executes on infrastructure you operate and may reach local networks or credentials if not isolated.

My Learning

Record your progress for this module.

Progress is saved in this browser immediately. When you sign in to My Learning, it can also sync across devices.

Not started

Attempt the core lab and knowledge checks before marking the module complete.