Compact GitHub Actions (GH-200) Cheat sheet for workflow syntax, triggers, runners, security, reuse, artifacts, caching, and troubleshooting.
Use the tables for a quick pre-exam check. Expand a topic’s notes for explanations, examples, and additional distinctions.
Scope and study context
Item
Reference
Vendor/provider
GitHub
Official exam title
GitHub Actions (GH-200)
Official exam code
GH-200
Page purpose
Independent Cheat Sheet for real-exam preparation and original practice support
The exam mindset is practical: know how a workflow is triggered, how jobs and steps execute, how data moves between jobs, how permissions and secrets are controlled, and which GitHub Actions feature solves a specific automation problem.
Core workflow anatomy
A workflow is a YAML file stored in .github/workflows/ and triggered by events, manual dispatch, schedules, or calls from other workflows.
name:CIon:push:branches:[main]pull_request:branches:[main]workflow_dispatch:permissions:contents:readenv:NODE_VERSION:"20"jobs:test:name:Test on ${{ matrix.os }}runs-on:${{ matrix.os }}strategy:matrix:os:[ubuntu-latest, windows-latest]node:["20","22"]steps:- name:Check out codeuses:actions/checkout@v4- name:Set up Nodeuses:actions/setup-node@v4with:node-version:${{ matrix.node }}- name:Install and testrun:| npm ci
npm test
Notes and examples
Workflow file elements
Element
Scope
High-yield use
name
Workflow
Display name in the Actions UI and checks.
on
Workflow
Defines events that trigger the workflow.
permissions
Workflow/job
Sets GITHUB_TOKEN permissions. Prefer least privilege.
env
Workflow/job/step
Defines environment variables. More specific scopes override broader scopes.
defaults
Workflow/job
Sets default shell or working directory for run steps.
jobs
Workflow
Groups independent or dependent units of work.
runs-on
Job
Selects GitHub-hosted or self-hosted runner.
needs
Job
Creates job dependencies and enables outputs from prior jobs.
if
Job/step
Conditionally runs a job or step.
strategy.matrix
Job
Expands one job definition into multiple job variations.
steps
Job
Sequential commands or actions inside a job.
uses
Step/job
Calls an action at step level or reusable workflow at job level.
run
Step
Executes shell commands.
with
Step/job call
Supplies action or reusable workflow inputs.
secrets
Job call/step context
Supplies sensitive values without hard-coding them.
Workflow File Anatomy
A workflow is a YAML file placed under .github/workflows/. It normally includes an event trigger and at least one job.
Key
Scope
Purpose
name
Workflow
Display name for the workflow
run-name
Workflow run
Dynamic display name for a specific run
on
Workflow
Defines triggering events
permissions
Workflow or job
Sets GITHUB_TOKEN permissions
env
Workflow, job, or step
Defines environment variables
defaults
Workflow or job
Sets defaults such as shell or working directory
concurrency
Workflow or job
Controls overlapping runs or jobs
jobs
Workflow
Defines one or more jobs
runs-on
Job
Chooses the runner
needs
Job
Creates job dependencies
if
Job or step
Conditionally runs a job or step
strategy.matrix
Job
Expands a job across combinations
steps
Job
Defines the commands/actions in a job
uses
Step or reusable workflow job
Invokes an action or reusable workflow
run
Step
Runs shell commands
with
Step or reusable workflow call
Supplies inputs
secrets
Reusable workflow call
Passes secrets to a reusable workflow
environment
Job
Associates job with a deployment environment
outputs
Job or step/action
Exposes values for later use
Workflow Structure Traps
Trap
Correct understanding
Jobs run in the order listed
Jobs run in parallel unless linked with needs
A step can have both run and uses
A normal step uses one or the other
uses always means “action”
At step level it invokes an action; at job level it can call a reusable workflow
Job-level if works exactly like step-level if
Job-level if is evaluated before matrix expansion
All workflow data is available everywhere
Context availability depends on workflow phase and scope
Environment variables set in one job are available in another
Jobs are isolated; use outputs or artifacts
Trigger selection
Common on events
Event
Choose when
Important exam traps
push
Run after commits or tags are pushed.
Branch and tag filters apply to push refs. Path filters do not apply to tag pushes.
pull_request
Validate PR changes before merge.
Runs in PR context. Fork PRs usually receive restricted token permissions and no repository secrets.
pull_request_target
Run automation in the base repository context, such as labeling or commenting.
Dangerous if you check out and execute untrusted PR code while secrets or write token permissions are available.
workflow_dispatch
Allow manual runs from the UI, API, or CLI.
Inputs are available through the inputs context.
schedule
Run on a cron schedule.
Uses UTC and runs on the default branch.
workflow_call
Make a workflow reusable by other workflows.
Called at job level, not as a normal step.
workflow_run
Run a follow-up workflow after another workflow completes.
Can separate untrusted build/test from privileged publish/deploy, but watch artifact/cache trust boundaries.
release
Run when release activity occurs.
Use types to narrow activity such as published or created.
merge_group
Validate merge queue candidates.
Required when branch protection uses merge queue and checks must run on merge groups.
issues, issue_comment, pull_request_review
Automate repository collaboration.
Confirm event payload fields before writing conditions.
Target branch for PR events; pushed branch for push events
Cannot be used with branches-ignore for the same event.
branches-ignore
Branch exclusion
Use when exclusion-only logic is clearer.
tags
Push tag refs
Cannot be used with tags-ignore for the same event.
paths
Changed files
Cannot be used with paths-ignore for the same event. Order matters when using ! negation.
paths-ignore
Changed files to ignore
If all changed files match ignored paths, the workflow is skipped.
types
Event activity types
Reduces unnecessary runs and avoids broad event handling.
Trigger decision table
Scenario
Best trigger/pattern
Run tests on every PR to main
pull_request with branches: [main]
Publish package only after a release is published
release with appropriate types
Let maintainers manually run a deployment
workflow_dispatch with inputs and environment protection
Reuse the same deployment pipeline across repositories
workflow_call reusable workflow
Run nightly dependency checks
schedule
Comment on PRs from forks without running their code
pull_request_target, limited permissions, no untrusted checkout execution
Perform privileged publish after untrusted PR checks pass
Use workflow_run carefully with trusted artifacts only
Validate merge queue entries
merge_group
Events and Triggers
The on key defines when a workflow runs. Be comfortable with simple triggers, filtered triggers, manual triggers, reusable workflow triggers, and security-sensitive pull request triggers.
Event
Use when
Key review points
push
Code is pushed to branches or tags
Can filter by branches, tags, and paths
pull_request
Validate PR changes safely
Fork PRs usually have restricted token/secrets access
pull_request_target
Run in base repository context
Security-sensitive; do not run untrusted head code with secrets/write token
workflow_dispatch
Manual run
Supports typed inputs; workflow file must be available for dispatch
workflow_call
Reusable workflow
Called from another workflow at the job level
schedule
Cron-based automation
Uses UTC cron; runs from the default branch context
repository_dispatch
External/custom trigger
Usually sent through the API
workflow_run
React to another workflow
Useful but can create privilege-escalation risk if artifacts/input are untrusted
release
Release lifecycle automation
Use activity types to limit when it runs
issues, pull_request_review, label
Repository collaboration automation
Understand the event payload and permissions needed
Trigger Filters
Filter
Applies to
Notes
branches
Branch names
For pull_request, usually filters target/base branches
branches-ignore
Branch names
Cannot be combined with branches for the same event
tags
Tag names
Used with push tag events
tags-ignore
Tag names
Cannot be combined with tags for the same event
paths
Changed file paths
If branch and path filters both exist, both must match
paths-ignore
Changed file paths
Cannot be combined with paths for the same event
types
Event activity types
Example: PR opened, synchronized, closed
High-yield filter rules:
If both branch filters and path filters are configured, the workflow runs only when both conditions match.
Negative patterns using ! are order-sensitive.
You cannot use branches and branches-ignore together for the same event.
You cannot use paths and paths-ignore together for the same event.
Path filters are not evaluated for tag pushes.
Workflows skipped by branch, path, or commit-message filters can leave required checks pending, which may block merging if that check is required.
Events created by the default GITHUB_TOKEN generally do not trigger new workflow runs, which helps prevent accidental recursion. Use a suitable GitHub App token or personal access token only when workflow chaining is intentionally required.
Pull Request Trigger Decision Point
Scenario
Safer choice
Why
Build and test untrusted PR code
pull_request
Runs with restricted access for forked PRs
Label/comment on a PR using base repo permissions
pull_request_target
Runs in base context, but avoid executing untrusted code
Need secrets for deployment
Avoid fork PR execution; use protected branches/environments
Secrets should not be exposed to untrusted code
Need to inspect PR metadata only
pull_request_target may fit
Metadata automation is different from checking out and running PR code
The key exam trap: pull_request_target is powerful but dangerous. It runs in the context of the base repository. If you check out and execute code from an untrusted fork in that context, secrets or write permissions may be exposed.
Contexts expose workflow data. The correct context depends on where the expression is evaluated.
Context
Contains
Common use
github
Event, repository, actor, ref, run metadata
Branch/event decisions
env
Environment variables defined in workflow/job/step
Shell configuration
vars
Configuration variables
Non-secret configuration
secrets
Encrypted secrets
Tokens, passwords, credentials
inputs
Manual or reusable workflow inputs
workflow_dispatch, workflow_call
matrix
Matrix values
OS/version-specific logic
needs
Upstream job results and outputs
Downstream job decisions
steps
Step outputs and outcomes
Use output from earlier step in same job
runner
Runner OS/temp/tool information
OS-specific behavior
strategy
Matrix strategy metadata
Matrix-related conditions
job
Current job information
Job services/container information
Variables and Secrets
Mechanism
Use for
Security level
Notes
env
Runtime environment values
Not inherently secret
Scope can be workflow, job, or step
vars
Plain configuration
Not secret
Organization, repository, or environment-level configuration
secrets
Sensitive values
Encrypted and masked
Not available in many untrusted fork scenarios
GITHUB_TOKEN
GitHub API access for the workflow
Scoped by permissions
Prefer least privilege
OIDC token
Federated cloud auth
Short-lived
Requires id-token: write and external trust config
Environment variable precedence generally becomes more specific as scope narrows: step-level env overrides job-level env, which overrides workflow-level env.
Workflow Command Files
File/environment variable
Purpose
Exam trap
GITHUB_ENV
Set environment variables for later steps in the same job
Does not affect the current step
GITHUB_OUTPUT
Set outputs for the current step
Step needs an id for later reference
GITHUB_PATH
Add directories to PATH for later steps
Job-scoped, not workflow-global
GITHUB_STEP_SUMMARY
Add Markdown summary for the job
Useful for reports and diagnostics
GITHUB_STATE
Share state within an action’s lifecycle
Mainly relevant to action authoring
Expression Traps
Trap
Correct approach
Treating all values as strongly typed
Use fromJSON when booleans/numbers matter
Assuming secrets can be used directly in all if expressions
Use safe patterns; secrets are restricted in conditionals
Dumping entire contexts into logs
Avoid exposing sensitive metadata; masking is not a full security design
Forgetting expression delimiters
Use ${{ }} where expression evaluation is required
Using untrusted input directly in shell scripts
Pass values through environment variables and quote carefully
Assuming outputs are typed
Outputs are strings unless parsed/converted
Using hashFiles without matching files
Empty hash results can cause unexpected cache keys
Read or write repository contents, releases, tags.
pull-requests
Read or modify pull requests.
issues
Read or modify issues.
actions
Interact with Actions runs/artifacts where allowed.
checks
Create or update check runs.
statuses
Create commit statuses.
deployments
Create or update deployments.
packages
Publish or read packages.
security-events
Upload security scanning results.
id-token
Request an OIDC token for federated authentication.
Secrets vs variables
Store
Sensitive?
Typical examples
Access syntax
Secrets
Yes
API tokens, private keys, passwords
${{ secrets.NAME }}
Configuration variables
No
Region, feature flag, environment name
${{ vars.NAME }}
Environment variables
Not inherently
Runtime values for steps
$NAME, $env:NAME, or ${{ env.NAME }}
High-yield rules:
Do not hard-code secrets in workflow YAML, scripts, logs, or action inputs.
Secrets are masked in logs, but masking is not a substitute for least privilege.
Secrets are generally not available to workflows triggered from untrusted forks.
Secrets cannot be directly used in some conditional expressions. A common pattern is to map to env and test the env value carefully.
Prefer environment secrets for deployment targets with required reviewers or protection rules.
Use separate secrets for separate environments instead of one broad credential.
OIDC federation pattern
Use OpenID Connect when a cloud or external identity provider trusts GitHub-issued tokens. This avoids long-lived cloud credentials in GitHub secrets.
permissions:contents:readid-token:writejobs:deploy:runs-on:ubuntu-latestenvironment:productionsteps:- name:Authenticate with cloud provider using OIDCrun:echo "Request short-lived credentials through provider action or CLI"
OIDC concept
Exam-ready meaning
id-token: write
Required permission to request a GitHub OIDC token.
Trust policy
Configured in the external provider, not only in the workflow.
Claims
Provider can validate repository, branch, environment, workflow, and other token claims.
Benefit
Reduces long-lived secret exposure.
Trap
OIDC does not automatically grant access; external trust and authorization must be configured.
Secure action usage
Risk
Safer pattern
Third-party action changes unexpectedly
Pin to a full commit SHA for high-security workflows.
Overbroad token permissions
Set top-level permissions: contents: read, elevate per job only when needed.
Running untrusted PR code with secrets
Use pull_request for validation; avoid privileged code execution in pull_request_target.
Shell injection from issue/PR data
Treat event context values as untrusted input. Quote variables and avoid direct interpolation into shell.
Secret printed by a script
Disable verbose output, avoid set -x, mask derived sensitive values when needed.
Self-hosted runner exposed to forks
Restrict runner access and avoid untrusted workloads.
- name:Use PR title as data, not codeenv:PR_TITLE:${{ github.event.pull_request.title }}run:| printf '%s\n' "$PR_TITLE"
Permissions, Tokens, and Security
Security is a major decision area for GitHub Actions. Know how to reduce privileges and prevent untrusted code from reaching secrets.
GITHUB_TOKEN
GitHub automatically creates a GITHUB_TOKEN for workflow runs. Its access is controlled with the permissions key.
Permissions practice
Why it matters
Set permissions at workflow or job level
Avoid unnecessary default access
Grant only required scopes
Least privilege reduces blast radius
Use job-level permissions for sensitive jobs
Different jobs may need different access
Use contents: read for checkout-only jobs
Many CI jobs do not need write access
Use id-token: write only for OIDC jobs
Needed to request an OIDC token
Avoid broad write permissions on untrusted triggers
PR workflows are a common attack surface
Important nuance: when you explicitly configure permissions, unspecified permissions are generally not granted, aside from required metadata access. This is a common exam-style trap.
OIDC
OpenID Connect allows workflows to request short-lived tokens from a cloud provider or external system without storing long-lived cloud credentials as GitHub secrets.
OIDC requirement
Meaning
permissions: id-token: write
Allows workflow to request an OIDC token
External trust policy
Cloud/provider must trust the GitHub identity claims
Short-lived credential exchange
OIDC token is exchanged for provider credentials
Claim restrictions
Limit by repository, branch, environment, workflow, or other claims where appropriate
OIDC trap: granting id-token: write does not automatically grant cloud access. The external provider must be configured to trust the workflow identity.
Secrets
Secret behavior
Review point
Encrypted at rest
Used for sensitive values
Masked in logs
Exact secret values are masked, but do not rely on logs as a security boundary
Scoped
Organization, repository, and environment scopes exist
Restricted for fork PRs
Do not expect secrets in untrusted fork workflows
Not plain configuration
Use vars for non-sensitive config
Can be environment-specific
Deployment environments can have separate secrets
Common secret mistakes:
Printing secrets or derived credentials.
Passing secrets to untrusted third-party actions.
Using secrets in workflows triggered by untrusted code.
Confusing vars and secrets.
Assuming masking prevents all forms of leakage.
Forgetting that generated sensitive values may need explicit masking with add-mask.
Avoid dumping secrets or full contexts that may contain sensitive data.
High-yield exam traps
Trap
Correct exam response
Using pull_request_target to build untrusted PR code with secrets
Use pull_request for untrusted validation; reserve pull_request_target for safe base-context automation.
Assuming GITHUB_TOKEN always has write permissions
Defaults can vary. Set permissions explicitly.
Using secrets in workflows triggered from forks
Secrets are restricted for untrusted fork contexts. Design around that boundary.
Confusing artifacts and caches
Artifacts are run outputs; caches are dependency/build acceleration.
Calling reusable workflows inside steps
Reusable workflows are called as jobs. Actions are called as steps.
Expecting jobs to run sequentially by default
Jobs run in parallel unless connected with needs.
Forgetting that skipped filtered workflows can affect required checks
Branch protection may wait for checks that never run.
Storing non-secret configuration as secrets
Use vars for non-sensitive configuration.
Using mutable action references in sensitive pipelines
Pin actions to commit SHA when integrity matters.
Running untrusted code on self-hosted runners
Restrict runner access and isolate workloads.
Assuming environment secrets are available before approval
Protected environment jobs must pass protection rules first.
Overusing always()
Prefer precise status checks; use !cancelled() when appropriate.
Compact scenario review
Requirement
Strong answer
Build, test, and lint every PR
pull_request workflow with matrix and read-only permissions.
Publish only from tags
push with tags filter and job condition for tag refs.
Deploy to production with manual approval
Environment protection plus deployment job.
Share standard CI across repositories
Reusable workflow with workflow_call.
Share five repeated shell steps inside one job
Composite action.
Authenticate to cloud without static cloud secret
OIDC with id-token: write and provider trust policy.
Speed up package installs
Cache package manager directory keyed by OS, tool version, and lockfile hash.
Pass build output to deploy job
Upload artifact in build; download artifact in deploy.
Stop overlapping deployments
Job-level concurrency keyed by environment.
Run database integration tests
Service container.
Target internal network for deployment
Self-hosted runner with restricted repository access.
Run safe labeling on fork PRs
pull_request_target with minimal permissions and no untrusted code execution.
Final preparation checklist
Can you choose the correct event for push, pull_request, pull_request_target, workflow_dispatch, schedule, workflow_call, and workflow_run scenarios?
Can you explain why pull_request_target is powerful and dangerous?
Can you write the difference between an action, a composite action, a Docker action, and a reusable workflow?
Can you set least-privilege permissions for GITHUB_TOKEN?
Can you distinguish secrets, vars, env, inputs, matrix, needs, and steps contexts?
Can you pass data from step to step, job to job, and workflow to workflow?
Can you choose between artifacts and caches?
Can you select GitHub-hosted versus self-hosted runners for a scenario?
Can you diagnose skipped workflows, pending checks, missing secrets, and permission errors?
Can you secure deployments with environments, approvals, environment secrets, and OIDC?
For the next step, use this Cheat Sheet to drill scenario-based questions: read a workflow requirement, choose the trigger, permissions, runner type, reuse mechanism, and data-passing pattern before checking your answer.
Core Mental Model
GitHub Actions automation usually follows this path:
An event occurs, such as push, pull_request, workflow_dispatch, or schedule.
GitHub finds a matching workflow file in .github/workflows/.
The workflow creates one or more jobs.
Each job runs on a runner.
Each job executes steps, which either run shell commands with run or invoke actions with uses.
Logs, outputs, artifacts, caches, checks, deployments, and summaries are produced.
Layer
What it does
High-yield exam cue
Common mistake
Workflow
YAML automation definition
Stored in .github/workflows/*.yml or .yaml
Expecting a workflow outside that directory to run
Event
Starts a workflow
on: push, on: pull_request, on: workflow_dispatch
Confusing event filters with job if conditions
Job
Unit of execution
Has runs-on, steps, optional needs
Assuming jobs run sequentially by default
Runner
Machine that executes a job
GitHub-hosted or self-hosted
Assuming files persist across jobs
Step
Individual command or action
Uses run or uses
Trying to use both run and uses in one step
Action
Reusable automation unit
JavaScript, Docker, or composite action
Confusing an action with a reusable workflow
Context
Runtime data
github, env, secrets, matrix, needs
Using the wrong context for the execution phase
Token/permissions
Access control
GITHUB_TOKEN, permissions, OIDC
Leaving broad write permissions enabled
Jobs, Steps, and Control Flow
Jobs
A job is the main execution unit in a workflow. Each job gets a runner and runs its steps in order.
Feature
Use for
Exam cue
runs-on
Select runner
Required for normal jobs
needs
Order jobs
Without needs, jobs run in parallel
if
Conditional job execution
Job skipped if condition is false
strategy.matrix
Run variants
OS/language/version combinations
continue-on-error
Allow failure without failing workflow/job
Often used for experimental matrix entries
timeout-minutes
Stop long-running jobs
Avoids stuck jobs consuming time
concurrency
Prevent overlapping work
Useful for deployments and branch-specific runs
environment
Deployment environment
Can add protection rules and environment-scoped secrets
permissions
Token scope
Prefer least privilege at workflow or job level
Notes and examples
Steps
Steps run sequentially inside a job.
Step type
Syntax cue
Use for
Shell command
run
Build, test, script, CLI command
Action
uses
Reusable task such as checkout, setup, upload artifact
Conditional step
if
Run only under specific status/event/context conditions
Identified step
id
Required if later steps read that step’s outputs
Input-driven step
with
Pass inputs to an action
Environment step
env
Pass environment variables to the command/action
Status Functions
Function
Meaning
Common use
success()
Previous steps/jobs succeeded
Default behavior for most steps
failure()
A previous step/job failed
Upload logs after failure
cancelled()
Workflow was cancelled
Skip cleanup that should not run after cancellation
always()
Run regardless of previous result
Cleanup, diagnostics, summaries
!cancelled()
Run unless cancelled
Often safer than unconditional always() for long operations
Common control-flow traps:
A dependent job is skipped if a required job is skipped or fails, unless the condition explicitly handles it.
Step-level if conditions are evaluated at runtime inside the job.
Job-level if conditions are evaluated before matrix expansion.
continue-on-error changes failure behavior but does not mean the command succeeded.
Use needs.<job_id>.result when downstream jobs must react to upstream success, failure, cancellation, or skip states.
Artifacts, Caches, Outputs, and Data Passing
Different data-sharing mechanisms solve different problems.
Need
Best tool
Why
Pass a small value between steps in one job
Step output
Simple and direct
Pass a small value between jobs
Job output plus needs
Designed for job dependencies
Pass files between jobs in a workflow
Artifact
Download in another job
Preserve dependencies between workflow runs
Cache
Speeds repeated installs/builds
Publish human-readable run results
Step summary
Appears in workflow UI
Persist deployment package for release
Artifact or release asset
Cache is not a release mechanism
Notes and examples
Outputs
Output type
How it is used
Step output
Written to GITHUB_OUTPUT; referenced through steps.<id>.outputs.<name>
Job output
Maps step outputs to jobs.<job_id>.outputs; consumed through needs.<job_id>.outputs.<name>
Reusable workflow output
Exposed by the called workflow and consumed by the caller
Output traps:
A step must have an id if later steps need its outputs.
Job outputs are only available to jobs that declare needs.
Outputs are strings unless converted.
Outputs are not a safe place for secrets unless the flow is carefully controlled.
Artifacts vs Cache
Feature
Artifact
Cache
Primary purpose
Store workflow files/results
Reuse dependencies/build data
Typical examples
Test reports, build packages, coverage files
Package manager directories, tool caches
Shared across jobs
Yes, by upload/download
Not the main purpose
Shared across workflow runs
Artifacts can be retained; caches are restored by key
Yes, if key/scope matches
Determinism
Good for exact files from a run
Cache hit is helpful but not guaranteed
Security caution
Do not blindly trust artifacts from untrusted workflows
Do not cache secrets or sensitive files
Cache key best practices:
Include operating system or platform.
Include dependency lockfile hash with hashFiles.
Use restore keys for fallback matches.
Do not depend on cache for correctness.
Do not put credentials, tokens, or secrets in cached paths.
Concurrency
Concurrency prevents overlapping workflow runs or jobs from interfering with each other.
Use case
Concurrency pattern
Cancel older CI runs on same branch
Group by workflow and ref; enable cancel-in-progress
Prevent simultaneous production deployments
Use a stable production deployment group
Serialize environment-specific deployments
Group by environment name
Avoid duplicate scheduled work
Use one group for the scheduled process
Review points:
concurrency can be set at workflow or job level.
A concurrency group allows at most one running and one pending run/job in that group.
cancel-in-progress: true cancels the currently running item in the group.
Group names are case-insensitive.
Ordering of queued items is not guaranteed.
Self-Hosted Runner Security
Self-hosted runners are powerful because they can access internal tools and networks, but that also increases risk.
Risk
Mitigation
Untrusted PR code runs on internal machine
Avoid self-hosted runners for untrusted public PRs
Files persist between jobs
Clean workspace and use ephemeral runners where possible
Runner has broad network access
Segment network access
Tooling becomes outdated
Patch runner host and runner application
Secrets remain in logs/files/processes
Minimize secrets, clean aggressively, use least privilege
Any repo can target runner
Use runner groups and labels carefully
Exam decision rule: if a scenario involves private infrastructure, custom hardware, or special internal dependencies, a self-hosted runner may be the answer. If the scenario involves untrusted public contributions, self-hosted runners are often the risk to avoid.
Debugging and Observability
Tool/feature
Use
Workflow run logs
Step-by-step execution details
Annotations
Warnings/errors surfaced in the UI
Step summaries
Markdown reports for a job
Re-run jobs/workflows
Retry transient failures
Debug logging
More detailed runner and step logs
toJSON
Inspect context data carefully
GitHub CLI
Inspect and trigger workflow runs from the command line