@htekdev/actions-debugger 1.0.87 → 1.0.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/errors/known-unsolved/known-unsolved-051.yml +94 -0
- package/errors/runner-environment/macos-arm64-rosetta-not-installed.yml +97 -0
- package/errors/runner-environment/runner-disk-full-no-space-left.yml +106 -0
- package/errors/runner-environment/runner-environment-152.yml +90 -0
- package/errors/runner-environment/ubuntu-snap-snapd-not-running.yml +90 -0
- package/errors/runner-environment/ubuntu-systemctl-systemd-not-running.yml +95 -0
- package/errors/silent-failures/silent-failures-081.yml +86 -0
- package/errors/yaml-syntax/yaml-syntax-055.yml +88 -0
- package/package.json +1 -1
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
id: known-unsolved-051
|
|
2
|
+
title: 'No workflow-level `timeout-minutes` — only job-level and step-level timeouts; runaway workflows consume runner hours with no global cap'
|
|
3
|
+
category: known-unsolved
|
|
4
|
+
severity: limitation
|
|
5
|
+
tags:
|
|
6
|
+
- timeout
|
|
7
|
+
- workflow-level
|
|
8
|
+
- runner-hours
|
|
9
|
+
- billing
|
|
10
|
+
- limitation
|
|
11
|
+
- runaway-workflow
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'timeout.minutes'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'workflow.*timed? ?out|timed? ?out.*workflow'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
error_messages:
|
|
18
|
+
- "No workflow-level timeout — only job-level timeout-minutes is supported"
|
|
19
|
+
- "Unexpected key 'timeout-minutes' at workflow level — property is only valid on jobs"
|
|
20
|
+
root_cause: |
|
|
21
|
+
GitHub Actions supports `timeout-minutes:` only at the JOB level and STEP level.
|
|
22
|
+
There is no `timeout-minutes:` field at the workflow level (the level containing
|
|
23
|
+
`on:`, `env:`, and `jobs:`). If placed at the workflow level, actionlint reports
|
|
24
|
+
"unexpected key 'timeout-minutes'" and the key is silently ignored at runtime
|
|
25
|
+
with no effect on execution.
|
|
26
|
+
|
|
27
|
+
The default job timeout is 360 minutes (6 hours). A workflow with multiple jobs,
|
|
28
|
+
each using the default timeout, can run for many times 360 minutes total. There is
|
|
29
|
+
no built-in way to enforce a global "if this entire workflow hasn't finished in X
|
|
30
|
+
hours, cancel everything."
|
|
31
|
+
|
|
32
|
+
Common scenarios where this causes unexpected runner hour consumption:
|
|
33
|
+
- A self-hosted runner goes offline mid-job; the job hangs until its per-job timeout
|
|
34
|
+
- A workflow waiting on a deployment environment review that is never approved
|
|
35
|
+
- A matrix job with a misconfigured container that hangs on startup
|
|
36
|
+
- A network call in a step that never times out (no step-level timeout set)
|
|
37
|
+
|
|
38
|
+
This is a long-requested GitHub Actions feature with hundreds of community upvotes.
|
|
39
|
+
fix: |
|
|
40
|
+
Workarounds (no official workflow-level timeout exists):
|
|
41
|
+
|
|
42
|
+
1. SET CONSERVATIVE JOB TIMEOUTS: Add explicit `timeout-minutes:` to every job
|
|
43
|
+
with a value appropriate for that job's actual expected runtime plus a buffer.
|
|
44
|
+
Do not rely on the 360-minute default.
|
|
45
|
+
|
|
46
|
+
2. SET STEP-LEVEL TIMEOUTS: Add `timeout-minutes:` to individual steps that perform
|
|
47
|
+
network calls, long-running builds, or any operation that can hang.
|
|
48
|
+
|
|
49
|
+
3. WATCHDOG WORKFLOW: A separate workflow triggered by `workflow_run` can monitor
|
|
50
|
+
in-progress runs and cancel them via the API if they exceed a threshold duration.
|
|
51
|
+
|
|
52
|
+
4. ENVIRONMENT REVIEW EXPIRY: For deployment workflows stuck on required reviewers,
|
|
53
|
+
configure an expiry window under Settings > Environments > [env] >
|
|
54
|
+
Deployment protection rules > Timeout.
|
|
55
|
+
fix_code:
|
|
56
|
+
- language: yaml
|
|
57
|
+
label: 'Set explicit per-job timeouts as a workaround'
|
|
58
|
+
code: |
|
|
59
|
+
jobs:
|
|
60
|
+
build:
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
timeout-minutes: 15 # Set per-job: build should not exceed 15 min
|
|
63
|
+
steps:
|
|
64
|
+
- uses: actions/checkout@v4
|
|
65
|
+
- run: npm ci && npm run build
|
|
66
|
+
|
|
67
|
+
test:
|
|
68
|
+
needs: build
|
|
69
|
+
runs-on: ubuntu-latest
|
|
70
|
+
timeout-minutes: 20 # Integration tests: 20 min max
|
|
71
|
+
steps:
|
|
72
|
+
- name: Run tests
|
|
73
|
+
timeout-minutes: 15 # Step-level: individual test run cap
|
|
74
|
+
run: npm run test:integration
|
|
75
|
+
|
|
76
|
+
deploy:
|
|
77
|
+
needs: test
|
|
78
|
+
runs-on: ubuntu-latest
|
|
79
|
+
timeout-minutes: 10 # Deployment itself should be fast
|
|
80
|
+
environment: production
|
|
81
|
+
steps:
|
|
82
|
+
- run: ./scripts/deploy.sh
|
|
83
|
+
prevention:
|
|
84
|
+
- 'Always set `timeout-minutes:` on every job — do not rely on the 360-minute default for normal CI workflows.'
|
|
85
|
+
- 'Add `timeout-minutes:` to individual steps that perform network I/O, external API calls, or any blocking operation.'
|
|
86
|
+
- 'Monitor unexpected Actions billing spikes: they often indicate a stuck workflow running against the 6-hour default job timeout.'
|
|
87
|
+
- 'Set deployment environment review expiry windows to prevent workflows from hanging indefinitely awaiting approval.'
|
|
88
|
+
docs:
|
|
89
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes'
|
|
90
|
+
label: 'Workflow syntax: jobs.<job_id>.timeout-minutes'
|
|
91
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepstimeout-minutes'
|
|
92
|
+
label: 'Workflow syntax: jobs.<job_id>.steps[*].timeout-minutes'
|
|
93
|
+
- url: 'https://github.com/orgs/community/discussions/16058'
|
|
94
|
+
label: 'GitHub Community: Workflow-level timeout-minutes (feature request)'
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
id: runner-environment-154
|
|
2
|
+
title: "macOS ARM64 runner: Rosetta 2 not pre-installed — x86_64 binaries fail"
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- macos
|
|
7
|
+
- arm64
|
|
8
|
+
- rosetta
|
|
9
|
+
- apple-silicon
|
|
10
|
+
- binary-compatibility
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'Bad CPU type in executable'
|
|
13
|
+
flags: i
|
|
14
|
+
- regex: 'Exec format error'
|
|
15
|
+
flags: i
|
|
16
|
+
- regex: 'is not supported on this machine \(CPU type'
|
|
17
|
+
flags: i
|
|
18
|
+
- regex: 'rosetta.*not.*install|softwareupdate.*rosetta'
|
|
19
|
+
flags: i
|
|
20
|
+
error_messages:
|
|
21
|
+
- "zsh: bad CPU type in executable: /usr/local/bin/mytool"
|
|
22
|
+
- "Exec format error"
|
|
23
|
+
- "/usr/local/bin/node: Bad CPU type in executable"
|
|
24
|
+
- "The file '/path/to/binary' is not supported on this machine (CPU type 16777223)"
|
|
25
|
+
root_cause: |
|
|
26
|
+
GitHub-hosted macOS runners on Apple Silicon hardware (macos-14, macos-15, and the `macos-latest`
|
|
27
|
+
label when pointing to ARM64 images) do NOT have Rosetta 2 pre-installed. Rosetta 2 is Apple's
|
|
28
|
+
x86_64-to-ARM64 translation layer that allows Intel-compiled binaries to run on Apple Silicon.
|
|
29
|
+
|
|
30
|
+
Without Rosetta 2, any x86_64 binary executed on the ARM64 runner fails immediately with
|
|
31
|
+
"Bad CPU type in executable" or "Exec format error". Common sources of x86_64 binaries:
|
|
32
|
+
- Pre-compiled tool downloads targeting darwin-x64
|
|
33
|
+
- npm packages with native addons built for x86_64
|
|
34
|
+
- Homebrew formulae that only have x86_64 bottles
|
|
35
|
+
- Custom build scripts that hardcode `arch -x86_64`
|
|
36
|
+
- Docker images using `linux/amd64` platform
|
|
37
|
+
|
|
38
|
+
This is distinct from Linux ARM64 runners (ubuntu-24.04-arm) where the error manifests
|
|
39
|
+
differently and no Rosetta equivalent exists. On macOS, Rosetta 2 can be installed as a
|
|
40
|
+
one-time setup step.
|
|
41
|
+
fix: |
|
|
42
|
+
Option 1 — Install Rosetta 2 at job start (quick workaround):
|
|
43
|
+
Add `softwareupdate --install-rosetta --agree-to-license` as the first step. This allows
|
|
44
|
+
x86_64 binaries to run via translation.
|
|
45
|
+
|
|
46
|
+
Option 2 — Use ARM64-native binaries (preferred):
|
|
47
|
+
Update download scripts to detect `arch` and fetch the correct binary:
|
|
48
|
+
- Use `$(uname -m)` to branch between arm64 and x86_64 download URLs
|
|
49
|
+
- Use `arch -arm64 brew install` for Homebrew packages
|
|
50
|
+
- For npm: ensure native addons are rebuilt for the current architecture
|
|
51
|
+
|
|
52
|
+
Option 3 — Pin to Intel macOS runner:
|
|
53
|
+
Use `runs-on: macos-13` which is the last Intel-based macOS runner image. Note that
|
|
54
|
+
macos-13 is scheduled for deprecation; this is a temporary workaround only.
|
|
55
|
+
fix_code:
|
|
56
|
+
- language: yaml
|
|
57
|
+
label: "Install Rosetta 2 as first step (workaround)"
|
|
58
|
+
code: |
|
|
59
|
+
jobs:
|
|
60
|
+
build:
|
|
61
|
+
runs-on: macos-latest # ARM64 Apple Silicon
|
|
62
|
+
steps:
|
|
63
|
+
- name: Install Rosetta 2
|
|
64
|
+
run: softwareupdate --install-rosetta --agree-to-license
|
|
65
|
+
- uses: actions/checkout@v4
|
|
66
|
+
- name: Download tool
|
|
67
|
+
run: |
|
|
68
|
+
# x86_64 binary will now work via Rosetta translation
|
|
69
|
+
curl -L https://example.com/tool-darwin-x64 -o tool
|
|
70
|
+
chmod +x tool
|
|
71
|
+
./tool
|
|
72
|
+
- language: yaml
|
|
73
|
+
label: "Detect architecture and fetch the correct binary (preferred)"
|
|
74
|
+
code: |
|
|
75
|
+
steps:
|
|
76
|
+
- name: Download architecture-appropriate binary
|
|
77
|
+
run: |
|
|
78
|
+
ARCH=$(uname -m)
|
|
79
|
+
if [ "$ARCH" = "arm64" ]; then
|
|
80
|
+
BINARY_URL="https://example.com/tool-darwin-arm64"
|
|
81
|
+
else
|
|
82
|
+
BINARY_URL="https://example.com/tool-darwin-x64"
|
|
83
|
+
fi
|
|
84
|
+
curl -L "$BINARY_URL" -o tool
|
|
85
|
+
chmod +x tool
|
|
86
|
+
./tool
|
|
87
|
+
prevention:
|
|
88
|
+
- "Always test workflows on both `macos-13` (Intel) and `macos-14`+ (ARM64) runners"
|
|
89
|
+
- "Check download scripts for hardcoded `darwin-x64` or `darwin-amd64` architecture strings"
|
|
90
|
+
- "Prefer tools distributed via Homebrew — many formulae now have native ARM64 bottles"
|
|
91
|
+
- "Use `${{ runner.arch }}` in workflow expressions to branch on architecture (`X64` vs `ARM64`)"
|
|
92
|
+
- "Audit npm packages with native addons — they must support `darwin-arm64` or provide a WASM fallback"
|
|
93
|
+
docs:
|
|
94
|
+
- url: "https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources"
|
|
95
|
+
label: "GitHub Docs: Supported runners and hardware resources"
|
|
96
|
+
- url: "https://support.apple.com/en-us/102527"
|
|
97
|
+
label: "Apple: If you need to install Rosetta on your Mac"
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
id: runner-environment-155
|
|
2
|
+
title: "GitHub-hosted runner disk full — 'No space left on device' during large builds"
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- disk-space
|
|
7
|
+
- ubuntu
|
|
8
|
+
- docker
|
|
9
|
+
- large-builds
|
|
10
|
+
- runner-storage
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'No space left on device'
|
|
13
|
+
flags: i
|
|
14
|
+
- regex: 'write.*error.*28|errno 28'
|
|
15
|
+
flags: i
|
|
16
|
+
- regex: 'disk.*full|filesystem.*full|out of disk'
|
|
17
|
+
flags: i
|
|
18
|
+
- regex: 'no space left'
|
|
19
|
+
flags: i
|
|
20
|
+
error_messages:
|
|
21
|
+
- "No space left on device"
|
|
22
|
+
- "Error: write /var/lib/docker/tmp/...: no space left on device"
|
|
23
|
+
- "tar: ./app: Cannot write: No space left on device"
|
|
24
|
+
- "error: failed to push some refs: No space left on device"
|
|
25
|
+
- "OSError: [Errno 28] No space left on device"
|
|
26
|
+
root_cause: |
|
|
27
|
+
GitHub-hosted Ubuntu runners have approximately 14 GB of usable disk space after the
|
|
28
|
+
pre-installed tool suite occupies the rest. The runner image includes a large set of
|
|
29
|
+
pre-installed software that consumes the majority of available disk:
|
|
30
|
+
- Android SDK: ~8.7 GB
|
|
31
|
+
- .NET SDKs: ~1.5 GB
|
|
32
|
+
- Haskell/GHC: ~5.4 GB
|
|
33
|
+
- CodeQL: ~5.4 GB
|
|
34
|
+
- Docker images cached on the runner: varies
|
|
35
|
+
|
|
36
|
+
Workflows that perform large Docker builds, pull multiple Docker images, build large
|
|
37
|
+
native packages, or accumulate many npm/cargo/maven dependencies can exhaust the
|
|
38
|
+
~14 GB limit. Common triggers:
|
|
39
|
+
- `docker build` for large multi-stage images
|
|
40
|
+
- `docker pull` of several large base images
|
|
41
|
+
- Building and caching large Rust/C++ projects
|
|
42
|
+
- Downloading large ML models or datasets
|
|
43
|
+
- Generating large test fixtures or build artifacts
|
|
44
|
+
|
|
45
|
+
The error manifests in diverse ways: Docker build errors (errno 28), tar extraction
|
|
46
|
+
failures, git push failures writing pack files, or Python/Node crashes writing temp files.
|
|
47
|
+
fix: |
|
|
48
|
+
Free disk space before your build by removing pre-installed tools you don't need.
|
|
49
|
+
The community-maintained `jlumbroso/free-disk-space` action is the standard solution.
|
|
50
|
+
|
|
51
|
+
Manual removal commands for the largest consumers:
|
|
52
|
+
- Android SDK: `sudo rm -rf /usr/local/lib/android`
|
|
53
|
+
- .NET: `sudo rm -rf /usr/share/dotnet`
|
|
54
|
+
- Haskell/GHC: `sudo rm -rf /usr/local/.ghcup`
|
|
55
|
+
- Large packages: `sudo apt-get clean && sudo apt-get autoremove -y`
|
|
56
|
+
- Docker build cache: `docker builder prune -af`
|
|
57
|
+
|
|
58
|
+
Alternatively, upgrade to GitHub-hosted larger runners (4+ cores) which provide
|
|
59
|
+
more disk space, or use self-hosted runners.
|
|
60
|
+
fix_code:
|
|
61
|
+
- language: yaml
|
|
62
|
+
label: "Free disk space before large Docker build"
|
|
63
|
+
code: |
|
|
64
|
+
jobs:
|
|
65
|
+
build:
|
|
66
|
+
runs-on: ubuntu-latest
|
|
67
|
+
steps:
|
|
68
|
+
- name: Free disk space
|
|
69
|
+
uses: jlumbroso/free-disk-space@main
|
|
70
|
+
with:
|
|
71
|
+
tool-cache: false
|
|
72
|
+
android: true
|
|
73
|
+
dotnet: true
|
|
74
|
+
haskell: true
|
|
75
|
+
large-packages: true
|
|
76
|
+
docker-images: true
|
|
77
|
+
swap-storage: true
|
|
78
|
+
- uses: actions/checkout@v4
|
|
79
|
+
- name: Build Docker image
|
|
80
|
+
run: docker build -t myapp:latest .
|
|
81
|
+
- language: yaml
|
|
82
|
+
label: "Manual removal of largest pre-installed tools"
|
|
83
|
+
code: |
|
|
84
|
+
steps:
|
|
85
|
+
- name: Free disk space (manual)
|
|
86
|
+
run: |
|
|
87
|
+
df -h /
|
|
88
|
+
sudo rm -rf /usr/local/lib/android
|
|
89
|
+
sudo rm -rf /usr/share/dotnet
|
|
90
|
+
sudo rm -rf /usr/local/.ghcup
|
|
91
|
+
sudo apt-get clean
|
|
92
|
+
docker builder prune -af || true
|
|
93
|
+
df -h /
|
|
94
|
+
prevention:
|
|
95
|
+
- "Add a disk-space check step (`df -h /`) early in the workflow to detect capacity issues before they cause cryptic failures"
|
|
96
|
+
- "Run `jlumbroso/free-disk-space` before any Docker build or large compilation job"
|
|
97
|
+
- "Remove only tools you know you don't need — removing the tool-cache may break `actions/setup-*` steps"
|
|
98
|
+
- "Consider using `runs-on: ubuntu-latest-4-cores` (GitHub Teams) which provides more disk space"
|
|
99
|
+
- "Use Docker `--no-cache` flags cautiously — reusing layer cache can actually save disk vs rebuilding every layer"
|
|
100
|
+
docs:
|
|
101
|
+
- url: "https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources"
|
|
102
|
+
label: "GitHub Docs: Runner hardware resources"
|
|
103
|
+
- url: "https://github.com/jlumbroso/free-disk-space"
|
|
104
|
+
label: "jlumbroso/free-disk-space action"
|
|
105
|
+
- url: "https://github.com/actions/runner-images/issues/2840"
|
|
106
|
+
label: "runner-images#2840: Tracking disk space usage"
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
id: runner-environment-152
|
|
2
|
+
title: 'Organization "Require immutable actions" policy blocks tag-pinned action refs — must use full commit SHA'
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- immutable-actions
|
|
7
|
+
- sha-pinning
|
|
8
|
+
- security-policy
|
|
9
|
+
- organization-policy
|
|
10
|
+
- enterprise
|
|
11
|
+
- supply-chain
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'not pinned to an immutable SHA'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'Action.*is not pinned.*immutable'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: 'immutable actions.*required'
|
|
18
|
+
flags: 'i'
|
|
19
|
+
- regex: 'Update the workflow to use the immutable reference'
|
|
20
|
+
flags: 'i'
|
|
21
|
+
error_messages:
|
|
22
|
+
- "Error: Action 'actions/checkout@v4' is not pinned to an immutable SHA. Update the workflow to use the immutable reference."
|
|
23
|
+
- "Actions must be pinned to an immutable commit SHA. Organization policy requires immutable actions."
|
|
24
|
+
- "Error: This action reference is not immutable. The organization requires all actions to be pinned by SHA."
|
|
25
|
+
root_cause: |
|
|
26
|
+
GitHub introduced an organization-level security policy called "Require immutable
|
|
27
|
+
actions" (available in GitHub Enterprise and GitHub Teams since late 2025). When
|
|
28
|
+
enabled by an organization admin, every `uses:` reference in every workflow within
|
|
29
|
+
that organization must point to a full commit SHA rather than a mutable tag (such
|
|
30
|
+
as `@v4`) or branch name (such as `@main`).
|
|
31
|
+
|
|
32
|
+
Tags and branches are mutable — they can be updated to point to a different commit
|
|
33
|
+
at any time. An attacker who compromises an upstream action repository can move a
|
|
34
|
+
widely used tag to point to malicious code. The SHA immutability policy protects
|
|
35
|
+
against this supply-chain attack vector by ensuring the exact code being run is
|
|
36
|
+
pinned and verifiable.
|
|
37
|
+
|
|
38
|
+
When the policy is active, the Actions runner validates every `uses:` reference
|
|
39
|
+
before execution and refuses to run any workflow containing mutable refs, even if
|
|
40
|
+
the referenced tag currently points to a trusted commit. This commonly surfaces
|
|
41
|
+
after an organization adopts the policy post-hoc, breaking all existing workflows.
|
|
42
|
+
fix: |
|
|
43
|
+
Replace every `uses:` tag or branch reference with the full 40-character commit SHA.
|
|
44
|
+
Add the human-readable tag as an inline comment for maintainability.
|
|
45
|
+
|
|
46
|
+
To find the SHA for a specific action version:
|
|
47
|
+
- Visit the action's GitHub releases page (e.g., github.com/actions/checkout/releases/tag/v4)
|
|
48
|
+
- Click the commit SHA link next to the tag
|
|
49
|
+
|
|
50
|
+
Tools that automate SHA pinning across all workflow files:
|
|
51
|
+
- `ratchet` (github.com/thepwagner/ratchet): `ratchet pin .github/workflows/`
|
|
52
|
+
- `pin-github-action` (Mend): available as a GitHub Action or CLI
|
|
53
|
+
- Dependabot with `package-ecosystem: github-actions` maintains pinned SHAs automatically
|
|
54
|
+
fix_code:
|
|
55
|
+
- language: yaml
|
|
56
|
+
label: 'Pin action refs to full commit SHA (with readable comment)'
|
|
57
|
+
code: |
|
|
58
|
+
# BEFORE (fails with immutable actions org policy)
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/checkout@v4
|
|
61
|
+
- uses: actions/setup-node@v4
|
|
62
|
+
- uses: actions/upload-artifact@v4
|
|
63
|
+
|
|
64
|
+
# AFTER (SHA-pinned with human-readable tag comment)
|
|
65
|
+
steps:
|
|
66
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
67
|
+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
68
|
+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
69
|
+
- language: yaml
|
|
70
|
+
label: 'Dependabot config to keep SHA pins up to date automatically'
|
|
71
|
+
code: |
|
|
72
|
+
# .github/dependabot.yml
|
|
73
|
+
version: 2
|
|
74
|
+
updates:
|
|
75
|
+
- package-ecosystem: github-actions
|
|
76
|
+
directory: /
|
|
77
|
+
schedule:
|
|
78
|
+
interval: weekly
|
|
79
|
+
prevention:
|
|
80
|
+
- 'Audit all workflow files before enabling the org policy — run ratchet or pin-github-action across the entire .github/workflows/ directory first.'
|
|
81
|
+
- 'Enable the policy in a single pilot repository before rolling it out organization-wide to identify and fix all mutable refs.'
|
|
82
|
+
- 'Add actionlint with SHA-pinning rules to CI so new mutable refs are caught in PRs before reaching main.'
|
|
83
|
+
- 'Configure Dependabot for github-actions to automatically open PRs whenever a pinned SHA has a new upstream release.'
|
|
84
|
+
docs:
|
|
85
|
+
- url: 'https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#using-third-party-actions'
|
|
86
|
+
label: 'Security hardening for GitHub Actions: using third-party actions'
|
|
87
|
+
- url: 'https://docs.github.com/en/organizations/managing-organization-settings/disabling-or-limiting-github-actions-for-your-organization'
|
|
88
|
+
label: 'Requiring immutable action components (org policy settings)'
|
|
89
|
+
- url: 'https://github.com/thepwagner/ratchet'
|
|
90
|
+
label: 'ratchet — CLI tool to pin GitHub Actions refs to SHA'
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
id: runner-environment-156
|
|
2
|
+
title: "ubuntu runner: snap packages unavailable — snapd not running"
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- ubuntu
|
|
7
|
+
- snap
|
|
8
|
+
- snapd
|
|
9
|
+
- packages
|
|
10
|
+
- ubuntu-24
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'cannot communicate with server.*snapd\.socket'
|
|
13
|
+
flags: i
|
|
14
|
+
- regex: 'snapd is not running'
|
|
15
|
+
flags: i
|
|
16
|
+
- regex: 'snap.*connect.*refused|dial unix.*snapd'
|
|
17
|
+
flags: i
|
|
18
|
+
- regex: 'snap: command not found'
|
|
19
|
+
flags: i
|
|
20
|
+
error_messages:
|
|
21
|
+
- "error: cannot communicate with server: Post \"http://localhost/v2/snaps/kubectl\": dial unix /run/snapd.socket: connect: no such file or directory"
|
|
22
|
+
- "error: cannot communicate with server: Post http://localhost/v2/snaps: dial unix /run/snapd.socket: connect: no such file or directory"
|
|
23
|
+
- "snapd is not running"
|
|
24
|
+
- "snap: command not found"
|
|
25
|
+
root_cause: |
|
|
26
|
+
GitHub-hosted Ubuntu runners do not run the snapd daemon. The snap socket
|
|
27
|
+
`/run/snapd.socket` is never created, so any `snap install` command immediately fails
|
|
28
|
+
when attempting to communicate with the snap store daemon.
|
|
29
|
+
|
|
30
|
+
While the `snap` binary may be present on the runner image, the background snapd service
|
|
31
|
+
is not started because GitHub-hosted runners use a minimal systemd-free environment.
|
|
32
|
+
Starting snapd manually is not practical — it requires systemd or a complex manual
|
|
33
|
+
daemon startup sequence, and snap packages are confined using AppArmor profiles that
|
|
34
|
+
may also be unavailable in the runner environment.
|
|
35
|
+
|
|
36
|
+
This is frequently encountered when workflows try to install tools distributed as snaps:
|
|
37
|
+
kubectl, microk8s, aws-cli, spotify, and many developer utilities.
|
|
38
|
+
fix: |
|
|
39
|
+
Replace `snap install` with an alternative package source for the tool you need:
|
|
40
|
+
|
|
41
|
+
- **kubectl**: Use `curl -LO https://dl.k8s.io/release/...` or the `azure/setup-kubectl` action
|
|
42
|
+
- **aws-cli v2**: Use `pip install awscli` or the official AWS install script via apt
|
|
43
|
+
- **Helm**: Use the `azure/setup-helm` action or the official install script
|
|
44
|
+
- **General tools**: Check for apt, pip, npm, or GitHub releases as alternatives
|
|
45
|
+
|
|
46
|
+
If you must install a snap, consider using a self-hosted runner with snapd enabled,
|
|
47
|
+
or a Docker container runner with snapd configured.
|
|
48
|
+
fix_code:
|
|
49
|
+
- language: yaml
|
|
50
|
+
label: "Install kubectl via apt instead of snap"
|
|
51
|
+
code: |
|
|
52
|
+
steps:
|
|
53
|
+
- name: Install kubectl
|
|
54
|
+
run: |
|
|
55
|
+
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key \
|
|
56
|
+
| sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
|
|
57
|
+
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' \
|
|
58
|
+
| sudo tee /etc/apt/sources.list.d/kubernetes.list
|
|
59
|
+
sudo apt-get update
|
|
60
|
+
sudo apt-get install -y kubectl
|
|
61
|
+
- language: yaml
|
|
62
|
+
label: "Use dedicated setup actions instead of snap"
|
|
63
|
+
code: |
|
|
64
|
+
steps:
|
|
65
|
+
# Instead of: snap install kubectl --classic
|
|
66
|
+
- uses: azure/setup-kubectl@v4
|
|
67
|
+
with:
|
|
68
|
+
version: 'v1.30.0'
|
|
69
|
+
|
|
70
|
+
# Instead of: snap install helm --classic
|
|
71
|
+
- uses: azure/setup-helm@v4
|
|
72
|
+
with:
|
|
73
|
+
version: '3.14.0'
|
|
74
|
+
|
|
75
|
+
# Instead of: snap install aws-cli --classic
|
|
76
|
+
- name: Install AWS CLI v2
|
|
77
|
+
run: |
|
|
78
|
+
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
|
|
79
|
+
unzip awscliv2.zip
|
|
80
|
+
sudo ./aws/install
|
|
81
|
+
prevention:
|
|
82
|
+
- "Audit your workflow for any `snap install` commands — GitHub-hosted runners cannot run snap packages"
|
|
83
|
+
- "Check if the tool has an official GitHub Action (setup-kubectl, setup-helm, etc.) before writing a manual install step"
|
|
84
|
+
- "For tools not on apt, prefer GitHub Releases binary downloads with `curl` and `chmod +x` over snap"
|
|
85
|
+
- "Self-hosted runners with a full Ubuntu desktop/server installation do support snap if needed"
|
|
86
|
+
docs:
|
|
87
|
+
- url: "https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#software-installed-on-github-hosted-runners"
|
|
88
|
+
label: "GitHub Docs: Software installed on GitHub-hosted runners"
|
|
89
|
+
- url: "https://github.com/actions/runner-images/issues/1769"
|
|
90
|
+
label: "runner-images#1769: snap is not supported"
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
id: runner-environment-153
|
|
2
|
+
title: "ubuntu runner systemctl fails — systemd not running as PID 1"
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- ubuntu
|
|
7
|
+
- systemd
|
|
8
|
+
- systemctl
|
|
9
|
+
- services
|
|
10
|
+
- daemon
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'System has not been booted with systemd as init system \(PID 1\)\. Can''t operate\.'
|
|
13
|
+
flags: i
|
|
14
|
+
- regex: 'Failed to connect to bus: No such file or directory'
|
|
15
|
+
flags: i
|
|
16
|
+
- regex: 'systemctl: command not found'
|
|
17
|
+
flags: i
|
|
18
|
+
error_messages:
|
|
19
|
+
- "System has not been booted with systemd as init system (PID 1). Can't operate."
|
|
20
|
+
- "Failed to connect to bus: No such file or directory"
|
|
21
|
+
- "Failed to start postgresql.service: Unit not found."
|
|
22
|
+
- "System has not been booted with systemd"
|
|
23
|
+
root_cause: |
|
|
24
|
+
GitHub-hosted Ubuntu runners do not run systemd as the init system (PID 1). The runner
|
|
25
|
+
process starts directly inside a container-like environment where systemd is never initialized.
|
|
26
|
+
Any workflow step that calls `sudo systemctl start <service>`, `systemctl enable <service>`,
|
|
27
|
+
or `systemctl status <service>` will immediately fail because the D-Bus socket and systemd
|
|
28
|
+
unit system are not present.
|
|
29
|
+
|
|
30
|
+
This is a fundamental architectural constraint of GitHub-hosted runners — they are ephemeral
|
|
31
|
+
VMs (not containers) but systemd is disabled to reduce boot time and resource overhead. The
|
|
32
|
+
pattern is extremely common when devs copy-paste service startup commands from their local
|
|
33
|
+
Linux environment or documentation into GitHub Actions run: steps.
|
|
34
|
+
|
|
35
|
+
Common affected services: PostgreSQL, MySQL, Redis, MongoDB, Nginx, Apache, RabbitMQ.
|
|
36
|
+
fix: |
|
|
37
|
+
Replace `systemctl` calls with one of these approaches:
|
|
38
|
+
|
|
39
|
+
1. **Use GitHub Actions `services:` containers** — the recommended approach for databases and
|
|
40
|
+
message queues. GitHub spins up Docker containers alongside your job.
|
|
41
|
+
|
|
42
|
+
2. **Use direct daemon start commands** — start the service binary directly:
|
|
43
|
+
- PostgreSQL: `sudo -u postgres pg_ctl -D /etc/postgresql/*/main start`
|
|
44
|
+
- MySQL: `sudo mysqld_safe &`
|
|
45
|
+
- Redis: `redis-server --daemonize yes`
|
|
46
|
+
|
|
47
|
+
3. **Use `service` SysV command** — on Ubuntu runners, SysV init `service` works even without
|
|
48
|
+
systemd: `sudo service postgresql start`
|
|
49
|
+
|
|
50
|
+
fix_code:
|
|
51
|
+
- language: yaml
|
|
52
|
+
label: "Use services: containers block (recommended for databases)"
|
|
53
|
+
code: |
|
|
54
|
+
jobs:
|
|
55
|
+
test:
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
services:
|
|
58
|
+
postgres:
|
|
59
|
+
image: postgres:16
|
|
60
|
+
env:
|
|
61
|
+
POSTGRES_PASSWORD: postgres
|
|
62
|
+
ports:
|
|
63
|
+
- 5432:5432
|
|
64
|
+
options: >-
|
|
65
|
+
--health-cmd pg_isready
|
|
66
|
+
--health-interval 10s
|
|
67
|
+
--health-timeout 5s
|
|
68
|
+
--health-retries 5
|
|
69
|
+
steps:
|
|
70
|
+
- uses: actions/checkout@v4
|
|
71
|
+
- name: Run tests
|
|
72
|
+
run: npm test
|
|
73
|
+
env:
|
|
74
|
+
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
|
|
75
|
+
- language: yaml
|
|
76
|
+
label: "Use SysV 'service' command as systemctl fallback"
|
|
77
|
+
code: |
|
|
78
|
+
steps:
|
|
79
|
+
- name: Start PostgreSQL
|
|
80
|
+
run: |
|
|
81
|
+
sudo service postgresql start
|
|
82
|
+
sudo service postgresql status
|
|
83
|
+
- name: Create test database
|
|
84
|
+
run: |
|
|
85
|
+
sudo -u postgres psql -c "CREATE DATABASE testdb;"
|
|
86
|
+
prevention:
|
|
87
|
+
- "Use the `services:` block in your workflow for databases and message queues — it's the GitHub Actions-native solution"
|
|
88
|
+
- "Replace `systemctl start X` with `sudo service X start` for SysV-compatible services"
|
|
89
|
+
- "For custom daemons, start them in the background with `&` and poll for readiness"
|
|
90
|
+
- "Never copy-paste `systemctl` commands from local Linux setup scripts into GitHub Actions without adaptation"
|
|
91
|
+
docs:
|
|
92
|
+
- url: "https://docs.github.com/en/actions/use-cases-and-examples/using-containerized-services/about-service-containers"
|
|
93
|
+
label: "GitHub Docs: About service containers"
|
|
94
|
+
- url: "https://docs.github.com/en/actions/use-cases-and-examples/using-containerized-services/creating-postgresql-service-containers"
|
|
95
|
+
label: "GitHub Docs: Creating PostgreSQL service containers"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
id: silent-failures-081
|
|
2
|
+
title: '`needs.<job_id>.conclusion` does not exist — correct property is `result`; evaluates to empty string silently'
|
|
3
|
+
category: silent-failures
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- needs-context
|
|
7
|
+
- job-result
|
|
8
|
+
- downstream-jobs
|
|
9
|
+
- if-condition
|
|
10
|
+
- empty-string
|
|
11
|
+
- notification-job
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'needs\.\w+\.conclusion'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
error_messages:
|
|
16
|
+
- "needs.<job_id>.conclusion evaluates to empty string — condition using .conclusion never fires"
|
|
17
|
+
root_cause: |
|
|
18
|
+
The `needs` context exposes `.result` for each upstream job — NOT `.conclusion`.
|
|
19
|
+
Valid values for `needs.<job_id>.result` are: `success`, `failure`, `cancelled`,
|
|
20
|
+
and `skipped`.
|
|
21
|
+
|
|
22
|
+
The property `.conclusion` does not exist on the needs context object. Accessing
|
|
23
|
+
`needs.<job_id>.conclusion` silently evaluates to an empty string `""` with no
|
|
24
|
+
warning, error, or annotation in the workflow logs. The downstream job runs but the
|
|
25
|
+
`if:` condition never matches because `"" == 'failure'` is always false.
|
|
26
|
+
|
|
27
|
+
This confusion arises because the `steps` context exposes BOTH `.conclusion` and
|
|
28
|
+
`.outcome` for step results, leading developers to assume the needs context follows
|
|
29
|
+
the same property naming. The mismatch causes notification jobs, cleanup steps, and
|
|
30
|
+
failure-handler jobs to silently skip execution with no observable error.
|
|
31
|
+
fix: |
|
|
32
|
+
Replace `.conclusion` with `.result` in all `needs` context expressions.
|
|
33
|
+
|
|
34
|
+
WRONG: if: needs.build.conclusion == 'failure' # always empty string, never matches
|
|
35
|
+
RIGHT: if: needs.build.result == 'failure' # correct
|
|
36
|
+
|
|
37
|
+
For aggregate checks, prefer the built-in status functions over manual needs.result
|
|
38
|
+
comparisons — `failure()`, `success()`, `cancelled()`, `always()` — which evaluate
|
|
39
|
+
the combined result of all upstream jobs automatically.
|
|
40
|
+
fix_code:
|
|
41
|
+
- language: yaml
|
|
42
|
+
label: 'Correct: use needs.<job>.result not needs.<job>.conclusion'
|
|
43
|
+
code: |
|
|
44
|
+
jobs:
|
|
45
|
+
build:
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@v4
|
|
49
|
+
- run: npm ci && npm test
|
|
50
|
+
|
|
51
|
+
notify-on-failure:
|
|
52
|
+
needs: [build]
|
|
53
|
+
# Use built-in failure() or explicit needs.<job>.result
|
|
54
|
+
if: failure()
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
steps:
|
|
57
|
+
- name: Send failure notification
|
|
58
|
+
run: |
|
|
59
|
+
echo "Build result: ${{ needs.build.result }}"
|
|
60
|
+
# .result values: success | failure | cancelled | skipped
|
|
61
|
+
- language: yaml
|
|
62
|
+
label: 'Multi-job downstream check using needs.result'
|
|
63
|
+
code: |
|
|
64
|
+
jobs:
|
|
65
|
+
deploy:
|
|
66
|
+
needs: [lint, test, build]
|
|
67
|
+
# Explicit per-job result check — use .result not .conclusion
|
|
68
|
+
if: >-
|
|
69
|
+
needs.lint.result == 'success' &&
|
|
70
|
+
needs.test.result == 'success' &&
|
|
71
|
+
needs.build.result == 'success'
|
|
72
|
+
runs-on: ubuntu-latest
|
|
73
|
+
steps:
|
|
74
|
+
- run: echo "All upstream jobs succeeded"
|
|
75
|
+
prevention:
|
|
76
|
+
- 'The needs context exposes `.result` only — `.conclusion` does not exist. Use `needs.<job>.result` for all downstream conditional checks.'
|
|
77
|
+
- 'Prefer the status check functions `failure()`, `success()`, `cancelled()`, `always()` in downstream job `if:` conditions — they aggregate all upstream job results automatically.'
|
|
78
|
+
- 'Add actionlint to CI — it reports references to undefined context properties including `needs.<job>.conclusion`, catching this mistake at review time.'
|
|
79
|
+
- 'When a notification or cleanup job silently skips, verify the `if:` condition uses `.result` and check the actual result value in the Actions run summary.'
|
|
80
|
+
docs:
|
|
81
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#needs-context'
|
|
82
|
+
label: 'GitHub Actions: needs context — result property'
|
|
83
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/using-conditions-to-control-job-execution'
|
|
84
|
+
label: 'Using conditions to control job execution'
|
|
85
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#status-check-functions'
|
|
86
|
+
label: 'Status check functions: failure(), success(), cancelled(), always()'
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
id: yaml-syntax-055
|
|
2
|
+
title: '`on.workflow_call.outputs.value` references `steps.<id>.outputs` — steps context unavailable at workflow scope; must use `jobs.<job_id>.outputs`'
|
|
3
|
+
category: yaml-syntax
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- reusable-workflow
|
|
7
|
+
- workflow_call
|
|
8
|
+
- outputs
|
|
9
|
+
- steps-context
|
|
10
|
+
- jobs-context
|
|
11
|
+
- empty-string
|
|
12
|
+
- scope
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: 'steps\.\w+\.outputs\.\w+'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
error_messages:
|
|
17
|
+
- "Reusable workflow output is empty — steps context not accessible in on.workflow_call.outputs.value"
|
|
18
|
+
- "on.workflow_call.outputs value references steps context which is not available at workflow scope"
|
|
19
|
+
root_cause: |
|
|
20
|
+
In a reusable workflow, `on.workflow_call.outputs[*].value:` expressions are
|
|
21
|
+
evaluated at the WORKFLOW level, not within a job. The `steps` context is scoped to
|
|
22
|
+
a specific job and is only accessible inside that job's step expressions — it is
|
|
23
|
+
not visible at the top-level workflow scope where `on.workflow_call.outputs` lives.
|
|
24
|
+
|
|
25
|
+
Using `${{ steps.upload.outputs.artifact-id }}` in the `value:` field silently
|
|
26
|
+
evaluates to an empty string. No error, warning, or annotation is raised; the
|
|
27
|
+
caller simply receives an empty output value.
|
|
28
|
+
|
|
29
|
+
The correct pattern requires two explicit hops:
|
|
30
|
+
1. Capture the step output at the JOB level using the job's `outputs:` block.
|
|
31
|
+
2. Reference the JOB output at the WORKFLOW level using `${{ jobs.<job_id>.outputs.<key> }}`.
|
|
32
|
+
|
|
33
|
+
Note: this is distinct from yaml-syntax-032 (jobs.<id>.result empty in workflow_call
|
|
34
|
+
outputs) which covers the result property specifically, not step output propagation.
|
|
35
|
+
fix: |
|
|
36
|
+
Bridge step outputs up through the job's `outputs:` block first, then reference the
|
|
37
|
+
job output in `on.workflow_call.outputs.value`.
|
|
38
|
+
|
|
39
|
+
Pattern:
|
|
40
|
+
step writes to GITHUB_OUTPUT (or action output)
|
|
41
|
+
→ job outputs: exposes it as jobs.<job_id>.outputs.<key>
|
|
42
|
+
→ on.workflow_call.outputs.value references jobs.<job_id>.outputs.<key>
|
|
43
|
+
fix_code:
|
|
44
|
+
- language: yaml
|
|
45
|
+
label: 'Correct two-hop output propagation for reusable workflows'
|
|
46
|
+
code: |
|
|
47
|
+
on:
|
|
48
|
+
workflow_call:
|
|
49
|
+
outputs:
|
|
50
|
+
artifact-id:
|
|
51
|
+
description: 'ID of the uploaded build artifact'
|
|
52
|
+
# CORRECT: reference job-level output
|
|
53
|
+
value: ${{ jobs.build.outputs.artifact-id }}
|
|
54
|
+
# WRONG (silent empty string):
|
|
55
|
+
# value: ${{ steps.upload.outputs.artifact-id }}
|
|
56
|
+
|
|
57
|
+
jobs:
|
|
58
|
+
build:
|
|
59
|
+
runs-on: ubuntu-latest
|
|
60
|
+
outputs:
|
|
61
|
+
# Hop 1: expose step output at job level
|
|
62
|
+
artifact-id: ${{ steps.upload.outputs.artifact-id }}
|
|
63
|
+
steps:
|
|
64
|
+
- uses: actions/checkout@v4
|
|
65
|
+
|
|
66
|
+
- name: Build
|
|
67
|
+
run: npm ci && npm run build
|
|
68
|
+
|
|
69
|
+
- name: Upload artifact
|
|
70
|
+
id: upload
|
|
71
|
+
uses: actions/upload-artifact@v4
|
|
72
|
+
with:
|
|
73
|
+
name: build-output
|
|
74
|
+
path: dist/
|
|
75
|
+
# Hop 2: job outputs block above captures steps.upload.outputs.artifact-id
|
|
76
|
+
# Hop 3: on.workflow_call.outputs.value references jobs.build.outputs.artifact-id
|
|
77
|
+
prevention:
|
|
78
|
+
- 'The `steps` context is job-scoped. Always bridge step outputs through the job `outputs:` block before referencing them at workflow level in `on.workflow_call.outputs.value:`.'
|
|
79
|
+
- 'Use actionlint to statically analyze reusable workflow output expressions — it reports invalid context usage at workflow scope.'
|
|
80
|
+
- 'When a reusable workflow output is unexpectedly empty in the caller, check whether the `value:` expression uses `steps.` (wrong scope) vs `jobs.` (correct scope).'
|
|
81
|
+
- 'Each output needs both a job-level `outputs:` mapping AND a workflow-level `on.workflow_call.outputs[*].value:` reference — missing either hop silently returns empty string.'
|
|
82
|
+
docs:
|
|
83
|
+
- url: 'https://docs.github.com/en/actions/sharing-automations/reusing-workflows#using-outputs-from-a-reusable-workflow'
|
|
84
|
+
label: 'Reusable workflows: using outputs'
|
|
85
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/passing-information-between-jobs'
|
|
86
|
+
label: 'Passing information between jobs (job outputs)'
|
|
87
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#steps-context'
|
|
88
|
+
label: 'Steps context — job-scoped, not available at workflow level'
|
package/package.json
CHANGED