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 1Prepare 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 2Create the prerequisite
printf 'ready\n' > ready.txt
STEP 3Run dependent stages
./test.sh && ./package.sh
STEP 4Verify 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 connectionSeparating 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.