@htekdev/actions-debugger 1.0.6 → 1.0.8
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/cache-10gb-limit-eviction.yml +135 -0
- package/errors/runner-environment/docker-29-compose-v2-40-breaking.yml +144 -0
- package/errors/runner-environment/node-20-toolcache-removal.yml +134 -0
- package/errors/runner-environment/setup-python-cache-no-dependency-file.yml +126 -0
- package/errors/runner-environment/ubuntu-arm64-docker-not-preinstalled.yml +137 -0
- package/errors/runner-environment/windows-2019-runner-retirement.yml +100 -0
- package/errors/triggers/merge-group-trigger-missing.yml +122 -0
- package/errors/yaml-syntax/set-output-deprecated-commands.yml +130 -0
- package/package.json +1 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
id: caching-artifacts-011
|
|
2
|
+
title: "Repository Cache Storage Limit (10 GB) — Silent Eviction Causes Cache Miss Spike"
|
|
3
|
+
category: caching-artifacts
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- cache
|
|
7
|
+
- storage-limit
|
|
8
|
+
- eviction
|
|
9
|
+
- cache-miss
|
|
10
|
+
- actions/cache
|
|
11
|
+
- 10gb
|
|
12
|
+
- lru
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: "cache.*evict|evict.*cache"
|
|
15
|
+
flags: "i"
|
|
16
|
+
- regex: "cache size.*limit|limit.*cache size"
|
|
17
|
+
flags: "i"
|
|
18
|
+
- regex: "exceeds.*10.*GB|10.*GB.*limit"
|
|
19
|
+
flags: "i"
|
|
20
|
+
- regex: "cache.*storage.*limit.*exceeded"
|
|
21
|
+
flags: "i"
|
|
22
|
+
error_messages:
|
|
23
|
+
- "Cache entry is too big. Maximum cache size is 10GB"
|
|
24
|
+
- "Warning: Cache size of XY GB (ZZZZ MB) is over the 10 GB limit, so some older caches will be removed"
|
|
25
|
+
- "Failed to save cache entry. Exiting with error: Cache storage quota has been reached for the current repository"
|
|
26
|
+
root_cause: |
|
|
27
|
+
GitHub limits the total Actions cache storage per repository to **10 GB**. When the
|
|
28
|
+
10 GB limit is reached, GitHub automatically evicts the **least-recently-used (LRU)**
|
|
29
|
+
cache entries to make room for new ones. Additionally, cache entries that have not been
|
|
30
|
+
accessed in **7 days** are automatically deleted.
|
|
31
|
+
|
|
32
|
+
**This is a silent failure** because:
|
|
33
|
+
- Eviction happens asynchronously — the job that triggers eviction does not fail.
|
|
34
|
+
- The workflow that was relying on an evicted cache simply gets a cache miss on the
|
|
35
|
+
next run and reinstalls from scratch, adding minutes to build time.
|
|
36
|
+
- There is no notification, no warning in the workflow log, and no failed check.
|
|
37
|
+
- Engineers often diagnose this as a "flaky cache" without realizing the 10 GB limit
|
|
38
|
+
is being hit regularly.
|
|
39
|
+
|
|
40
|
+
**Common causes of limit exhaustion:**
|
|
41
|
+
1. **Matrix builds with many OS/version combinations** each storing large dependency
|
|
42
|
+
caches (node_modules, .cargo, ~/.gradle, etc.).
|
|
43
|
+
2. **Large monorepo caches** where the entire dependency tree exceeds 10 GB.
|
|
44
|
+
3. **Docker layer caches** stored via `actions/cache` for repeated builds.
|
|
45
|
+
4. **Accumulation without cleanup** — cache keys rotate on every dependency update
|
|
46
|
+
but old entries aren't explicitly purged.
|
|
47
|
+
|
|
48
|
+
**How to check current cache usage:**
|
|
49
|
+
Repository → Actions → Management → Caches (or via `gh cache list --repo owner/repo`).
|
|
50
|
+
fix: |
|
|
51
|
+
Reduce total cache storage by improving cache key strategy and explicitly pruning old
|
|
52
|
+
cache entries.
|
|
53
|
+
|
|
54
|
+
**Immediate steps:**
|
|
55
|
+
1. Audit current cache usage with `gh cache list --repo owner/repo --sort size --order desc`
|
|
56
|
+
2. Delete oversized or stale entries with `gh cache delete <id> --repo owner/repo`
|
|
57
|
+
3. Review matrix build cache keys — large matrices with OS+version combinations
|
|
58
|
+
multiply cache storage proportionally.
|
|
59
|
+
|
|
60
|
+
**Structural fixes:**
|
|
61
|
+
- Use more specific cache keys to avoid storing redundant versions.
|
|
62
|
+
- Split large caches into smaller focused caches (dependencies vs. build outputs).
|
|
63
|
+
- Add a periodic workflow to prune old caches before the limit is reached.
|
|
64
|
+
- For Docker layer caches, consider using GitHub Container Registry or a dedicated
|
|
65
|
+
cache registry instead of Actions cache.
|
|
66
|
+
fix_code:
|
|
67
|
+
- language: yaml
|
|
68
|
+
label: "Check cache usage and delete stale entries in a workflow"
|
|
69
|
+
code: |
|
|
70
|
+
jobs:
|
|
71
|
+
cleanup-caches:
|
|
72
|
+
runs-on: ubuntu-latest
|
|
73
|
+
steps:
|
|
74
|
+
- name: List and clean old caches
|
|
75
|
+
env:
|
|
76
|
+
GH_TOKEN: ${{ github.token }}
|
|
77
|
+
run: |
|
|
78
|
+
# List all caches sorted by last accessed time (oldest first)
|
|
79
|
+
gh cache list \
|
|
80
|
+
--repo ${{ github.repository }} \
|
|
81
|
+
--sort last-accessed \
|
|
82
|
+
--order asc \
|
|
83
|
+
--limit 100 \
|
|
84
|
+
--json id,key,sizeInBytes,lastAccessedAt \
|
|
85
|
+
| jq -r '.[] | "\(.id)\t\(.sizeInBytes)\t\(.lastAccessedAt)\t\(.key)"'
|
|
86
|
+
- language: yaml
|
|
87
|
+
label: "Prune caches older than N days using the Actions API"
|
|
88
|
+
code: |
|
|
89
|
+
jobs:
|
|
90
|
+
prune-caches:
|
|
91
|
+
runs-on: ubuntu-latest
|
|
92
|
+
permissions:
|
|
93
|
+
actions: write
|
|
94
|
+
steps:
|
|
95
|
+
- name: Delete caches not accessed in 5 days
|
|
96
|
+
env:
|
|
97
|
+
GH_TOKEN: ${{ github.token }}
|
|
98
|
+
REPO: ${{ github.repository }}
|
|
99
|
+
run: |
|
|
100
|
+
CUTOFF=$(date -d '5 days ago' --iso-8601=seconds)
|
|
101
|
+
gh api "repos/$REPO/actions/caches" \
|
|
102
|
+
--paginate \
|
|
103
|
+
--jq ".actions_caches[] | select(.last_accessed_at < \"$CUTOFF\") | .id" \
|
|
104
|
+
| xargs -I{} gh api --method DELETE "repos/$REPO/actions/caches/{}"
|
|
105
|
+
- language: yaml
|
|
106
|
+
label: "Optimize matrix builds to share a single cache entry"
|
|
107
|
+
code: |
|
|
108
|
+
jobs:
|
|
109
|
+
build:
|
|
110
|
+
strategy:
|
|
111
|
+
matrix:
|
|
112
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
113
|
+
node: ['18', '20', '22']
|
|
114
|
+
runs-on: ${{ matrix.os }}
|
|
115
|
+
steps:
|
|
116
|
+
- uses: actions/cache@v4
|
|
117
|
+
with:
|
|
118
|
+
path: ~/.npm
|
|
119
|
+
# Share cache across Node versions — hash only package-lock.json
|
|
120
|
+
key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
|
|
121
|
+
restore-keys: npm-${{ runner.os }}-
|
|
122
|
+
prevention:
|
|
123
|
+
- "Monitor total cache usage regularly with `gh cache list --repo owner/repo` or the GitHub UI (Actions → Caches) — set up an alert when approaching 8 GB."
|
|
124
|
+
- "Add a weekly scheduled workflow that prunes caches older than 5-7 days to stay well under the 10 GB limit."
|
|
125
|
+
- "Use `actions: write` permission and the REST API to manage caches programmatically as part of your CI housekeeping."
|
|
126
|
+
- "Design cache keys to be OS-specific but NOT dependency-version-specific where possible — this reduces the number of unique cache entries stored simultaneously."
|
|
127
|
+
- "For Docker layer caches, prefer GitHub Container Registry or an external caching service to avoid eating into the 10 GB Actions cache budget."
|
|
128
|
+
- "Check for cache key patterns that change too frequently (e.g., including `github.run_id`) — these create orphaned entries that accumulate until evicted."
|
|
129
|
+
docs:
|
|
130
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy"
|
|
131
|
+
label: "GitHub Docs: Cache usage limits and eviction policy"
|
|
132
|
+
- url: "https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28"
|
|
133
|
+
label: "GitHub REST API: Actions cache endpoints"
|
|
134
|
+
- url: "https://github.com/actions/cache/blob/main/tips-and-workarounds.md"
|
|
135
|
+
label: "actions/cache: Tips and workarounds"
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
id: runner-environment-031
|
|
2
|
+
title: "Docker 29.1 + Compose 2.40.3 Runner Update Breaks Compose Commands"
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- docker
|
|
7
|
+
- docker-compose
|
|
8
|
+
- docker-29
|
|
9
|
+
- compose-v2
|
|
10
|
+
- ubuntu
|
|
11
|
+
- windows
|
|
12
|
+
- runner-image-update
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: "docker compose.*unknown flag|unknown flag.*docker compose"
|
|
15
|
+
flags: "i"
|
|
16
|
+
- regex: "docker-compose.*command not found|docker-compose.*deprecated"
|
|
17
|
+
flags: "i"
|
|
18
|
+
- regex: "compose.*unknown command|error.*compose.*not a docker command"
|
|
19
|
+
flags: "i"
|
|
20
|
+
- regex: "docker compose.*plugin.*not found|failed to get plugins"
|
|
21
|
+
flags: "i"
|
|
22
|
+
error_messages:
|
|
23
|
+
- "docker-compose: command not found"
|
|
24
|
+
- "unknown flag: --compatibility"
|
|
25
|
+
- "unknown shorthand flag: 'f' in -f"
|
|
26
|
+
- "Error response from daemon: client version 1.24 is too old. Minimum supported API version is 1.25"
|
|
27
|
+
- "'docker compose' requires at least 1 argument"
|
|
28
|
+
root_cause: |
|
|
29
|
+
On **February 9, 2026**, GitHub pushed an update to Ubuntu and Windows runner images
|
|
30
|
+
that bumped Docker Server and Client from 28.x to **29.1.*** and Docker Compose from
|
|
31
|
+
2.x to **2.40.3** (announced in actions/runner-images#13474).
|
|
32
|
+
|
|
33
|
+
For Ubuntu 24.04, the update was **rolled back** on February 20, 2026 due to multiple
|
|
34
|
+
reported issues (#13682, #13691, #13684) and is being re-evaluated (tracked in
|
|
35
|
+
#14105). The Windows runner update proceeded.
|
|
36
|
+
|
|
37
|
+
**Breaking changes in Docker Compose 2.40.x and Docker 29.x:**
|
|
38
|
+
|
|
39
|
+
1. **`docker-compose` v1 binary removed** — Many older workflows use the hyphenated
|
|
40
|
+
`docker-compose` command (Compose v1). As of Docker Compose v2, only the plugin
|
|
41
|
+
form `docker compose` (no hyphen) is installed. Workflows with
|
|
42
|
+
`run: docker-compose up -d` fail with `command not found`.
|
|
43
|
+
|
|
44
|
+
2. **`--compatibility` flag removed** — The `docker compose --compatibility` flag
|
|
45
|
+
(for mapping v2 configs to v2-compatible behavior) was removed in 2.40.x.
|
|
46
|
+
Workflows that use `docker compose --compatibility up` fail.
|
|
47
|
+
|
|
48
|
+
3. **API version minimums** — Docker 29 raises the minimum supported Docker daemon
|
|
49
|
+
API version, breaking some older base images in service containers that use the
|
|
50
|
+
Docker socket with old clients.
|
|
51
|
+
|
|
52
|
+
4. **`COMPOSE_DOCKER_CLI_BUILD` env var deprecated** — Setting
|
|
53
|
+
`COMPOSE_DOCKER_CLI_BUILD=1` no longer has any effect; BuildKit is always used.
|
|
54
|
+
|
|
55
|
+
5. **Docker 29.5 `CLONE_NEWTIME` private time namespaces** — Docker 29.5 (released
|
|
56
|
+
May 2026) enables private time namespaces by default on kernels ≥ 5.6, which
|
|
57
|
+
breaks Docker-socket-passthrough patterns used in Cloud Native Buildpacks (CNB)
|
|
58
|
+
lifecycle builds. Buildpack builds via `pack build` or Spring Boot's built-in
|
|
59
|
+
Buildpacks fail silently or with lifecycle container errors.
|
|
60
|
+
fix: |
|
|
61
|
+
**For `docker-compose` → `docker compose` migration:**
|
|
62
|
+
Replace all `docker-compose` (hyphenated) invocations with `docker compose` (space).
|
|
63
|
+
This is the most common fix.
|
|
64
|
+
|
|
65
|
+
**For `--compatibility` flag removal:**
|
|
66
|
+
Remove the `--compatibility` flag. Docker Compose v2 handles modern compose file
|
|
67
|
+
formats natively without this flag.
|
|
68
|
+
|
|
69
|
+
**For CNB/Buildpack Docker socket passthrough (Docker 29.5+):**
|
|
70
|
+
Mount the Docker socket without private time namespaces by using
|
|
71
|
+
`--security-opt=no-new-privileges:false` or by setting
|
|
72
|
+
`DOCKER_HOST` to use a sidecar daemon.
|
|
73
|
+
|
|
74
|
+
**For pinning Docker version on self-hosted runners:**
|
|
75
|
+
Pin to Docker 28.x until your Compose files and build pipelines are validated against
|
|
76
|
+
29.x.
|
|
77
|
+
fix_code:
|
|
78
|
+
- language: yaml
|
|
79
|
+
label: "Replace docker-compose (v1) with docker compose (v2 plugin)"
|
|
80
|
+
code: |
|
|
81
|
+
jobs:
|
|
82
|
+
deploy:
|
|
83
|
+
runs-on: ubuntu-latest
|
|
84
|
+
steps:
|
|
85
|
+
- uses: actions/checkout@v4
|
|
86
|
+
|
|
87
|
+
# ❌ Old (docker-compose v1 — removed)
|
|
88
|
+
# - run: docker-compose up -d
|
|
89
|
+
# - run: docker-compose --compatibility up -d
|
|
90
|
+
|
|
91
|
+
# ✅ New (docker compose v2 plugin)
|
|
92
|
+
- name: Start services
|
|
93
|
+
run: docker compose up -d
|
|
94
|
+
|
|
95
|
+
- name: Run tests
|
|
96
|
+
run: docker compose exec app npm test
|
|
97
|
+
|
|
98
|
+
- name: Tear down
|
|
99
|
+
run: docker compose down
|
|
100
|
+
- language: yaml
|
|
101
|
+
label: "Verify Docker and Compose versions in workflow"
|
|
102
|
+
code: |
|
|
103
|
+
jobs:
|
|
104
|
+
debug:
|
|
105
|
+
runs-on: ubuntu-latest
|
|
106
|
+
steps:
|
|
107
|
+
- name: Check Docker version
|
|
108
|
+
run: |
|
|
109
|
+
docker version
|
|
110
|
+
docker compose version
|
|
111
|
+
# If docker-compose (v1) is needed, install it explicitly:
|
|
112
|
+
# pip install docker-compose
|
|
113
|
+
- language: yaml
|
|
114
|
+
label: "Pin Docker version for self-hosted runners sensitive to 29.x changes"
|
|
115
|
+
code: |
|
|
116
|
+
jobs:
|
|
117
|
+
build:
|
|
118
|
+
runs-on: self-hosted
|
|
119
|
+
steps:
|
|
120
|
+
- name: Pin Docker to 28.x (if 29.x breaks your workflow)
|
|
121
|
+
run: |
|
|
122
|
+
sudo apt-get remove -y docker-ce docker-ce-cli
|
|
123
|
+
sudo apt-get install -y docker-ce=5:28.0.4-1~ubuntu.24.04~noble \
|
|
124
|
+
docker-ce-cli=5:28.0.4-1~ubuntu.24.04~noble
|
|
125
|
+
prevention:
|
|
126
|
+
- "Migrate from `docker-compose` (v1) to `docker compose` (v2 plugin) immediately —
|
|
127
|
+
v1 is no longer maintained and is removed in Docker 29.x images."
|
|
128
|
+
- "Remove `--compatibility` flags from all Compose invocations; the flag was
|
|
129
|
+
deprecated and is removed in Compose 2.40.x."
|
|
130
|
+
- "Subscribe to `actions/runner-images` announcements to get advance notice of
|
|
131
|
+
Docker version bumps before they land on hosted runners."
|
|
132
|
+
- "Pin Docker Compose file format version at `version: '3.8'` or later; v2 Compose
|
|
133
|
+
files have better compatibility with modern Compose plugin versions."
|
|
134
|
+
- "Test workflows in a local Docker 29.x environment before relying on them in CI
|
|
135
|
+
to catch API and behavioral differences early."
|
|
136
|
+
docs:
|
|
137
|
+
- url: "https://github.com/actions/runner-images/issues/13474"
|
|
138
|
+
label: "Announcement: Docker 29.1 + Compose 2.40.3 update (runner-images#13474)"
|
|
139
|
+
- url: "https://github.com/actions/runner-images/issues/14105"
|
|
140
|
+
label: "Tracking: Ubuntu Docker v29 rollback and re-attempt (runner-images#14105)"
|
|
141
|
+
- url: "https://docs.docker.com/compose/releases/migrate/"
|
|
142
|
+
label: "Docker Docs: Migrate from Compose v1 to v2"
|
|
143
|
+
- url: "https://docs.docker.com/engine/release-notes/29.1/"
|
|
144
|
+
label: "Docker Engine 29.1 release notes"
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
id: runner-environment-029
|
|
2
|
+
title: "Node.js 20 Removed from Runner Image Toolcache — Scripts Break Without setup-node"
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- node
|
|
7
|
+
- nodejs
|
|
8
|
+
- toolcache
|
|
9
|
+
- node20
|
|
10
|
+
- node22
|
|
11
|
+
- setup-node
|
|
12
|
+
- eol
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: "node.*not found|node: command not found"
|
|
15
|
+
flags: "i"
|
|
16
|
+
- regex: "node.*version.*20.*not.*available|node 20.*removed"
|
|
17
|
+
flags: "i"
|
|
18
|
+
- regex: "required node.*20|node@20.*not installed"
|
|
19
|
+
flags: "i"
|
|
20
|
+
- regex: "engines.*node.*20.*not satisfied"
|
|
21
|
+
flags: "i"
|
|
22
|
+
error_messages:
|
|
23
|
+
- "node: command not found"
|
|
24
|
+
- "The tool 'node' for version spec '20' was not found locally."
|
|
25
|
+
- "Couldn't resolve the package 'node' to a version matching '20'"
|
|
26
|
+
- "error engines: The engine \"node\" is incompatible with this module."
|
|
27
|
+
root_cause: |
|
|
28
|
+
Node.js 20 reached **end-of-life on April 30, 2026**. Starting with runner image
|
|
29
|
+
releases on **May 18, 2026** (commit 249562679f on actions/runner-images), Node.js 20
|
|
30
|
+
was removed from the pre-installed toolcache on all runner images (Ubuntu, macOS,
|
|
31
|
+
Windows).
|
|
32
|
+
|
|
33
|
+
**What changed:**
|
|
34
|
+
- The default system `node` binary on all runner images changed from Node.js **20**
|
|
35
|
+
to Node.js **22** (Maintenance LTS).
|
|
36
|
+
- `node 20` is no longer available in the toolcache — `actions/setup-node` will
|
|
37
|
+
download it from the internet if explicitly requested, or fail if the network is
|
|
38
|
+
not available (self-hosted runners with restricted network access).
|
|
39
|
+
- Workflows that use `node` without `actions/setup-node` now get Node 22 by default.
|
|
40
|
+
|
|
41
|
+
**Three distinct breakage patterns:**
|
|
42
|
+
|
|
43
|
+
1. **Shell scripts calling `node script.js`** — these now run under Node 22, which
|
|
44
|
+
may break code that relied on Node 20 behavior (e.g., `fetch` API differences,
|
|
45
|
+
removed experimental APIs, `--openssl-legacy-provider` not available by default).
|
|
46
|
+
|
|
47
|
+
2. **`actions/setup-node` without version** — previously defaulted to node-version-
|
|
48
|
+
file lookup or the installed 20.x; now defaults to the latest LTS (22.x). Any
|
|
49
|
+
`package.json` `engines` field restricting to `>=20 <21` still works, but strict
|
|
50
|
+
`20.x` pins will now cause download overhead or failure.
|
|
51
|
+
|
|
52
|
+
3. **Self-hosted runners with restricted internet access** — if a workflow requests
|
|
53
|
+
`node-version: '20'` via `actions/setup-node` and the runner has no internet
|
|
54
|
+
access to download from nodejs.org, the setup step fails because 20 is no longer
|
|
55
|
+
in the local toolcache.
|
|
56
|
+
|
|
57
|
+
Note: This is distinct from the **action runtime migration** (Node 20 → Node 24 for
|
|
58
|
+
running JavaScript actions themselves, announced separately). This entry covers the
|
|
59
|
+
*pre-installed Node.js available to shell scripts*.
|
|
60
|
+
fix: |
|
|
61
|
+
Update workflows to use Node.js 22 (current Maintenance LTS) or pin an explicit LTS
|
|
62
|
+
version via `actions/setup-node`.
|
|
63
|
+
|
|
64
|
+
**Option 1 — Explicit version pin (recommended for reproducibility):**
|
|
65
|
+
Add `actions/setup-node` with an explicit `node-version` or `node-version-file`.
|
|
66
|
+
|
|
67
|
+
**Option 2 — Use `.nvmrc` or `.node-version` file:**
|
|
68
|
+
Create a version file in the repo root and use `node-version-file` input.
|
|
69
|
+
|
|
70
|
+
**Option 3 — Accept Node 22:**
|
|
71
|
+
Test your application on Node 22 and update `package.json` `engines` accordingly.
|
|
72
|
+
|
|
73
|
+
**For self-hosted runners with no internet:**
|
|
74
|
+
Pre-install Node.js 22 in the runner's local toolcache directory and point
|
|
75
|
+
`AGENT_TOOLSDIRECTORY` to it.
|
|
76
|
+
fix_code:
|
|
77
|
+
- language: yaml
|
|
78
|
+
label: "Pin explicit Node.js version via actions/setup-node"
|
|
79
|
+
code: |
|
|
80
|
+
jobs:
|
|
81
|
+
build:
|
|
82
|
+
runs-on: ubuntu-latest
|
|
83
|
+
steps:
|
|
84
|
+
- uses: actions/checkout@v4
|
|
85
|
+
- uses: actions/setup-node@v4
|
|
86
|
+
with:
|
|
87
|
+
node-version: '22' # or '20' to keep on 20 (downloaded from web)
|
|
88
|
+
cache: 'npm'
|
|
89
|
+
- run: npm ci
|
|
90
|
+
- run: npm test
|
|
91
|
+
- language: yaml
|
|
92
|
+
label: "Use .nvmrc to declare Node version in the repo"
|
|
93
|
+
code: |
|
|
94
|
+
# .nvmrc (in repo root)
|
|
95
|
+
# 22
|
|
96
|
+
|
|
97
|
+
# workflow step
|
|
98
|
+
- uses: actions/setup-node@v4
|
|
99
|
+
with:
|
|
100
|
+
node-version-file: '.nvmrc'
|
|
101
|
+
cache: 'npm'
|
|
102
|
+
- language: yaml
|
|
103
|
+
label: "Matrix build to verify compatibility across Node versions"
|
|
104
|
+
code: |
|
|
105
|
+
jobs:
|
|
106
|
+
test:
|
|
107
|
+
strategy:
|
|
108
|
+
matrix:
|
|
109
|
+
node-version: ['20', '22', '24']
|
|
110
|
+
runs-on: ubuntu-latest
|
|
111
|
+
steps:
|
|
112
|
+
- uses: actions/checkout@v4
|
|
113
|
+
- uses: actions/setup-node@v4
|
|
114
|
+
with:
|
|
115
|
+
node-version: ${{ matrix.node-version }}
|
|
116
|
+
- run: npm ci && npm test
|
|
117
|
+
prevention:
|
|
118
|
+
- "Always use `actions/setup-node` with an explicit `node-version` or
|
|
119
|
+
`node-version-file` — never rely on the runner's pre-installed Node.js version."
|
|
120
|
+
- "Add a `.nvmrc` or `.node-version` file to your repository to pin Node.js version
|
|
121
|
+
for local dev, CI, and Vercel/Netlify deployments simultaneously."
|
|
122
|
+
- "Watch for Node.js EOL dates at https://github.com/nodejs/release#readme — plan
|
|
123
|
+
upgrades before the runner image drops the EOL version."
|
|
124
|
+
- "For self-hosted runners, maintain a local toolcache refresh process whenever a
|
|
125
|
+
new Node.js LTS is released or an old one reaches EOL."
|
|
126
|
+
docs:
|
|
127
|
+
- url: "https://github.com/actions/runner-images/issues/14029"
|
|
128
|
+
label: "Announcement: Node.js 20 removal from runner images (runner-images#14029)"
|
|
129
|
+
- url: "https://github.com/nodejs/release#readme"
|
|
130
|
+
label: "Node.js Release Schedule — EOL dates"
|
|
131
|
+
- url: "https://github.com/actions/setup-node"
|
|
132
|
+
label: "actions/setup-node — official action documentation"
|
|
133
|
+
- url: "https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/customizing-github-hosted-runners"
|
|
134
|
+
label: "GitHub Docs: Customizing GitHub-hosted runners"
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
id: runner-environment-027
|
|
2
|
+
title: "actions/setup-python cache Fails — No Dependency File Found for pip/poetry/pipenv"
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- setup-python
|
|
7
|
+
- cache
|
|
8
|
+
- pip
|
|
9
|
+
- poetry
|
|
10
|
+
- pipenv
|
|
11
|
+
- cache-dependency-path
|
|
12
|
+
- requirements.txt
|
|
13
|
+
- pyproject.toml
|
|
14
|
+
patterns:
|
|
15
|
+
- regex: "No file.*found for the supported package managers"
|
|
16
|
+
flags: "i"
|
|
17
|
+
- regex: "Error: No file in .* found for the supported package managers"
|
|
18
|
+
flags: "i"
|
|
19
|
+
- regex: "setup-python.*cache.*dependency.*not found"
|
|
20
|
+
flags: "i"
|
|
21
|
+
- regex: "dependencies were not found for the cache-dependency-path"
|
|
22
|
+
flags: "i"
|
|
23
|
+
- regex: "Could not find .* in .*requirements"
|
|
24
|
+
flags: "i"
|
|
25
|
+
error_messages:
|
|
26
|
+
- "Error: No file in /home/runner/work/my-repo/my-repo found for the supported package managers (pip, pipenv, poetry), file patterns (requirements*.txt, Pipfile.lock, poetry.lock)"
|
|
27
|
+
- "Error: No file in /home/runner/work found for the supported package managers (pip), file patterns (requirements*.txt)"
|
|
28
|
+
- "dependencies were not found for the cache-dependency-path input"
|
|
29
|
+
root_cause: |
|
|
30
|
+
When `actions/setup-python` is configured with `cache: 'pip'` (or `'poetry'` /
|
|
31
|
+
`'pipenv'`), it looks for a dependency lockfile to use as the cache key. The action
|
|
32
|
+
searches the repository for these file patterns:
|
|
33
|
+
|
|
34
|
+
| Cache type | File patterns searched |
|
|
35
|
+
|------------|---------------------------------------------------|
|
|
36
|
+
| `pip` | `requirements*.txt`, `requirements/*.txt` |
|
|
37
|
+
| `poetry` | `poetry.lock` |
|
|
38
|
+
| `pipenv` | `Pipfile.lock` |
|
|
39
|
+
|
|
40
|
+
If no matching file is found (either because the project uses a non-standard layout,
|
|
41
|
+
the file has a custom name, or the lockfile is gitignored), the action fails with this
|
|
42
|
+
error.
|
|
43
|
+
|
|
44
|
+
**Common causes:**
|
|
45
|
+
1. **Non-standard requirements file name**: `deps.txt`, `dev-requirements.txt` (outside
|
|
46
|
+
`requirements*.txt` glob), or stored in a subdirectory not matching the search path.
|
|
47
|
+
2. **pyproject.toml without poetry.lock**: Modern Python projects using `pyproject.toml`
|
|
48
|
+
with pip or flit don't generate a lockfile by default.
|
|
49
|
+
3. **Monorepo layout**: The requirements file is in a subdirectory (e.g.,
|
|
50
|
+
`backend/requirements.txt`) but the default search is from the repo root.
|
|
51
|
+
4. **Gitignored lockfiles**: `poetry.lock` or `Pipfile.lock` is in `.gitignore`, so
|
|
52
|
+
setup-python can't find it on the runner.
|
|
53
|
+
|
|
54
|
+
The `cache-dependency-path` input was added (actions/setup-python #361) to address
|
|
55
|
+
non-standard layouts, but is often overlooked in workflow templates.
|
|
56
|
+
fix: |
|
|
57
|
+
Set the `cache-dependency-path` input to point to your actual dependency file, or
|
|
58
|
+
ensure the file follows the default naming convention.
|
|
59
|
+
|
|
60
|
+
**Option 1 (preferred):** Use `cache-dependency-path` to specify the exact path or glob.
|
|
61
|
+
**Option 2:** Rename your requirements file to match the default patterns (`requirements.txt`
|
|
62
|
+
or `requirements-*.txt`).
|
|
63
|
+
**Option 3:** If you don't need caching, remove `cache:` from the setup-python step entirely.
|
|
64
|
+
**Option 4 (pyproject.toml):** If using pip with pyproject.toml, create a
|
|
65
|
+
`requirements.txt` (or use `pip-compile`) to generate a lockfile for cache keying.
|
|
66
|
+
fix_code:
|
|
67
|
+
- language: yaml
|
|
68
|
+
label: "Specify custom requirements file path with cache-dependency-path"
|
|
69
|
+
code: |
|
|
70
|
+
- uses: actions/setup-python@v5
|
|
71
|
+
with:
|
|
72
|
+
python-version: '3.12'
|
|
73
|
+
cache: 'pip'
|
|
74
|
+
cache-dependency-path: |
|
|
75
|
+
backend/requirements.txt
|
|
76
|
+
backend/requirements-dev.txt
|
|
77
|
+
- language: yaml
|
|
78
|
+
label: "Use cache-dependency-path glob for monorepo with multiple requirements files"
|
|
79
|
+
code: |
|
|
80
|
+
- uses: actions/setup-python@v5
|
|
81
|
+
with:
|
|
82
|
+
python-version: '3.12'
|
|
83
|
+
cache: 'pip'
|
|
84
|
+
cache-dependency-path: '**/requirements*.txt'
|
|
85
|
+
- language: yaml
|
|
86
|
+
label: "Poetry project with explicit cache-dependency-path"
|
|
87
|
+
code: |
|
|
88
|
+
- uses: actions/setup-python@v5
|
|
89
|
+
with:
|
|
90
|
+
python-version: '3.12'
|
|
91
|
+
cache: 'poetry'
|
|
92
|
+
cache-dependency-path: 'pyproject/poetry.lock'
|
|
93
|
+
- language: yaml
|
|
94
|
+
label: "pyproject.toml project using pip — generate a lockfile for cache keying"
|
|
95
|
+
code: |
|
|
96
|
+
- uses: actions/setup-python@v5
|
|
97
|
+
with:
|
|
98
|
+
python-version: '3.12'
|
|
99
|
+
# No cache here — use actions/cache manually with hash of pyproject.toml
|
|
100
|
+
- uses: actions/cache@v4
|
|
101
|
+
with:
|
|
102
|
+
path: ~/.cache/pip
|
|
103
|
+
key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }}
|
|
104
|
+
restore-keys: |
|
|
105
|
+
${{ runner.os }}-pip-
|
|
106
|
+
- language: yaml
|
|
107
|
+
label: "Skip caching entirely when no lockfile exists"
|
|
108
|
+
code: |
|
|
109
|
+
- uses: actions/setup-python@v5
|
|
110
|
+
with:
|
|
111
|
+
python-version: '3.12'
|
|
112
|
+
# Omit 'cache:' entirely — no caching, no failure
|
|
113
|
+
- run: pip install -r deps.txt
|
|
114
|
+
prevention:
|
|
115
|
+
- "Always set `cache-dependency-path` explicitly rather than relying on the default file search — it makes the workflow self-documenting and prevents surprises on rename."
|
|
116
|
+
- "Commit `poetry.lock` and `Pipfile.lock` to version control — these files serve as both the reproducible install spec and the cache key."
|
|
117
|
+
- "In monorepos, use a glob pattern like `**/requirements*.txt` to match files across subdirectories."
|
|
118
|
+
- "If pyproject.toml is your only dependency file, use `actions/cache@v4` directly with `hashFiles('pyproject.toml')` instead of setup-python's built-in cache."
|
|
119
|
+
- "Pin to `actions/setup-python@v5` or later — older versions have different cache file discovery behavior."
|
|
120
|
+
docs:
|
|
121
|
+
- url: "https://github.com/actions/setup-python?tab=readme-ov-file#caching-packages-dependencies"
|
|
122
|
+
label: "actions/setup-python: Caching packages dependencies"
|
|
123
|
+
- url: "https://github.com/actions/setup-python/issues/361"
|
|
124
|
+
label: "actions/setup-python #361: Support cache-dependency-paths outside the current directory"
|
|
125
|
+
- url: "https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows"
|
|
126
|
+
label: "GitHub Docs: Caching dependencies to speed up workflows"
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
id: runner-environment-030
|
|
2
|
+
title: "Ubuntu ARM64 Runner Missing Docker — docker: command not found on arm64"
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- arm64
|
|
7
|
+
- aarch64
|
|
8
|
+
- docker
|
|
9
|
+
- ubuntu
|
|
10
|
+
- partner-runner
|
|
11
|
+
- docker-buildx
|
|
12
|
+
- setup-buildx-action
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: "docker.*command not found|docker.*not found.*arm64"
|
|
15
|
+
flags: "i"
|
|
16
|
+
- regex: "docker/setup-buildx-action.*error|setup-buildx.*arm64.*fail"
|
|
17
|
+
flags: "i"
|
|
18
|
+
- regex: "Cannot connect to the Docker daemon|Is the docker daemon running"
|
|
19
|
+
flags: "i"
|
|
20
|
+
- regex: "Error: Unable to locate executable file: docker"
|
|
21
|
+
flags: "i"
|
|
22
|
+
error_messages:
|
|
23
|
+
- "docker: command not found"
|
|
24
|
+
- "Error: Unable to locate executable file: docker"
|
|
25
|
+
- "Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?"
|
|
26
|
+
- "exec: \"docker\": executable file not found in $PATH"
|
|
27
|
+
root_cause: |
|
|
28
|
+
GitHub-hosted **Ubuntu 24.04 ARM64** runner images (available via labels such as
|
|
29
|
+
`ubuntu-24.04-arm64`, `ubuntu-arm`, or partner runner images for ARM64) do **not**
|
|
30
|
+
have Docker pre-installed on `PATH`, despite the partner image README listing Docker
|
|
31
|
+
client and server versions.
|
|
32
|
+
|
|
33
|
+
This is a **documentation mismatch** affecting ARM64 runner users (actions/runner-
|
|
34
|
+
images#14051, created March 2026, still open as of May 2026):
|
|
35
|
+
- The `partner-runner-images` README lists Docker Client 28.0.4 and Docker Server
|
|
36
|
+
28.0.4 as installed software.
|
|
37
|
+
- In practice, `docker` is **not present on `PATH`** in these runners.
|
|
38
|
+
- The runner is identified as `Source: Partner` and `Base Image for Ubuntu Server
|
|
39
|
+
24.04`.
|
|
40
|
+
|
|
41
|
+
**Affected workflows:**
|
|
42
|
+
- Any step using `docker build`, `docker run`, `docker pull`, or `docker push`
|
|
43
|
+
directly in a `run:` block.
|
|
44
|
+
- `docker/setup-buildx-action@v3` fails because it cannot find the Docker CLI.
|
|
45
|
+
- Container-based jobs that use the host Docker socket.
|
|
46
|
+
- Multi-platform builds that need BuildKit on ARM64.
|
|
47
|
+
|
|
48
|
+
**x86-64 runners are not affected.** This is specific to ARM64 GitHub-hosted
|
|
49
|
+
runners using the partner image.
|
|
50
|
+
|
|
51
|
+
This is distinct from the `docker-buildx-not-setup.yml` entry (which covers x64
|
|
52
|
+
runners where Docker BuildKit is present but `buildx` is not configured).
|
|
53
|
+
fix: |
|
|
54
|
+
Install Docker explicitly at the start of ARM64 workflow jobs, or use a Docker
|
|
55
|
+
action that handles installation automatically.
|
|
56
|
+
|
|
57
|
+
**Option 1 — Install Docker via the official convenience script (fastest):**
|
|
58
|
+
Run the Docker install script at the start of the job. This adds ~60 seconds to
|
|
59
|
+
job start time but ensures Docker is available.
|
|
60
|
+
|
|
61
|
+
**Option 2 — Use `docker/setup-buildx-action@v3` after Docker install:**
|
|
62
|
+
After installing Docker, `setup-buildx-action` can then install BuildKit buildx.
|
|
63
|
+
|
|
64
|
+
**Option 3 — Use a Docker-pre-installed large runner:**
|
|
65
|
+
If budget allows, use GitHub's x86-64 larger runners which have Docker pre-installed,
|
|
66
|
+
or a self-hosted ARM64 runner with Docker pre-configured.
|
|
67
|
+
|
|
68
|
+
**Option 4 — Use `runs-on: ubuntu-latest` (x86-64) instead of ARM64:**
|
|
69
|
+
If ARM64 is not strictly required, run on x86-64 which has Docker pre-installed.
|
|
70
|
+
fix_code:
|
|
71
|
+
- language: yaml
|
|
72
|
+
label: "Install Docker on ARM64 runner before using it"
|
|
73
|
+
code: |
|
|
74
|
+
jobs:
|
|
75
|
+
build:
|
|
76
|
+
runs-on: ubuntu-24.04-arm64
|
|
77
|
+
steps:
|
|
78
|
+
- uses: actions/checkout@v4
|
|
79
|
+
|
|
80
|
+
- name: Install Docker
|
|
81
|
+
run: |
|
|
82
|
+
curl -fsSL https://get.docker.com -o get-docker.sh
|
|
83
|
+
sudo sh get-docker.sh
|
|
84
|
+
sudo usermod -aG docker $USER
|
|
85
|
+
sudo systemctl start docker
|
|
86
|
+
docker --version
|
|
87
|
+
|
|
88
|
+
- name: Set up Docker Buildx
|
|
89
|
+
uses: docker/setup-buildx-action@v3
|
|
90
|
+
|
|
91
|
+
- name: Build image
|
|
92
|
+
run: docker build -t myapp:latest .
|
|
93
|
+
- language: yaml
|
|
94
|
+
label: "Cross-platform build with explicit ARM64 Docker install"
|
|
95
|
+
code: |
|
|
96
|
+
jobs:
|
|
97
|
+
build:
|
|
98
|
+
strategy:
|
|
99
|
+
matrix:
|
|
100
|
+
include:
|
|
101
|
+
- runner: ubuntu-latest
|
|
102
|
+
platform: linux/amd64
|
|
103
|
+
- runner: ubuntu-24.04-arm64
|
|
104
|
+
platform: linux/arm64
|
|
105
|
+
install_docker: true
|
|
106
|
+
runs-on: ${{ matrix.runner }}
|
|
107
|
+
steps:
|
|
108
|
+
- uses: actions/checkout@v4
|
|
109
|
+
|
|
110
|
+
- name: Install Docker (ARM64 only)
|
|
111
|
+
if: matrix.install_docker == true
|
|
112
|
+
run: |
|
|
113
|
+
curl -fsSL https://get.docker.com | sudo sh
|
|
114
|
+
sudo usermod -aG docker $USER
|
|
115
|
+
sudo systemctl enable --now docker
|
|
116
|
+
|
|
117
|
+
- name: Build for ${{ matrix.platform }}
|
|
118
|
+
run: docker build --platform ${{ matrix.platform }} -t myapp .
|
|
119
|
+
prevention:
|
|
120
|
+
- "Before adding `runs-on: ubuntu-24.04-arm64` to a workflow that uses Docker,
|
|
121
|
+
verify Docker availability by running `docker --version` in a test job."
|
|
122
|
+
- "Check the current partner runner image README at
|
|
123
|
+
https://github.com/actions/partner-runner-images before relying on pre-installed
|
|
124
|
+
tooling on non-standard runner images."
|
|
125
|
+
- "Consider using self-hosted ARM64 runners with Docker pre-configured for
|
|
126
|
+
production workloads that depend on Docker on ARM64."
|
|
127
|
+
- "Track the open issue (actions/runner-images#14051) for when GitHub adds Docker
|
|
128
|
+
to ARM64 partner images natively."
|
|
129
|
+
docs:
|
|
130
|
+
- url: "https://github.com/actions/runner-images/issues/14051"
|
|
131
|
+
label: "Issue: Ubuntu 24.04 ARM64 missing Docker (runner-images#14051)"
|
|
132
|
+
- url: "https://github.com/actions/partner-runner-images"
|
|
133
|
+
label: "actions/partner-runner-images — partner runner image definitions"
|
|
134
|
+
- url: "https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories"
|
|
135
|
+
label: "GitHub Docs: GitHub-hosted runner specifications"
|
|
136
|
+
- url: "https://docs.docker.com/engine/install/ubuntu/"
|
|
137
|
+
label: "Docker Docs: Install Docker Engine on Ubuntu"
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
id: runner-environment-028
|
|
2
|
+
title: "windows-2019 Runner Retired — Jobs Fail with No Runner Found"
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- windows
|
|
7
|
+
- windows-2019
|
|
8
|
+
- runner-retirement
|
|
9
|
+
- deprecation
|
|
10
|
+
- runs-on
|
|
11
|
+
- migration
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: "No runner matching the requested labels.*windows-2019"
|
|
14
|
+
flags: "i"
|
|
15
|
+
- regex: "Could not find any runner matching.*windows-2019"
|
|
16
|
+
flags: "i"
|
|
17
|
+
- regex: "windows-2019.*is no longer supported"
|
|
18
|
+
flags: "i"
|
|
19
|
+
- regex: "windows-2019.*deprecated.*unsupported"
|
|
20
|
+
flags: "i"
|
|
21
|
+
error_messages:
|
|
22
|
+
- "No runner matching the requested labels was found: windows-2019"
|
|
23
|
+
- "Could not find any runner matching the requested labels: [windows-2019]"
|
|
24
|
+
- "This request was automatically failed because 'windows-2019' is no longer available."
|
|
25
|
+
root_cause: |
|
|
26
|
+
GitHub retired the `windows-2019` runner image on **June 30, 2025** following the
|
|
27
|
+
GitHub Actions N-1 OS support policy (only the latest two major versions of each OS
|
|
28
|
+
are hosted).
|
|
29
|
+
|
|
30
|
+
**Timeline:**
|
|
31
|
+
- **2025-04-15**: Deprecation announcement (actions/runner-images#12045)
|
|
32
|
+
- **2025-06-01**: Deprecation begins — longer queue times during peak hours
|
|
33
|
+
- **Between June 1–30**: GitHub temporarily fails jobs using `windows-2019` to raise
|
|
34
|
+
awareness in advance of the hard removal
|
|
35
|
+
- **2025-06-30**: `windows-2019` fully unsupported — all jobs using this label fail
|
|
36
|
+
|
|
37
|
+
Workflows that explicitly specify `runs-on: windows-2019` (or any combination like
|
|
38
|
+
`[self-hosted, windows-2019]` on non-self-hosted runners) will fail immediately after
|
|
39
|
+
the retirement date. Workflows that used `windows-latest` were not affected since
|
|
40
|
+
`windows-latest` already pointed to `windows-2022`.
|
|
41
|
+
|
|
42
|
+
The replacement is `windows-2022` (already the current `windows-latest` at time of
|
|
43
|
+
retirement) or `windows-2025` (Windows Server 2025 image).
|
|
44
|
+
fix: |
|
|
45
|
+
Update all `runs-on` references from `windows-2019` to `windows-2022` or
|
|
46
|
+
`windows-2025` (or use `windows-latest`).
|
|
47
|
+
|
|
48
|
+
**Migration path:**
|
|
49
|
+
- `windows-2019` → `windows-2022` (minimal change, widely compatible)
|
|
50
|
+
- `windows-2019` → `windows-2025` (latest; check for VS 2026 path changes if using
|
|
51
|
+
hardcoded MSVC paths)
|
|
52
|
+
- `windows-2019` → `windows-latest` (tracks latest, reduces future manual migrations)
|
|
53
|
+
|
|
54
|
+
**Before migrating**, verify that your workflow does not depend on Windows Server 2019
|
|
55
|
+
-specific behavior such as:
|
|
56
|
+
- VS 2019 toolchain at `C:\Program Files (x86)\Microsoft Visual Studio\2019\`
|
|
57
|
+
- Older .NET Framework SDK versions not present on 2022 or 2025 images
|
|
58
|
+
- Windows Server 2019-specific APIs or registry keys
|
|
59
|
+
fix_code:
|
|
60
|
+
- language: yaml
|
|
61
|
+
label: "Replace windows-2019 with windows-2022"
|
|
62
|
+
code: |
|
|
63
|
+
jobs:
|
|
64
|
+
build:
|
|
65
|
+
# Before: runs-on: windows-2019
|
|
66
|
+
runs-on: windows-2022
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v4
|
|
69
|
+
- name: Build
|
|
70
|
+
run: msbuild MyApp.sln /p:Configuration=Release
|
|
71
|
+
- language: yaml
|
|
72
|
+
label: "Use windows-latest to avoid future manual migrations"
|
|
73
|
+
code: |
|
|
74
|
+
jobs:
|
|
75
|
+
build:
|
|
76
|
+
# windows-latest currently points to windows-2025 (as of June 2026)
|
|
77
|
+
runs-on: windows-latest
|
|
78
|
+
steps:
|
|
79
|
+
- uses: actions/checkout@v4
|
|
80
|
+
- language: bash
|
|
81
|
+
label: "Audit all workflows for windows-2019 references"
|
|
82
|
+
code: |
|
|
83
|
+
# Find all workflow files using windows-2019
|
|
84
|
+
grep -r "windows-2019" .github/workflows/
|
|
85
|
+
prevention:
|
|
86
|
+
- "Use `windows-latest` instead of pinned OS versions unless you have a specific
|
|
87
|
+
reason to pin. This avoids retirement failures entirely."
|
|
88
|
+
- "Subscribe to the `actions/runner-images` repository announcements to receive
|
|
89
|
+
deprecation notices before they become hard failures."
|
|
90
|
+
- "When you must pin an OS version, add a calendar reminder or Renovate/Dependabot
|
|
91
|
+
rule to review the pin when the N-1 policy applies."
|
|
92
|
+
- "Run a periodic repository search for retired runner labels:
|
|
93
|
+
`grep -r 'windows-2019\\|ubuntu-20.04\\|macos-12' .github/workflows/`"
|
|
94
|
+
docs:
|
|
95
|
+
- url: "https://github.com/actions/runner-images/issues/12045"
|
|
96
|
+
label: "Announcement: Windows 2019 deprecation and retirement (runner-images#12045)"
|
|
97
|
+
- url: "https://github.blog/changelog/2025-04-15-upcoming-breaking-changes-and-releases-for-github-actions/"
|
|
98
|
+
label: "GitHub Changelog: Windows Server 2019 is closing down"
|
|
99
|
+
- url: "https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources"
|
|
100
|
+
label: "GitHub Docs: Supported GitHub-hosted runners"
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
id: triggers-007
|
|
2
|
+
title: "merge_group Trigger Missing — Required Checks Never Run in Merge Queue"
|
|
3
|
+
category: triggers
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- merge_group
|
|
7
|
+
- merge-queue
|
|
8
|
+
- required-checks
|
|
9
|
+
- branch-protection
|
|
10
|
+
- triggers
|
|
11
|
+
- pull_request
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: "merge_group"
|
|
14
|
+
flags: "i"
|
|
15
|
+
- regex: "Expected.*Waiting.*merge queue"
|
|
16
|
+
flags: "i"
|
|
17
|
+
- regex: "merge queue.*required.*status check.*waiting"
|
|
18
|
+
flags: "i"
|
|
19
|
+
error_messages:
|
|
20
|
+
- "Required check 'CI' is expected — Waiting"
|
|
21
|
+
- "All checks have passed except those that are waiting for merge queue"
|
|
22
|
+
- "The merge queue is waiting for the required check to pass"
|
|
23
|
+
root_cause: |
|
|
24
|
+
GitHub's merge queue (enabled via branch protection rules → "Require merge queue")
|
|
25
|
+
creates a `merge_group` event when a PR is added to the queue. This event is distinct
|
|
26
|
+
from `pull_request` and `push` — a workflow must explicitly declare `on: merge_group:`
|
|
27
|
+
to receive it.
|
|
28
|
+
|
|
29
|
+
When a workflow is required by branch protection but does NOT include `merge_group`
|
|
30
|
+
as a trigger, the merge queue adds the PR to a temporary merge group branch (format:
|
|
31
|
+
`gh-readonly-queue/{base}/{pr-number}`) but the required workflow **never starts**.
|
|
32
|
+
GitHub shows the required check as "Expected — Waiting" indefinitely, and the PR
|
|
33
|
+
cannot merge.
|
|
34
|
+
|
|
35
|
+
**Why this is subtle:**
|
|
36
|
+
- The workflow runs fine for normal `pull_request` events (dev branch → PR, all checks
|
|
37
|
+
pass).
|
|
38
|
+
- The failure only manifests once the PR is actually added to the merge queue.
|
|
39
|
+
- The "Waiting" status in the merge queue looks different from a failed check, making
|
|
40
|
+
it unclear that the workflow trigger is misconfigured.
|
|
41
|
+
|
|
42
|
+
**The merge_group event payload** is slightly different from `pull_request`:
|
|
43
|
+
- `github.event.merge_group.base_ref` — the base branch
|
|
44
|
+
- `github.event.merge_group.head_sha` — the merged commit SHA to test
|
|
45
|
+
- `github.event.merge_group.head_ref` — the temporary merge branch name
|
|
46
|
+
fix: |
|
|
47
|
+
Add `merge_group:` to the `on:` block of every workflow that is listed as a required
|
|
48
|
+
status check for merge queue-protected branches.
|
|
49
|
+
|
|
50
|
+
**Important:** `merge_group` does NOT automatically run `pull_request` workflows — it
|
|
51
|
+
is a completely separate event type. You must add it explicitly.
|
|
52
|
+
|
|
53
|
+
If your workflow has conditions that reference `github.event_name == 'pull_request'`,
|
|
54
|
+
update those conditions to also allow `merge_group` events, or restructure them to
|
|
55
|
+
check `github.event.pull_request || github.event.merge_group`.
|
|
56
|
+
fix_code:
|
|
57
|
+
- language: yaml
|
|
58
|
+
label: "Add merge_group trigger to an existing CI workflow"
|
|
59
|
+
code: |
|
|
60
|
+
on:
|
|
61
|
+
pull_request:
|
|
62
|
+
branches: [main, develop]
|
|
63
|
+
merge_group: # <-- Add this to receive merge queue events
|
|
64
|
+
types: [checks_requested]
|
|
65
|
+
|
|
66
|
+
jobs:
|
|
67
|
+
ci:
|
|
68
|
+
runs-on: ubuntu-latest
|
|
69
|
+
steps:
|
|
70
|
+
- uses: actions/checkout@v4
|
|
71
|
+
- name: Run tests
|
|
72
|
+
run: npm test
|
|
73
|
+
- language: yaml
|
|
74
|
+
label: "Conditional logic that handles both pull_request and merge_group"
|
|
75
|
+
code: |
|
|
76
|
+
on:
|
|
77
|
+
pull_request:
|
|
78
|
+
merge_group:
|
|
79
|
+
types: [checks_requested]
|
|
80
|
+
|
|
81
|
+
jobs:
|
|
82
|
+
ci:
|
|
83
|
+
runs-on: ubuntu-latest
|
|
84
|
+
steps:
|
|
85
|
+
- uses: actions/checkout@v4
|
|
86
|
+
|
|
87
|
+
# Access the base SHA correctly for both event types
|
|
88
|
+
- name: Get base SHA
|
|
89
|
+
id: base
|
|
90
|
+
run: |
|
|
91
|
+
if [ "${{ github.event_name }}" = "merge_group" ]; then
|
|
92
|
+
echo "sha=${{ github.event.merge_group.base_sha }}" >> $GITHUB_OUTPUT
|
|
93
|
+
else
|
|
94
|
+
echo "sha=${{ github.event.pull_request.base.sha }}" >> $GITHUB_OUTPUT
|
|
95
|
+
fi
|
|
96
|
+
- language: yaml
|
|
97
|
+
label: "Reusable workflow that supports merge_group via workflow_call"
|
|
98
|
+
code: |
|
|
99
|
+
# In the caller workflow:
|
|
100
|
+
on:
|
|
101
|
+
pull_request:
|
|
102
|
+
merge_group:
|
|
103
|
+
types: [checks_requested]
|
|
104
|
+
|
|
105
|
+
jobs:
|
|
106
|
+
ci:
|
|
107
|
+
uses: ./.github/workflows/ci-reusable.yml
|
|
108
|
+
with:
|
|
109
|
+
ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }}
|
|
110
|
+
prevention:
|
|
111
|
+
- "When enabling merge queue on a branch protection rule, immediately check that every required workflow has `merge_group` in its `on:` triggers."
|
|
112
|
+
- "Add a repository-level workflow audit that lists all required status checks and verifies each has a matching `merge_group` trigger."
|
|
113
|
+
- "Test the merge queue setup by creating a test PR and attempting to add it to the queue — if checks show 'Waiting', add the trigger."
|
|
114
|
+
- "Third-party Actions and path-filter actions (dorny/paths-filter, tj-actions/changed-files) may need explicit `merge_group` support — check their changelogs."
|
|
115
|
+
- "GitHub's documentation now includes a merge queue section — review it when enabling the feature in your organization."
|
|
116
|
+
docs:
|
|
117
|
+
- url: "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue"
|
|
118
|
+
label: "GitHub Docs: Managing a merge queue"
|
|
119
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#merge_group"
|
|
120
|
+
label: "GitHub Actions: merge_group event trigger"
|
|
121
|
+
- url: "https://github.blog/changelog/2023-02-08-pull-request-merge-queue-public-beta/"
|
|
122
|
+
label: "GitHub Changelog: Pull request merge queue public beta (Feb 2023)"
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
id: yaml-syntax-015
|
|
2
|
+
title: "Deprecated ::set-output:: / ::save-state:: / ::add-path:: Workflow Commands"
|
|
3
|
+
category: yaml-syntax
|
|
4
|
+
severity: warning
|
|
5
|
+
tags:
|
|
6
|
+
- set-output
|
|
7
|
+
- save-state
|
|
8
|
+
- add-path
|
|
9
|
+
- deprecated
|
|
10
|
+
- GITHUB_OUTPUT
|
|
11
|
+
- GITHUB_ENV
|
|
12
|
+
- GITHUB_PATH
|
|
13
|
+
- workflow-commands
|
|
14
|
+
patterns:
|
|
15
|
+
- regex: "The `set-output` command is deprecated"
|
|
16
|
+
flags: "i"
|
|
17
|
+
- regex: "The `save-state` command is deprecated"
|
|
18
|
+
flags: "i"
|
|
19
|
+
- regex: "The `set-env` command is disabled"
|
|
20
|
+
flags: "i"
|
|
21
|
+
- regex: "::set-output name="
|
|
22
|
+
flags: ""
|
|
23
|
+
- regex: "::save-state name="
|
|
24
|
+
flags: ""
|
|
25
|
+
- regex: "::add-path::"
|
|
26
|
+
flags: ""
|
|
27
|
+
- regex: "workflow commands.*deprecated.*will be disabled"
|
|
28
|
+
flags: "i"
|
|
29
|
+
error_messages:
|
|
30
|
+
- "Warning: The `set-output` command is deprecated and will be disabled soon. Please upgrade to using Environment Files. For more information see: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter"
|
|
31
|
+
- "Warning: The `save-state` command is deprecated and will be disabled soon. Please upgrade to using Environment Files."
|
|
32
|
+
- "Error: The `set-env` command is disabled. Please upgrade to using Environment Files."
|
|
33
|
+
- "Error: The `add-path` command is disabled. Please upgrade to using Environment Files."
|
|
34
|
+
root_cause: |
|
|
35
|
+
GitHub Actions introduced a new Environment Files mechanism in 2020 to replace the
|
|
36
|
+
older `echo "::command::"` workflow commands. The old commands were deprecated in
|
|
37
|
+
October 2022 (security advisory: injection attacks could hijack `::set-output::` via
|
|
38
|
+
untrusted log output) and disabled shortly after.
|
|
39
|
+
|
|
40
|
+
**Deprecated commands and their replacements:**
|
|
41
|
+
| Old command | Replacement |
|
|
42
|
+
|-------------------------------------|------------------------------------------------|
|
|
43
|
+
| `echo "::set-output name=K::V"` | `echo "K=V" >> $GITHUB_OUTPUT` |
|
|
44
|
+
| `echo "::save-state name=K::V"` | `echo "K=V" >> $GITHUB_STATE` |
|
|
45
|
+
| `echo "::set-env name=K::V"` | `echo "K=V" >> $GITHUB_ENV` |
|
|
46
|
+
| `echo "::add-path::PATH"` | `echo "PATH" >> $GITHUB_PATH` |
|
|
47
|
+
|
|
48
|
+
These commands still appear in:
|
|
49
|
+
- Third-party GitHub Actions that haven't been updated to a newer major version
|
|
50
|
+
- Scripts copied from old Stack Overflow answers or blog posts
|
|
51
|
+
- Custom scripts that use the `::set-output::` form directly
|
|
52
|
+
- Older composite actions where steps use `echo "::set-output name=result::$value"`
|
|
53
|
+
|
|
54
|
+
When the runner encounters these commands, it emits a deprecation warning. If the
|
|
55
|
+
commands are later hard-disabled for a repository (or for a specific runner version),
|
|
56
|
+
the output variable is simply never set — creating a silent downstream failure.
|
|
57
|
+
fix: |
|
|
58
|
+
Replace all deprecated `::command::` syntax with the Environment Files equivalents
|
|
59
|
+
in your workflow YAML, composite action scripts, and any shell scripts that produce
|
|
60
|
+
outputs or modify the environment.
|
|
61
|
+
|
|
62
|
+
**Key rules:**
|
|
63
|
+
- `GITHUB_OUTPUT`, `GITHUB_ENV`, `GITHUB_STATE`, `GITHUB_PATH` are all file paths
|
|
64
|
+
that are set as environment variables by the runner.
|
|
65
|
+
- Append to these files — never overwrite them (`>>` not `>`).
|
|
66
|
+
- For multiline values, use the heredoc delimiter syntax (see fix_code below).
|
|
67
|
+
- On Windows (PowerShell), use `"K=V" | Out-File -FilePath $env:GITHUB_OUTPUT -Append`
|
|
68
|
+
or simply `echo "K=V" >> $env:GITHUB_OUTPUT` (cmd-style append works in pwsh too).
|
|
69
|
+
fix_code:
|
|
70
|
+
- language: yaml
|
|
71
|
+
label: "Replace ::set-output:: with GITHUB_OUTPUT (bash)"
|
|
72
|
+
code: |
|
|
73
|
+
- name: Set output (modern)
|
|
74
|
+
id: my-step
|
|
75
|
+
run: |
|
|
76
|
+
# Old (deprecated):
|
|
77
|
+
# echo "::set-output name=version::1.2.3"
|
|
78
|
+
|
|
79
|
+
# New (use environment file):
|
|
80
|
+
echo "version=1.2.3" >> $GITHUB_OUTPUT
|
|
81
|
+
|
|
82
|
+
- name: Use output downstream
|
|
83
|
+
run: echo "Version is ${{ steps.my-step.outputs.version }}"
|
|
84
|
+
- language: yaml
|
|
85
|
+
label: "Replace ::set-output:: with GITHUB_OUTPUT (PowerShell)"
|
|
86
|
+
code: |
|
|
87
|
+
- name: Set output (PowerShell modern)
|
|
88
|
+
id: my-step
|
|
89
|
+
shell: pwsh
|
|
90
|
+
run: |
|
|
91
|
+
# Old (deprecated):
|
|
92
|
+
# Write-Output "::set-output name=version::1.2.3"
|
|
93
|
+
|
|
94
|
+
# New:
|
|
95
|
+
"version=1.2.3" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
|
|
96
|
+
- language: yaml
|
|
97
|
+
label: "Replace ::save-state:: with GITHUB_STATE"
|
|
98
|
+
code: |
|
|
99
|
+
- name: Save state in pre step
|
|
100
|
+
run: echo "cleanup_token=${{ secrets.TOKEN }}" >> $GITHUB_STATE
|
|
101
|
+
|
|
102
|
+
- name: Read state in post step
|
|
103
|
+
run: echo "Token was $STATE_CLEANUP_TOKEN"
|
|
104
|
+
# State values are exposed as STATE_<NAME> environment variables
|
|
105
|
+
- language: yaml
|
|
106
|
+
label: "Multiline output value with heredoc delimiter"
|
|
107
|
+
code: |
|
|
108
|
+
- name: Set multiline output
|
|
109
|
+
id: changelog
|
|
110
|
+
run: |
|
|
111
|
+
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
|
|
112
|
+
echo "notes<<$EOF" >> $GITHUB_OUTPUT
|
|
113
|
+
echo "Line 1 of release notes" >> $GITHUB_OUTPUT
|
|
114
|
+
echo "Line 2 of release notes" >> $GITHUB_OUTPUT
|
|
115
|
+
echo "$EOF" >> $GITHUB_OUTPUT
|
|
116
|
+
prevention:
|
|
117
|
+
- "Audit all workflows and composite actions for `::set-output::`, `::save-state::`, `::set-env::`, and `::add-path::` patterns before they become hard failures."
|
|
118
|
+
- "Add a CI lint step using `grep -r '::set-output' .github/` to catch regressions."
|
|
119
|
+
- "When using third-party Actions, pin to a version tag that uses the modern file-based outputs — check the action's CHANGELOG for 'GITHUB_OUTPUT migration'."
|
|
120
|
+
- "For cross-platform workflows, test the `$GITHUB_OUTPUT` / `$env:GITHUB_OUTPUT` equivalence — both work on ubuntu/macos/windows runners."
|
|
121
|
+
- "Enable the 'Deprecation warnings as errors' setting in your organization's Actions policy to catch deprecated commands in CI before they silently fail."
|
|
122
|
+
docs:
|
|
123
|
+
- url: "https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter"
|
|
124
|
+
label: "GitHub Actions: Setting an output parameter (Environment Files)"
|
|
125
|
+
- url: "https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/"
|
|
126
|
+
label: "GitHub Changelog: Deprecating save-state and set-output commands (Oct 2022)"
|
|
127
|
+
- url: "https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/"
|
|
128
|
+
label: "GitHub Changelog: Deprecating set-env and add-path commands (Oct 2020)"
|
|
129
|
+
- url: "https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#understanding-the-risk-of-script-injections"
|
|
130
|
+
label: "Security hardening: Understanding the risk of script injections"
|
package/package.json
CHANGED