@htekdev/actions-debugger 1.0.49 → 1.0.51
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/caching-artifacts/caching-artifacts-035.yml +119 -0
- package/errors/runner-environment/runner-environment-105.yml +111 -0
- package/errors/runner-environment/runner-environment-106.yml +110 -0
- package/errors/runner-environment/runner-environment-107.yml +105 -0
- package/errors/runner-environment/runner-environment-108.yml +109 -0
- package/errors/runner-environment/runner-environment-109.yml +121 -0
- package/errors/triggers/triggers-038.yml +126 -0
- package/errors/yaml-syntax/yaml-syntax-036.yml +100 -0
- package/package.json +1 -1
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
id: caching-artifacts-035
|
|
2
|
+
title: 'actions/cache fail-on-cache-miss: true causes first-run workflow failure — no cache exists on initial or rekeyed run'
|
|
3
|
+
category: caching-artifacts
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- cache
|
|
7
|
+
- fail-on-cache-miss
|
|
8
|
+
- first-run
|
|
9
|
+
- actions-cache
|
|
10
|
+
- cache-miss
|
|
11
|
+
- bootstrap
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'fail-on-cache-miss:\s*true'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'Error: Cannot find a cache that matches the specified keys'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
error_messages:
|
|
18
|
+
- 'Error: Cannot find a cache that matches the specified keys'
|
|
19
|
+
- 'Cache not found for input keys: ...'
|
|
20
|
+
- '##[error]Cannot find a cache that matches the specified keys'
|
|
21
|
+
root_cause: |
|
|
22
|
+
The actions/cache action added a fail-on-cache-miss input (introduced in v3.3.0,
|
|
23
|
+
available in v4). When set to true, the action exits with a non-zero status code
|
|
24
|
+
if no cache entry matches the provided key or restore-keys list. The intended use
|
|
25
|
+
case is detecting stale or misconfigured cache keys in established pipelines.
|
|
26
|
+
|
|
27
|
+
The critical problem: on the very first run of a workflow (new repository, newly
|
|
28
|
+
added cache step, or after changing the cache key expression), NO cache exists by
|
|
29
|
+
definition. With fail-on-cache-miss: true, the action fails immediately and the
|
|
30
|
+
job exits before any steps produce the artifacts that would be cached.
|
|
31
|
+
|
|
32
|
+
This creates a bootstrap deadlock:
|
|
33
|
+
1. Job starts — no cache exists — fail-on-cache-miss: true fires — job fails
|
|
34
|
+
2. Post-step cache save never runs because the job failed
|
|
35
|
+
3. Next run repeats step 1 — cache is never populated — workflow is permanently broken
|
|
36
|
+
|
|
37
|
+
The same issue occurs whenever the cache key expression changes (adding runner OS,
|
|
38
|
+
changing the hash source file, bumping a version prefix), because all existing
|
|
39
|
+
caches miss the new key pattern. Until the new cache is warm, every run fails.
|
|
40
|
+
|
|
41
|
+
Matrix builds compound the problem: each unique matrix dimension (OS × version)
|
|
42
|
+
needs its own initial run to seed the cache, so all combinations fail in parallel
|
|
43
|
+
on first use of the new key.
|
|
44
|
+
fix: |
|
|
45
|
+
Remove fail-on-cache-miss: true from the actions/cache step unless you have an
|
|
46
|
+
externally pre-seeded cache and a specific requirement to guarantee it exists
|
|
47
|
+
(rare, advanced use case).
|
|
48
|
+
|
|
49
|
+
For the common use case of skipping expensive install steps on cache hit:
|
|
50
|
+
use the cache-hit output instead. cache-hit is 'true' on exact key match and
|
|
51
|
+
allows downstream steps to be conditional, while still letting the job complete
|
|
52
|
+
successfully on a miss so the cache can be populated.
|
|
53
|
+
|
|
54
|
+
If you genuinely need to gate on cache existence (e.g., a nightly build that
|
|
55
|
+
consumes a separately-seeded model or dataset cache), run a dedicated cache-warming
|
|
56
|
+
workflow first and use fail-on-cache-miss: true only after confirming the seeder
|
|
57
|
+
workflow has run at least once.
|
|
58
|
+
fix_code:
|
|
59
|
+
- language: yaml
|
|
60
|
+
label: 'Use cache-hit output for conditional install instead of fail-on-cache-miss'
|
|
61
|
+
code: |
|
|
62
|
+
jobs:
|
|
63
|
+
build:
|
|
64
|
+
runs-on: ubuntu-latest
|
|
65
|
+
steps:
|
|
66
|
+
- uses: actions/checkout@v4
|
|
67
|
+
|
|
68
|
+
- name: Cache npm dependencies
|
|
69
|
+
id: cache-npm
|
|
70
|
+
uses: actions/cache@v4
|
|
71
|
+
with:
|
|
72
|
+
path: ~/.npm
|
|
73
|
+
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
|
|
74
|
+
restore-keys: |
|
|
75
|
+
${{ runner.os }}-npm-
|
|
76
|
+
# AVOID: fail-on-cache-miss: true ← breaks first run (deadlock)
|
|
77
|
+
|
|
78
|
+
- name: Install dependencies
|
|
79
|
+
# Only runs on cache miss — fast path skipped on hit
|
|
80
|
+
if: steps.cache-npm.outputs.cache-hit != 'true'
|
|
81
|
+
run: npm ci
|
|
82
|
+
|
|
83
|
+
- name: Build
|
|
84
|
+
run: npm run build
|
|
85
|
+
|
|
86
|
+
- language: yaml
|
|
87
|
+
label: 'Dedicated cache-warming workflow to pre-seed before fail-on-cache-miss use'
|
|
88
|
+
code: |
|
|
89
|
+
# .github/workflows/warm-cache.yml — run this first to pre-seed
|
|
90
|
+
name: Warm Cache
|
|
91
|
+
on:
|
|
92
|
+
schedule:
|
|
93
|
+
- cron: '0 6 * * 1'
|
|
94
|
+
workflow_dispatch: # Allow manual trigger when rekeying cache
|
|
95
|
+
|
|
96
|
+
jobs:
|
|
97
|
+
warm:
|
|
98
|
+
runs-on: ubuntu-latest
|
|
99
|
+
steps:
|
|
100
|
+
- uses: actions/checkout@v4
|
|
101
|
+
- name: Cache dependencies
|
|
102
|
+
uses: actions/cache@v4
|
|
103
|
+
with:
|
|
104
|
+
path: ~/.npm
|
|
105
|
+
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
|
|
106
|
+
- name: Install to populate cache
|
|
107
|
+
run: npm ci
|
|
108
|
+
prevention:
|
|
109
|
+
- 'Never set fail-on-cache-miss: true on a fresh workflow or after changing the cache key expression — the cache cannot exist yet'
|
|
110
|
+
- 'Use cache-hit output and conditional if: steps.id.outputs.cache-hit != true for skip-on-hit behavior without failing on miss'
|
|
111
|
+
- 'When rekeying cache (OS prefix, hash source change), trigger a manual cache-warming workflow_dispatch run before deploying the new key'
|
|
112
|
+
- 'Test new cache key expressions in a feature branch where a job failure will not block main'
|
|
113
|
+
docs:
|
|
114
|
+
- url: 'https://github.com/actions/cache'
|
|
115
|
+
label: 'actions/cache README — fail-on-cache-miss input documentation'
|
|
116
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows'
|
|
117
|
+
label: 'GitHub Docs: Caching dependencies to speed up workflows'
|
|
118
|
+
- url: 'https://github.com/actions/cache/blob/main/tips-and-workarounds.md'
|
|
119
|
+
label: 'actions/cache tips and workarounds — cache miss handling patterns'
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
id: runner-environment-105
|
|
2
|
+
title: 'macOS 12 (Monterey) runner retired September 2024 — runs-on: macos-12 workflows fail or queue indefinitely'
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- macos-12
|
|
7
|
+
- runner-retirement
|
|
8
|
+
- macos-monterey
|
|
9
|
+
- deprecated-runner
|
|
10
|
+
- github-hosted
|
|
11
|
+
- runs-on
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'runs-on:\s*macos-12'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'No runner matching the specified labels was found.*macos-12|Requested labels: macos-12'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
error_messages:
|
|
18
|
+
- 'No runner matching the specified labels was found: macos-12'
|
|
19
|
+
- '##[error]No runner matching the specified labels was found'
|
|
20
|
+
- 'Runner not found matching labels: [macos-12]'
|
|
21
|
+
root_cause: |
|
|
22
|
+
GitHub retired the macOS 12 (Monterey) hosted runner on September 1, 2024. After
|
|
23
|
+
this date, workflows specifying runs-on: macos-12 can no longer be scheduled on a
|
|
24
|
+
GitHub-hosted runner matching that label.
|
|
25
|
+
|
|
26
|
+
Depending on repository and organization settings, affected jobs may:
|
|
27
|
+
- Fail immediately with "No runner matching the specified labels was found"
|
|
28
|
+
- Queue indefinitely waiting for a runner that will never be provisioned
|
|
29
|
+
- Show a "This job was skipped" status with no clear error message
|
|
30
|
+
|
|
31
|
+
GitHub announced the deprecation on May 20, 2024 (90+ days notice) and made it
|
|
32
|
+
official with a deprecation flag on July 1, 2024. Hard retirement occurred
|
|
33
|
+
September 1, 2024.
|
|
34
|
+
|
|
35
|
+
macOS 12 was the Monterey release. GitHub's macOS runner fleet moved to:
|
|
36
|
+
- macOS 13 (Ventura) — Intel x86-64, became the Intel baseline
|
|
37
|
+
- macOS 14 (Sonoma) — Apple Silicon M1, new default for macos-latest (Oct 2024)
|
|
38
|
+
- macOS 15 (Sequoia) — Apple Silicon M2, macos-latest as of January 2025
|
|
39
|
+
|
|
40
|
+
Common sources of this error after retirement:
|
|
41
|
+
- Long-lived workflow files written when macOS 12 was current
|
|
42
|
+
- Forks and template repositories with outdated runner labels
|
|
43
|
+
- Composite actions that pin macos-12 in their action.yml runs: block
|
|
44
|
+
- Third-party reusable workflows that have not been updated
|
|
45
|
+
fix: |
|
|
46
|
+
Replace runs-on: macos-12 with a supported macOS runner label. Choose based on
|
|
47
|
+
architecture requirements:
|
|
48
|
+
|
|
49
|
+
- macos-13 — Intel x86-64, macOS Ventura (closest to macOS 12 behavior)
|
|
50
|
+
- macos-14 — Apple Silicon M1, macOS Sonoma
|
|
51
|
+
- macos-15 — Apple Silicon M2, macOS Sequoia
|
|
52
|
+
- macos-latest — currently macOS 15 / Apple Silicon as of January 2025
|
|
53
|
+
|
|
54
|
+
IMPORTANT: macos-14 and later use Apple Silicon (M1/M2). If your workflow depends
|
|
55
|
+
on Intel x86-64 architecture (Homebrew formula paths differ, Rosetta 2 needed for
|
|
56
|
+
old binaries, or x86-specific compiler flags), migrate to macos-13, not macos-latest.
|
|
57
|
+
|
|
58
|
+
After migrating, verify:
|
|
59
|
+
- Homebrew default prefix changed from /usr/local (Intel) to /opt/homebrew (ARM)
|
|
60
|
+
- Xcode version availability — use actions/setup-xcode for explicit version pinning
|
|
61
|
+
- System Python and Ruby versions differ between macOS generations
|
|
62
|
+
- Any hardcoded SDKROOT or architecture flags targeting x86-64
|
|
63
|
+
fix_code:
|
|
64
|
+
- language: yaml
|
|
65
|
+
label: 'Replace retired macos-12 with macos-13 (Intel) or macos-14/15 (Apple Silicon)'
|
|
66
|
+
code: |
|
|
67
|
+
jobs:
|
|
68
|
+
build-intel:
|
|
69
|
+
# Before: runs-on: macos-12 ← retired September 1, 2024
|
|
70
|
+
# Intel x86-64 — closest behavioral match to macOS 12:
|
|
71
|
+
runs-on: macos-13
|
|
72
|
+
steps:
|
|
73
|
+
- uses: actions/checkout@v4
|
|
74
|
+
- name: Build
|
|
75
|
+
run: make build
|
|
76
|
+
|
|
77
|
+
build-arm:
|
|
78
|
+
# Apple Silicon M1/M2 — use for new projects or ARM-compatible builds:
|
|
79
|
+
runs-on: macos-latest # macOS 15 / Apple Silicon as of Jan 2025
|
|
80
|
+
steps:
|
|
81
|
+
- uses: actions/checkout@v4
|
|
82
|
+
- name: Build
|
|
83
|
+
run: make build
|
|
84
|
+
|
|
85
|
+
- language: yaml
|
|
86
|
+
label: 'Matrix across macOS versions to validate compatibility before committing to one'
|
|
87
|
+
code: |
|
|
88
|
+
jobs:
|
|
89
|
+
test:
|
|
90
|
+
strategy:
|
|
91
|
+
matrix:
|
|
92
|
+
# Test Intel (13) and Apple Silicon (14) in parallel
|
|
93
|
+
os: [macos-13, macos-14]
|
|
94
|
+
fail-fast: false
|
|
95
|
+
runs-on: ${{ matrix.os }}
|
|
96
|
+
steps:
|
|
97
|
+
- uses: actions/checkout@v4
|
|
98
|
+
- name: Test on ${{ matrix.os }}
|
|
99
|
+
run: make test
|
|
100
|
+
prevention:
|
|
101
|
+
- 'Subscribe to the GitHub Changelog (github.blog/changelog) for runner retirement notices — typically 90+ days notice'
|
|
102
|
+
- 'Pin to a specific macOS version (macos-13, macos-14) rather than macos-latest for reproducible builds; macos-latest advances'
|
|
103
|
+
- 'Be aware of architecture differences: macos-13 is Intel x86-64; macos-14 and later are Apple Silicon'
|
|
104
|
+
- 'Search workflow files periodically for retired labels: look for macos-12, macos-11, ubuntu-18.04, windows-2019'
|
|
105
|
+
docs:
|
|
106
|
+
- url: 'https://github.blog/changelog/2024-05-20-actions-upcoming-changes-to-github-hosted-macos-runners/'
|
|
107
|
+
label: 'GitHub Changelog: Upcoming changes to macOS runners (May 2024)'
|
|
108
|
+
- url: 'https://github.blog/changelog/2024-07-01-github-actions-macos-12-is-now-deprecated/'
|
|
109
|
+
label: 'GitHub Changelog: macOS 12 is now deprecated (July 2024)'
|
|
110
|
+
- url: 'https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources'
|
|
111
|
+
label: 'GitHub Docs: Supported runners and hardware resources'
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
id: runner-environment-106
|
|
2
|
+
title: 'Windows Server 2019 (windows-2019) runner retired April 1, 2025 — jobs fail or queue indefinitely'
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- windows-2019
|
|
7
|
+
- runner-retirement
|
|
8
|
+
- windows-server-2019
|
|
9
|
+
- deprecated-runner
|
|
10
|
+
- github-hosted
|
|
11
|
+
- runs-on
|
|
12
|
+
- visual-studio-2019
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: 'runs-on:\s*windows-2019'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'No runner matching the specified labels was found.*windows-2019|Requested labels:\s*windows-2019'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
error_messages:
|
|
19
|
+
- 'No runner matching the specified labels was found: windows-2019'
|
|
20
|
+
- '##[error]No runner matching the specified labels was found'
|
|
21
|
+
- 'Runner not found matching labels: [windows-2019]'
|
|
22
|
+
root_cause: |
|
|
23
|
+
GitHub retired the Windows Server 2019 (windows-2019) GitHub-hosted runner on
|
|
24
|
+
April 1, 2025. After this date, workflows specifying runs-on: windows-2019 can
|
|
25
|
+
no longer be scheduled on a GitHub-hosted runner matching that label.
|
|
26
|
+
|
|
27
|
+
GitHub announced the deprecation in September 2024 (90+ days notice) with
|
|
28
|
+
brownout periods beginning before the hard cutoff. windows-latest had already
|
|
29
|
+
transitioned to point to windows-2022 (Windows Server 2022 with Visual Studio
|
|
30
|
+
2022) on October 28, 2024, giving teams an early signal.
|
|
31
|
+
|
|
32
|
+
Workflows most affected:
|
|
33
|
+
- Files explicitly specifying runs-on: windows-2019 (not windows-latest)
|
|
34
|
+
- Builds relying on Visual Studio 2019 toolset version v142 MSBuild tools
|
|
35
|
+
- .csproj files with hardcoded <PlatformToolset>v142</PlatformToolset>
|
|
36
|
+
- Workflows using .NET Framework or SDK behaviors specific to the VS2019 era
|
|
37
|
+
- Actions pinned to a major version that internally specified windows-2019
|
|
38
|
+
- Forks and template repositories written before windows-2022 was the default
|
|
39
|
+
|
|
40
|
+
A secondary migration concern: workflows that used windows-latest and relied on
|
|
41
|
+
VS2019 behavior were silently broken when windows-latest moved to windows-2022
|
|
42
|
+
in October 2024. Pinning to windows-2019 was a common workaround — the
|
|
43
|
+
retirement forced resolution of both the workaround and the underlying toolset
|
|
44
|
+
incompatibility simultaneously.
|
|
45
|
+
fix: |
|
|
46
|
+
Replace runs-on: windows-2019 with a supported Windows runner label:
|
|
47
|
+
|
|
48
|
+
- windows-2022 — Windows Server 2022, Visual Studio 2022 (toolset v143)
|
|
49
|
+
- windows-2025 — Windows Server 2025, Visual Studio 2022 (available 2025)
|
|
50
|
+
- windows-latest — currently maps to windows-2022
|
|
51
|
+
|
|
52
|
+
If your workflow uses MSBuild and specifies PlatformToolset=v142 (VS2019
|
|
53
|
+
toolset), you have two options:
|
|
54
|
+
1. Update project files to remove the explicit PlatformToolset element and
|
|
55
|
+
let MSBuild select the installed toolset automatically (preferred).
|
|
56
|
+
2. Migrate the .csproj to PlatformToolset v143 (VS2022 toolset).
|
|
57
|
+
|
|
58
|
+
Check these locations for VS2019-specific behavior:
|
|
59
|
+
- .csproj files with <PlatformToolset>v142</PlatformToolset>
|
|
60
|
+
- Hardcoded paths like C:\Program Files (x86)\Microsoft Visual Studio\2019\...
|
|
61
|
+
- vcpkg toolchain files referencing VS2019 installs
|
|
62
|
+
- Workflow env: blocks with hardcoded VSINSTALLDIR paths
|
|
63
|
+
fix_code:
|
|
64
|
+
- language: yaml
|
|
65
|
+
label: 'Replace retired windows-2019 with windows-2022'
|
|
66
|
+
code: |
|
|
67
|
+
jobs:
|
|
68
|
+
build:
|
|
69
|
+
# Before: runs-on: windows-2019 <- retired April 1, 2025
|
|
70
|
+
runs-on: windows-2022
|
|
71
|
+
steps:
|
|
72
|
+
- uses: actions/checkout@v4
|
|
73
|
+
|
|
74
|
+
- name: Setup MSBuild
|
|
75
|
+
uses: microsoft/setup-msbuild@v2
|
|
76
|
+
|
|
77
|
+
- name: Build solution
|
|
78
|
+
run: msbuild solution.sln /p:Configuration=Release /p:Platform="Any CPU"
|
|
79
|
+
# If build fails on toolset version, update PlatformToolset in .csproj
|
|
80
|
+
# from v142 (VS2019) to v143 (VS2022) or remove it to auto-select
|
|
81
|
+
|
|
82
|
+
- language: yaml
|
|
83
|
+
label: 'Matrix across Windows versions to verify migration before cutover'
|
|
84
|
+
code: |
|
|
85
|
+
jobs:
|
|
86
|
+
build:
|
|
87
|
+
strategy:
|
|
88
|
+
matrix:
|
|
89
|
+
# windows-2019 removed — retired April 1, 2025
|
|
90
|
+
os: [windows-2022]
|
|
91
|
+
fail-fast: false
|
|
92
|
+
runs-on: ${{ matrix.os }}
|
|
93
|
+
steps:
|
|
94
|
+
- uses: actions/checkout@v4
|
|
95
|
+
- name: Setup MSBuild
|
|
96
|
+
uses: microsoft/setup-msbuild@v2
|
|
97
|
+
- name: Build
|
|
98
|
+
run: msbuild solution.sln /p:Configuration=Release
|
|
99
|
+
prevention:
|
|
100
|
+
- 'Use windows-latest or windows-2022 — never pin to a specific older Windows runner label for long-lived workflows'
|
|
101
|
+
- 'Avoid hardcoding Visual Studio toolset versions (v142, v143) in .csproj files — let MSBuild auto-select the installed toolset'
|
|
102
|
+
- 'Subscribe to GitHub Changelog at github.blog/changelog to receive runner retirement announcements before hard cutoff dates'
|
|
103
|
+
- 'Test on windows-2022 in a feature branch before any deprecation deadline to catch VS toolset migration issues early'
|
|
104
|
+
docs:
|
|
105
|
+
- url: 'https://github.blog/changelog/2024-09-12-windows-2019-actions-runner-image-brownout-and-deprecation/'
|
|
106
|
+
label: 'GitHub Changelog: Windows 2019 runner image brownout and deprecation'
|
|
107
|
+
- url: 'https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources'
|
|
108
|
+
label: 'GitHub Docs: Supported GitHub-hosted runners and hardware resources'
|
|
109
|
+
- url: 'https://github.com/actions/runner-images'
|
|
110
|
+
label: 'actions/runner-images: GitHub-hosted runner image specifications'
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
id: runner-environment-107
|
|
2
|
+
title: 'Ubuntu 24.04 runner: unversioned python command absent — /usr/bin/env: python: No such file or directory'
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- ubuntu-24
|
|
7
|
+
- python
|
|
8
|
+
- python3
|
|
9
|
+
- unversioned-alias
|
|
10
|
+
- command-not-found
|
|
11
|
+
- ubuntu-noble
|
|
12
|
+
- ubuntu-latest
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: '/usr/bin/env:\s*[''"]?python[''"]?:\s*No such file|python:\s*command not found'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'runs-on:\s*ubuntu-2[4-9]|runs-on:\s*ubuntu-latest'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
error_messages:
|
|
19
|
+
- '/usr/bin/env: python: No such file or directory'
|
|
20
|
+
- 'python: command not found'
|
|
21
|
+
- '##[error]Process completed with exit code 127.'
|
|
22
|
+
root_cause: |
|
|
23
|
+
Ubuntu 24.04 (Noble Numbat) does not install the unversioned python command by
|
|
24
|
+
default. Only python3 (Python 3.12+) is present in the PATH. This follows
|
|
25
|
+
PEP 394 guidance and a deliberate Ubuntu packaging decision: the
|
|
26
|
+
python3-is-python package (which creates a /usr/bin/python -> python3 symlink)
|
|
27
|
+
is not pre-installed on GitHub-hosted Ubuntu 24.04 runners.
|
|
28
|
+
|
|
29
|
+
As of November 2024, ubuntu-latest on GitHub-hosted runners maps to ubuntu-24.04.
|
|
30
|
+
Workflows that ran on ubuntu-latest (previously ubuntu-22.04) began failing
|
|
31
|
+
because Ubuntu 22.04 runners had side-effected python aliases through
|
|
32
|
+
actions/setup-python or the python-is-python3 shim, while the Ubuntu 24.04
|
|
33
|
+
baseline has no unversioned python at all.
|
|
34
|
+
|
|
35
|
+
Affected patterns:
|
|
36
|
+
- run: python script.py
|
|
37
|
+
- run: python -m pytest
|
|
38
|
+
- Shell scripts with #!/usr/bin/env python shebang lines
|
|
39
|
+
- Makefile targets invoking python
|
|
40
|
+
- Third-party composite actions that call python internally without setup-python
|
|
41
|
+
- pip invocations — pip is also absent (only pip3 available)
|
|
42
|
+
fix: |
|
|
43
|
+
Option 1 (recommended): Use actions/setup-python before any step that needs
|
|
44
|
+
Python. This installs a versioned Python and creates both python and python3
|
|
45
|
+
symlinks in PATH, resolving the problem portably across all runner OS versions.
|
|
46
|
+
|
|
47
|
+
Option 2: Replace all python invocations with python3 in workflow files.
|
|
48
|
+
Also replace pip with pip3 or python3 -m pip. Works if you control all scripts
|
|
49
|
+
but misses shebangs in vendor code or third-party tools.
|
|
50
|
+
|
|
51
|
+
Option 3: Install the alias manually in a setup step:
|
|
52
|
+
sudo apt-get install -y python-is-python3
|
|
53
|
+
This creates the /usr/bin/python -> python3 symlink immediately. The package is
|
|
54
|
+
already in the apt cache — install is fast with no download required.
|
|
55
|
+
fix_code:
|
|
56
|
+
- language: yaml
|
|
57
|
+
label: 'Use actions/setup-python (recommended — portable across all runner versions)'
|
|
58
|
+
code: |
|
|
59
|
+
jobs:
|
|
60
|
+
test:
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
steps:
|
|
63
|
+
- uses: actions/checkout@v4
|
|
64
|
+
|
|
65
|
+
- name: Set up Python
|
|
66
|
+
uses: actions/setup-python@v5
|
|
67
|
+
with:
|
|
68
|
+
python-version: '3.12'
|
|
69
|
+
# Creates both python and python3 aliases in PATH
|
|
70
|
+
|
|
71
|
+
- name: Install dependencies
|
|
72
|
+
run: python -m pip install -r requirements.txt
|
|
73
|
+
|
|
74
|
+
- name: Run tests
|
|
75
|
+
run: python -m pytest tests/
|
|
76
|
+
|
|
77
|
+
- language: yaml
|
|
78
|
+
label: 'Install python-is-python3 alias for scripts with hardcoded python shebangs'
|
|
79
|
+
code: |
|
|
80
|
+
jobs:
|
|
81
|
+
build:
|
|
82
|
+
runs-on: ubuntu-latest
|
|
83
|
+
steps:
|
|
84
|
+
- uses: actions/checkout@v4
|
|
85
|
+
|
|
86
|
+
- name: Install python alias
|
|
87
|
+
run: sudo apt-get install -y python-is-python3
|
|
88
|
+
# Creates /usr/bin/python -> python3 symlink
|
|
89
|
+
# Fast: package already in apt cache on ubuntu-24.04
|
|
90
|
+
|
|
91
|
+
- name: Run script with python shebang
|
|
92
|
+
run: ./scripts/legacy-build.sh
|
|
93
|
+
# Script uses #!/usr/bin/env python internally
|
|
94
|
+
prevention:
|
|
95
|
+
- 'Always use actions/setup-python in workflows that invoke python — portable and creates the python alias on all runner OS versions'
|
|
96
|
+
- 'Avoid relying on system Python; python version and alias availability varies between Ubuntu 22.04 and 24.04'
|
|
97
|
+
- 'When ubuntu-latest bumps to a new Ubuntu version, search run: blocks and scripts for bare python and pip invocations'
|
|
98
|
+
- 'Pin ubuntu-24.04 explicitly during transition testing rather than ubuntu-latest to catch breakage before it hits production'
|
|
99
|
+
docs:
|
|
100
|
+
- url: 'https://github.com/actions/runner-images/issues/9654'
|
|
101
|
+
label: 'runner-images#9654: python command not found on Ubuntu 24.04'
|
|
102
|
+
- url: 'https://github.com/actions/runner-images'
|
|
103
|
+
label: 'actions/runner-images: GitHub-hosted runner image specifications'
|
|
104
|
+
- url: 'https://github.com/actions/setup-python'
|
|
105
|
+
label: 'actions/setup-python: Set up a Python environment for use in Actions'
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
id: runner-environment-108
|
|
2
|
+
title: 'Ubuntu 22.04 runner: libssl.so.1.1 missing — binaries compiled on Ubuntu 20.04 fail with cannot open shared object file'
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- ubuntu-22
|
|
7
|
+
- libssl
|
|
8
|
+
- openssl3
|
|
9
|
+
- shared-library
|
|
10
|
+
- binary-compatibility
|
|
11
|
+
- ubuntu-jammy
|
|
12
|
+
- dynamic-linking
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: 'libssl\.so\.1\.1.*cannot open shared object file|error while loading shared libraries: libssl\.so\.1\.1'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'libcrypto\.so\.1\.1.*cannot open shared object file'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
error_messages:
|
|
19
|
+
- 'error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory'
|
|
20
|
+
- '/usr/lib/x86_64-linux-gnu/libssl.so.1.1: No such file or directory'
|
|
21
|
+
- 'error while loading shared libraries: libcrypto.so.1.1: cannot open shared object file: No such file or directory'
|
|
22
|
+
root_cause: |
|
|
23
|
+
Ubuntu 22.04 (Jammy) ships OpenSSL 3.0, replacing OpenSSL 1.1. The shared
|
|
24
|
+
library libssl.so.1.1 is absent — the libssl1.1 package that provided it is
|
|
25
|
+
not available in the Ubuntu 22.04 (jammy) package repository at all; it was
|
|
26
|
+
a focal (Ubuntu 20.04) package only.
|
|
27
|
+
|
|
28
|
+
When ubuntu-latest transitioned from Ubuntu 20.04 to Ubuntu 22.04 in 2022,
|
|
29
|
+
CI pipelines that downloaded or shipped pre-compiled binaries started failing
|
|
30
|
+
because those binaries were dynamically linked against libssl1.1. Common
|
|
31
|
+
scenarios that trigger this error:
|
|
32
|
+
|
|
33
|
+
- Self-hosted runners migrated from Ubuntu 20.04 to 22.04 while tool cache
|
|
34
|
+
contains pre-compiled focal binaries
|
|
35
|
+
- Docker images with pre-compiled binaries using libssl1.1 run in container
|
|
36
|
+
jobs on ubuntu-22.04 hosts
|
|
37
|
+
- Ruby gems with native extensions (mysql2, pg, ruby-openssl) compiled on
|
|
38
|
+
Ubuntu 20.04 and installed from a cached bundler path
|
|
39
|
+
- Node.js native add-ons (node-gyp built) that link against libssl1.1
|
|
40
|
+
- Custom CLI tools shipped as pre-built .deb or tar.gz for Ubuntu 20.04
|
|
41
|
+
- Python C extension packages (pycurl, cryptography old versions) with
|
|
42
|
+
libssl1.1 runtime dependency
|
|
43
|
+
|
|
44
|
+
libcrypto.so.1.1 is also absent — tools linked against both libraries fail
|
|
45
|
+
with the same error on whichever library is loaded first.
|
|
46
|
+
fix: |
|
|
47
|
+
Option 1 (best long-term): Recompile the affected binary for Ubuntu 22.04 or
|
|
48
|
+
later against OpenSSL 3.0 (libssl3). Ubuntu 20.04 reached end-of-standard-support
|
|
49
|
+
in April 2025 — new binaries should target OpenSSL 3.0.
|
|
50
|
+
|
|
51
|
+
Option 2: Install a libssl1.1 compatibility .deb backported from Ubuntu 20.04
|
|
52
|
+
focal. Add an install step using the focal security archive. This is a
|
|
53
|
+
temporary workaround — the package receives no security patches on 22.04.
|
|
54
|
+
|
|
55
|
+
Option 3: Use a container job with ubuntu:20.04 base image for steps that
|
|
56
|
+
require libssl1.1, isolating the dependency from the host runner OS.
|
|
57
|
+
|
|
58
|
+
Option 4: Pin runs-on: ubuntu-20.04 temporarily while planning recompile.
|
|
59
|
+
ubuntu-20.04 runners will eventually be retired — plan a migration timeline.
|
|
60
|
+
fix_code:
|
|
61
|
+
- language: yaml
|
|
62
|
+
label: 'Install libssl1.1 compatibility shim from Ubuntu 20.04 focal archive (temporary workaround)'
|
|
63
|
+
code: |
|
|
64
|
+
jobs:
|
|
65
|
+
build:
|
|
66
|
+
runs-on: ubuntu-22.04
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v4
|
|
69
|
+
|
|
70
|
+
- name: Install libssl1.1 compatibility shim
|
|
71
|
+
run: |
|
|
72
|
+
wget -q http://security.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb
|
|
73
|
+
sudo dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb
|
|
74
|
+
# WARNING: Temporary workaround only. Recompile binary against OpenSSL 3.0 for the permanent fix.
|
|
75
|
+
|
|
76
|
+
- name: Run legacy binary
|
|
77
|
+
run: ./vendor/legacy-tool
|
|
78
|
+
|
|
79
|
+
- language: yaml
|
|
80
|
+
label: 'Use container job with ubuntu:20.04 base image to isolate libssl1.1 dependency'
|
|
81
|
+
code: |
|
|
82
|
+
jobs:
|
|
83
|
+
build:
|
|
84
|
+
runs-on: ubuntu-latest
|
|
85
|
+
container:
|
|
86
|
+
image: ubuntu:20.04
|
|
87
|
+
steps:
|
|
88
|
+
- uses: actions/checkout@v4
|
|
89
|
+
|
|
90
|
+
- name: Install prerequisites
|
|
91
|
+
run: |
|
|
92
|
+
apt-get update
|
|
93
|
+
apt-get install -y libssl1.1 curl
|
|
94
|
+
|
|
95
|
+
- name: Run legacy binary
|
|
96
|
+
run: ./vendor/legacy-tool
|
|
97
|
+
# Binary now runs with libssl1.1 available in container
|
|
98
|
+
prevention:
|
|
99
|
+
- 'Compile release binaries against the same OpenSSL version as the target runner OS (3.0 for Ubuntu 22.04+)'
|
|
100
|
+
- 'When upgrading ubuntu-latest, audit all pre-compiled binaries with ldd to check for libssl.so.1.1 dynamic dependencies before rolling out'
|
|
101
|
+
- 'Use statically-linked binaries or distroless container images for tools that must run across multiple Ubuntu versions'
|
|
102
|
+
- 'In matrix workflows, include ubuntu-22.04 alongside ubuntu-20.04 to catch OpenSSL ABI incompatibilities before retirement deadlines'
|
|
103
|
+
docs:
|
|
104
|
+
- url: 'https://github.com/actions/runner-images/issues/6399'
|
|
105
|
+
label: 'runner-images#6399: libssl.so.1.1 missing on Ubuntu 22.04'
|
|
106
|
+
- url: 'https://wiki.openssl.org/index.php/OpenSSL_3.0'
|
|
107
|
+
label: 'OpenSSL 3.0 migration guide — ABI compatibility with OpenSSL 1.1'
|
|
108
|
+
- url: 'https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners'
|
|
109
|
+
label: 'GitHub Docs: About GitHub-hosted runners'
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
id: runner-environment-109
|
|
2
|
+
title: 'macOS 14+ (Apple Silicon) runner: Homebrew prefix changed from /usr/local to /opt/homebrew — hardcoded paths fail'
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- macos-14
|
|
7
|
+
- apple-silicon
|
|
8
|
+
- homebrew
|
|
9
|
+
- arm64
|
|
10
|
+
- path
|
|
11
|
+
- macos-sonoma
|
|
12
|
+
- opt-homebrew
|
|
13
|
+
- cross-architecture
|
|
14
|
+
patterns:
|
|
15
|
+
- regex: '/usr/local/(bin/brew|Cellar|opt)\b'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: 'No such file or directory.*(/usr/local/bin/brew|/usr/local/opt|/usr/local/Cellar)'
|
|
18
|
+
flags: 'i'
|
|
19
|
+
error_messages:
|
|
20
|
+
- '/usr/local/bin/brew: No such file or directory'
|
|
21
|
+
- 'Error: No such file or directory @ rb_sysopen - /usr/local/Cellar'
|
|
22
|
+
- '/usr/local/opt/openssl: No such file or directory'
|
|
23
|
+
- 'pkg-config: /usr/local/opt/openssl/lib/pkgconfig: No such file or directory'
|
|
24
|
+
root_cause: |
|
|
25
|
+
Homebrew on Apple Silicon (ARM64) installs to /opt/homebrew, while Homebrew on
|
|
26
|
+
Intel x86-64 installs to /usr/local. This architectural split was introduced when
|
|
27
|
+
Homebrew added native Apple Silicon support in early 2021.
|
|
28
|
+
|
|
29
|
+
GitHub-hosted macOS runners on Apple Silicon hardware (macos-14, macos-15, and
|
|
30
|
+
macos-latest since October 2024) use /opt/homebrew as the Homebrew prefix.
|
|
31
|
+
Workflows migrating from macOS 12 or macOS 13 (Intel x86-64) to macOS 14+
|
|
32
|
+
(Apple Silicon) break when they reference hardcoded /usr/local paths:
|
|
33
|
+
|
|
34
|
+
- /usr/local/bin/brew — the brew binary itself
|
|
35
|
+
- /usr/local/Cellar/package-name — installed package files
|
|
36
|
+
- /usr/local/opt/package-name — formula options/keg link (very common for
|
|
37
|
+
openssl, readline, libpq, libyaml, icu4c, pkg-config)
|
|
38
|
+
- PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig in env: blocks
|
|
39
|
+
- OPENSSL_ROOT_DIR=/usr/local/opt/openssl in build steps
|
|
40
|
+
- LDFLAGS=-L/usr/local/opt/readline/lib for native extension builds
|
|
41
|
+
- CPPFLAGS=-I/usr/local/opt/openssl/include for C/C++ compilation
|
|
42
|
+
- Shell scripts that source /usr/local/etc/profile.d/
|
|
43
|
+
|
|
44
|
+
Commonly broken language ecosystems:
|
|
45
|
+
- Ruby gems with native extensions (nokogiri --with-opt-dir=/usr/local/opt/openssl)
|
|
46
|
+
- Python packages (pycurl, psycopg2, cryptography) with hardcoded CPPFLAGS
|
|
47
|
+
- Node.js native add-ons reading PKG_CONFIG_PATH pointing to /usr/local/opt
|
|
48
|
+
- Go builds with CGO_CFLAGS referencing /usr/local/include
|
|
49
|
+
fix: |
|
|
50
|
+
Replace all hardcoded /usr/local/opt and /usr/local/Cellar paths with the
|
|
51
|
+
dynamic output of brew --prefix [formula-name].
|
|
52
|
+
|
|
53
|
+
The portable pattern:
|
|
54
|
+
OPENSSL_ROOT_DIR=$(brew --prefix openssl)
|
|
55
|
+
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig"
|
|
56
|
+
|
|
57
|
+
brew --prefix returns /usr/local/opt/package on Intel and /opt/homebrew/opt/package
|
|
58
|
+
on Apple Silicon — making it correct on both architectures automatically.
|
|
59
|
+
|
|
60
|
+
For the Homebrew root itself, use the $HOMEBREW_PREFIX environment variable
|
|
61
|
+
which is pre-set by the runner image to the correct prefix (/usr/local or
|
|
62
|
+
/opt/homebrew) depending on the runner architecture.
|
|
63
|
+
|
|
64
|
+
Actionlint does not flag hardcoded /usr/local paths — a manual audit of
|
|
65
|
+
env: blocks and run: scripts is required when migrating runner architectures.
|
|
66
|
+
fix_code:
|
|
67
|
+
- language: yaml
|
|
68
|
+
label: 'Use brew --prefix for portable formula paths across Intel and Apple Silicon'
|
|
69
|
+
code: |
|
|
70
|
+
jobs:
|
|
71
|
+
build:
|
|
72
|
+
runs-on: macos-latest # macos-14+ on Apple Silicon (/opt/homebrew)
|
|
73
|
+
steps:
|
|
74
|
+
- uses: actions/checkout@v4
|
|
75
|
+
|
|
76
|
+
- name: Install dependencies
|
|
77
|
+
run: brew install openssl readline libpq
|
|
78
|
+
|
|
79
|
+
- name: Set library paths (portable — works on Intel and Apple Silicon)
|
|
80
|
+
run: |
|
|
81
|
+
echo "OPENSSL_ROOT_DIR=$(brew --prefix openssl)" >> $GITHUB_ENV
|
|
82
|
+
echo "PKG_CONFIG_PATH=$(brew --prefix openssl)/lib/pkgconfig:$(brew --prefix readline)/lib/pkgconfig" >> $GITHUB_ENV
|
|
83
|
+
echo "LDFLAGS=-L$(brew --prefix openssl)/lib -L$(brew --prefix readline)/lib" >> $GITHUB_ENV
|
|
84
|
+
echo "CPPFLAGS=-I$(brew --prefix openssl)/include -I$(brew --prefix readline)/include" >> $GITHUB_ENV
|
|
85
|
+
# DO NOT hardcode /usr/local/opt/... — breaks on Apple Silicon (/opt/homebrew)
|
|
86
|
+
|
|
87
|
+
- name: Install native gems
|
|
88
|
+
run: bundle install
|
|
89
|
+
|
|
90
|
+
- language: yaml
|
|
91
|
+
label: 'Use $HOMEBREW_PREFIX env variable for Homebrew root references'
|
|
92
|
+
code: |
|
|
93
|
+
jobs:
|
|
94
|
+
build:
|
|
95
|
+
runs-on: macos-latest
|
|
96
|
+
steps:
|
|
97
|
+
- uses: actions/checkout@v4
|
|
98
|
+
|
|
99
|
+
- name: Install tool
|
|
100
|
+
run: brew install libffi
|
|
101
|
+
|
|
102
|
+
- name: Build with native dependency
|
|
103
|
+
run: |
|
|
104
|
+
# $HOMEBREW_PREFIX is pre-set by the runner image
|
|
105
|
+
# Intel macOS 12/13: /usr/local
|
|
106
|
+
# Apple Silicon 14/15: /opt/homebrew
|
|
107
|
+
export LIBRARY_PATH="$HOMEBREW_PREFIX/lib:$LIBRARY_PATH"
|
|
108
|
+
export C_INCLUDE_PATH="$HOMEBREW_PREFIX/include:$C_INCLUDE_PATH"
|
|
109
|
+
make install
|
|
110
|
+
prevention:
|
|
111
|
+
- 'Never hardcode /usr/local/opt, /usr/local/Cellar, or /usr/local/bin/brew — always use brew --prefix <formula> at runtime'
|
|
112
|
+
- 'Use $HOMEBREW_PREFIX (set by runner images) for generic Homebrew root path references'
|
|
113
|
+
- 'When migrating from macos-12/13 (Intel) to macos-14+ (Apple Silicon), grep workflow files and scripts for /usr/local/ strings'
|
|
114
|
+
- 'Test with runs-on: macos-14 in a feature branch before switching macos-latest to catch architecture-specific path failures'
|
|
115
|
+
docs:
|
|
116
|
+
- url: 'https://docs.brew.sh/Installation'
|
|
117
|
+
label: 'Homebrew Installation docs: default prefix differences between Intel and Apple Silicon'
|
|
118
|
+
- url: 'https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md'
|
|
119
|
+
label: 'actions/runner-images: macOS 14 ARM64 image README'
|
|
120
|
+
- url: 'https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners'
|
|
121
|
+
label: 'GitHub Docs: About GitHub-hosted runners — macOS runner architecture details'
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
id: triggers-038
|
|
2
|
+
title: 'workflow_run.conclusion is null when the upstream run was cancelled before any job started — if: checks silently skip'
|
|
3
|
+
category: triggers
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- workflow-run
|
|
7
|
+
- conclusion
|
|
8
|
+
- cancelled
|
|
9
|
+
- null-conclusion
|
|
10
|
+
- if-condition
|
|
11
|
+
- cross-workflow
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'github\.event\.workflow_run\.conclusion\s*==\s*[''"]success[''"]'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'github\.event\.workflow_run\.conclusion\s*==\s*[''"]failure[''"]'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
error_messages:
|
|
18
|
+
- "(No error — triggered workflow runs but all jobs/steps with if: github.event.workflow_run.conclusion == 'success' silently skip)"
|
|
19
|
+
root_cause: |
|
|
20
|
+
When a downstream workflow uses on: workflow_run (types: [completed]), it fires
|
|
21
|
+
whenever an upstream workflow run reaches a terminal state. The
|
|
22
|
+
github.event.workflow_run.conclusion field is expected to reflect the outcome of
|
|
23
|
+
that upstream run.
|
|
24
|
+
|
|
25
|
+
However, if the upstream run was cancelled before any job started — for example,
|
|
26
|
+
due to a concurrent push triggering cancel-in-progress on the queued run, or a
|
|
27
|
+
manual UI cancellation before the run left the queue — the conclusion field is
|
|
28
|
+
null, not "cancelled".
|
|
29
|
+
|
|
30
|
+
GitHub's API returns: { "conclusion": null, "status": "cancelled" } for runs
|
|
31
|
+
cancelled while still queued. This is documented behavior: conclusion is only set
|
|
32
|
+
when at least one job has run to completion.
|
|
33
|
+
|
|
34
|
+
The effect on downstream conditional logic:
|
|
35
|
+
if: github.event.workflow_run.conclusion == 'success' → false (null != string)
|
|
36
|
+
if: github.event.workflow_run.conclusion == 'failure' → false
|
|
37
|
+
if: github.event.workflow_run.conclusion == 'cancelled' → also false (null != string)
|
|
38
|
+
if: github.event.workflow_run.conclusion != 'success' → TRUE (null != string)
|
|
39
|
+
|
|
40
|
+
The downstream workflow's workflow_run completed event fires and the workflow
|
|
41
|
+
starts, but every job with a success/failure/cancelled equality check is silently
|
|
42
|
+
skipped. A CD pipeline gated on CI success may appear to trigger but produce no
|
|
43
|
+
deployment with no error surfaced to the developer.
|
|
44
|
+
|
|
45
|
+
This can also silently allow deployment jobs protected by
|
|
46
|
+
conclusion != 'failure' to run when the upstream was an early cancellation.
|
|
47
|
+
fix: |
|
|
48
|
+
Treat workflow_run.conclusion as nullable. Always verify it is not null before
|
|
49
|
+
comparing to an expected value:
|
|
50
|
+
|
|
51
|
+
Option A — Explicit null check (most readable):
|
|
52
|
+
if: github.event.workflow_run.conclusion != null && github.event.workflow_run.conclusion == 'success'
|
|
53
|
+
|
|
54
|
+
Option B — contains() with fromJSON allowlist (handles null gracefully; null is
|
|
55
|
+
not in the list, so the condition evaluates false without error):
|
|
56
|
+
if: contains(fromJSON('["success"]'), github.event.workflow_run.conclusion)
|
|
57
|
+
|
|
58
|
+
Option C — Guard step that fails fast and visibly when conclusion is unexpected,
|
|
59
|
+
so silent skips become explicit failures:
|
|
60
|
+
- run: |
|
|
61
|
+
if [ "$CONCLUSION" != "success" ]; then
|
|
62
|
+
echo "Upstream conclusion was: $CONCLUSION"
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
env:
|
|
66
|
+
CONCLUSION: ${{ github.event.workflow_run.conclusion }}
|
|
67
|
+
fix_code:
|
|
68
|
+
- language: yaml
|
|
69
|
+
label: 'Use contains() with fromJSON to handle null conclusion safely'
|
|
70
|
+
code: |
|
|
71
|
+
on:
|
|
72
|
+
workflow_run:
|
|
73
|
+
workflows: ['CI']
|
|
74
|
+
types: [completed]
|
|
75
|
+
|
|
76
|
+
jobs:
|
|
77
|
+
deploy:
|
|
78
|
+
# contains() returns false when conclusion is null — no null-equality error
|
|
79
|
+
if: |
|
|
80
|
+
contains(fromJSON('["success"]'), github.event.workflow_run.conclusion) &&
|
|
81
|
+
github.event.workflow_run.head_branch == 'main'
|
|
82
|
+
runs-on: ubuntu-latest
|
|
83
|
+
steps:
|
|
84
|
+
- name: Deploy
|
|
85
|
+
run: echo "Deploying after confirmed CI success"
|
|
86
|
+
|
|
87
|
+
- language: yaml
|
|
88
|
+
label: 'Guard step that fails visibly on null or unexpected conclusion'
|
|
89
|
+
code: |
|
|
90
|
+
on:
|
|
91
|
+
workflow_run:
|
|
92
|
+
workflows: ['CI']
|
|
93
|
+
types: [completed]
|
|
94
|
+
|
|
95
|
+
jobs:
|
|
96
|
+
verify-conclusion:
|
|
97
|
+
runs-on: ubuntu-latest
|
|
98
|
+
steps:
|
|
99
|
+
- name: Check upstream conclusion
|
|
100
|
+
env:
|
|
101
|
+
CONCLUSION: ${{ github.event.workflow_run.conclusion }}
|
|
102
|
+
run: |
|
|
103
|
+
echo "Upstream workflow conclusion: $CONCLUSION"
|
|
104
|
+
if [ "$CONCLUSION" != "success" ]; then
|
|
105
|
+
echo "Expected 'success', got '$CONCLUSION' (possibly null if cancelled before job start)"
|
|
106
|
+
exit 1
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
deploy:
|
|
110
|
+
needs: verify-conclusion
|
|
111
|
+
runs-on: ubuntu-latest
|
|
112
|
+
steps:
|
|
113
|
+
- name: Deploy
|
|
114
|
+
run: echo "Deploying"
|
|
115
|
+
prevention:
|
|
116
|
+
- 'Always treat workflow_run.conclusion as nullable — a run cancelled while queued has conclusion: null, not "cancelled"'
|
|
117
|
+
- 'Use contains(fromJSON(...), github.event.workflow_run.conclusion) instead of == equality — contains() handles null safely'
|
|
118
|
+
- 'Add a guard step that prints the actual conclusion value to make silent skips visible during debugging'
|
|
119
|
+
- 'Prefer repository_dispatch for cross-workflow chaining when you need explicit control over the payload and conclusion semantics'
|
|
120
|
+
docs:
|
|
121
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_run'
|
|
122
|
+
label: 'GitHub Docs: workflow_run event — conclusion field behavior'
|
|
123
|
+
- url: 'https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#get-a-workflow-run'
|
|
124
|
+
label: 'GitHub REST API: Workflow run — conclusion is nullable'
|
|
125
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/contexts#github-context'
|
|
126
|
+
label: 'GitHub Docs: github.event.workflow_run context properties'
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
id: yaml-syntax-036
|
|
2
|
+
title: 'run-name: using github.event.head_commit.message shows "undefined" for schedule and workflow_dispatch events'
|
|
3
|
+
category: yaml-syntax
|
|
4
|
+
severity: warning
|
|
5
|
+
tags:
|
|
6
|
+
- run-name
|
|
7
|
+
- head-commit-message
|
|
8
|
+
- schedule
|
|
9
|
+
- workflow-dispatch
|
|
10
|
+
- null-property
|
|
11
|
+
- expression
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'run-name:.*head_commit\.message'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
error_messages:
|
|
16
|
+
- "(Run title in the UI displays 'undefined' or 'Deploy by @actor from undefined' — no log error is emitted)"
|
|
17
|
+
root_cause: |
|
|
18
|
+
The run-name: workflow key (introduced October 2022) lets you set a custom title
|
|
19
|
+
for each workflow run using GitHub Actions expressions. The GitHub Docs examples
|
|
20
|
+
include the pattern:
|
|
21
|
+
|
|
22
|
+
run-name: Deploy by @${{ github.actor }} from ${{ github.event.head_commit.message }}
|
|
23
|
+
|
|
24
|
+
However, github.event.head_commit is ONLY populated for on: push events. For
|
|
25
|
+
on: schedule, on: workflow_dispatch, on: pull_request, on: release, and most other
|
|
26
|
+
event types, the head_commit object is absent from the event payload. Accessing
|
|
27
|
+
github.event.head_commit.message on a null object evaluates to '' in some contexts
|
|
28
|
+
but renders as "undefined" in the Actions UI run title.
|
|
29
|
+
|
|
30
|
+
The result is a workflow run title like:
|
|
31
|
+
"Deploy by @octocat from undefined"
|
|
32
|
+
or simply "undefined" — confusing in the Actions tab and audit logs.
|
|
33
|
+
|
|
34
|
+
The workflow parses without error because the expression is syntactically valid.
|
|
35
|
+
The problem only surfaces at runtime when a non-push event triggers the workflow.
|
|
36
|
+
This is especially common in workflows that have both on: push and on: schedule or
|
|
37
|
+
on: workflow_dispatch triggers.
|
|
38
|
+
fix: |
|
|
39
|
+
Use the || short-circuit operator to provide fallback values for event types where
|
|
40
|
+
head_commit is absent. GitHub Actions expressions treat || as a null/false fallback:
|
|
41
|
+
|
|
42
|
+
run-name: "${{ github.event.head_commit.message || github.event.inputs.reason || 'Scheduled run' }}"
|
|
43
|
+
|
|
44
|
+
Prefer contexts that are populated for ALL event types:
|
|
45
|
+
- github.actor — always set (the user or app that triggered the run)
|
|
46
|
+
- github.ref_name — always set (branch or tag short name)
|
|
47
|
+
- github.run_number — always set (monotonically increasing per workflow)
|
|
48
|
+
- github.event.inputs.* — set for workflow_dispatch when inputs are defined
|
|
49
|
+
fix_code:
|
|
50
|
+
- language: yaml
|
|
51
|
+
label: 'Add || fallback so run-name is readable for all trigger types'
|
|
52
|
+
code: |
|
|
53
|
+
name: Deploy
|
|
54
|
+
# Without || fallback, schedule and workflow_dispatch show "undefined"
|
|
55
|
+
# github.event.head_commit is ONLY available on push events
|
|
56
|
+
run-name: "${{ github.event.head_commit.message || github.event.inputs.reason || 'Scheduled run' }}"
|
|
57
|
+
on:
|
|
58
|
+
push:
|
|
59
|
+
branches: [main]
|
|
60
|
+
schedule:
|
|
61
|
+
- cron: '0 8 * * 1'
|
|
62
|
+
workflow_dispatch:
|
|
63
|
+
inputs:
|
|
64
|
+
reason:
|
|
65
|
+
description: 'Reason for manual trigger'
|
|
66
|
+
required: false
|
|
67
|
+
jobs:
|
|
68
|
+
deploy:
|
|
69
|
+
runs-on: ubuntu-latest
|
|
70
|
+
steps:
|
|
71
|
+
- uses: actions/checkout@v4
|
|
72
|
+
|
|
73
|
+
- language: yaml
|
|
74
|
+
label: 'Use always-populated contexts for a universally safe run-name'
|
|
75
|
+
code: |
|
|
76
|
+
name: Deploy
|
|
77
|
+
# github.actor, github.ref_name, and github.run_number are set for every event
|
|
78
|
+
run-name: '${{ github.actor }} on ${{ github.ref_name }} (#${{ github.run_number }})'
|
|
79
|
+
on:
|
|
80
|
+
push:
|
|
81
|
+
schedule:
|
|
82
|
+
- cron: '0 8 * * 1'
|
|
83
|
+
workflow_dispatch:
|
|
84
|
+
jobs:
|
|
85
|
+
deploy:
|
|
86
|
+
runs-on: ubuntu-latest
|
|
87
|
+
steps:
|
|
88
|
+
- uses: actions/checkout@v4
|
|
89
|
+
prevention:
|
|
90
|
+
- 'Test run-name expressions against every trigger in your on: block — head_commit is only available for push events'
|
|
91
|
+
- 'Always provide a || fallback: github.event.head_commit.message || ''Scheduled run'' handles both push and non-push'
|
|
92
|
+
- 'Prefer github.actor, github.ref_name, and github.run_number — these are populated for every event type'
|
|
93
|
+
- 'Check context availability in the GitHub Docs contexts reference before using event-specific properties in run-name'
|
|
94
|
+
docs:
|
|
95
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#run-name'
|
|
96
|
+
label: 'GitHub Docs: Workflow syntax — run-name'
|
|
97
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/contexts#github-context'
|
|
98
|
+
label: 'GitHub Docs: github context — event-specific property availability'
|
|
99
|
+
- url: 'https://github.blog/changelog/2022-10-05-github-actions-run-name-and-workflow-run-title/'
|
|
100
|
+
label: 'GitHub Changelog: run-name and workflow run title (October 2022)'
|
package/package.json
CHANGED