@htekdev/actions-debugger 1.0.77 → 1.0.79
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/merge-queue-branch-cache-isolation.yml +80 -0
- package/errors/concurrency-timing/rerun-cancel-original-missing-run-attempt.yml +67 -0
- package/errors/runner-environment/macos-15-python-command-not-found.yml +103 -0
- package/errors/runner-environment/ubuntu-24-mysql-84-native-password-removed.yml +104 -0
- package/errors/runner-environment/ubuntu-24-pip-externally-managed-environment.yml +90 -0
- package/errors/runner-environment/ubuntu-snap-not-available-no-systemd.yml +92 -0
- package/errors/silent-failures/fromjson-object-stored-in-env-stringifies.yml +77 -0
- package/errors/triggers/event-types-unknown-value-silently-ignored.yml +89 -0
- package/package.json +1 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
id: caching-artifacts-045
|
|
2
|
+
title: "Merge queue (merge_group) runs cannot restore cache saved by pull_request runs"
|
|
3
|
+
category: caching-artifacts
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- merge-queue
|
|
7
|
+
- merge_group
|
|
8
|
+
- cache-isolation
|
|
9
|
+
- branch-scoping
|
|
10
|
+
- cache-miss
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'Cache not found for input keys'
|
|
13
|
+
flags: i
|
|
14
|
+
- regex: 'gh-readonly-queue'
|
|
15
|
+
flags: i
|
|
16
|
+
error_messages:
|
|
17
|
+
- "Cache not found for input keys:"
|
|
18
|
+
- "No cache found for key: Linux-node-"
|
|
19
|
+
root_cause: |
|
|
20
|
+
GitHub Actions caches are branch-scoped. When the merge_group trigger fires,
|
|
21
|
+
GitHub creates a temporary branch named
|
|
22
|
+
gh-readonly-queue/main/pr-<number>-<sha> with a fresh merge commit. This
|
|
23
|
+
temporary branch has no prior cache entries, so every cache lookup is a cache
|
|
24
|
+
miss — even if the identical hashFiles() key was successfully saved during the
|
|
25
|
+
preceding pull_request run on the feature branch.
|
|
26
|
+
|
|
27
|
+
Branch-scoped cache fallback rules allow access to the base branch (e.g., main)
|
|
28
|
+
but NOT to arbitrary feature branches. The gh-readonly-queue/* branch is treated
|
|
29
|
+
as a new branch with no cache history and no access to feature-branch caches.
|
|
30
|
+
Only caches saved directly to main (or the configured merge target) are accessible
|
|
31
|
+
in merge queue runs.
|
|
32
|
+
|
|
33
|
+
The result: CI times effectively double. The pull_request run warms the cache
|
|
34
|
+
but the merge queue run cannot use it and must rebuild from scratch.
|
|
35
|
+
fix: |
|
|
36
|
+
Seed caches on the base branch via push-triggered or scheduled workflows so
|
|
37
|
+
merge queue runs can restore from main's cache. Use restore-keys with a
|
|
38
|
+
branch-agnostic prefix to maximize fallback hit rate.
|
|
39
|
+
fix_code:
|
|
40
|
+
- language: yaml
|
|
41
|
+
label: "Use restore-keys for base branch fallback"
|
|
42
|
+
code: |
|
|
43
|
+
- name: Cache dependencies
|
|
44
|
+
uses: actions/cache@v4
|
|
45
|
+
with:
|
|
46
|
+
path: ~/.npm
|
|
47
|
+
# Exact key includes lock file hash — works for push/PR
|
|
48
|
+
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
|
49
|
+
# restore-keys fall back to base branch cache (accessible in merge_group)
|
|
50
|
+
restore-keys: |
|
|
51
|
+
${{ runner.os }}-node-
|
|
52
|
+
|
|
53
|
+
- language: yaml
|
|
54
|
+
label: "Seed base branch cache via push workflow"
|
|
55
|
+
code: |
|
|
56
|
+
# Separate workflow to warm cache on main after every merge
|
|
57
|
+
on:
|
|
58
|
+
push:
|
|
59
|
+
branches: [main]
|
|
60
|
+
|
|
61
|
+
jobs:
|
|
62
|
+
warm-cache:
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
steps:
|
|
65
|
+
- uses: actions/checkout@v4
|
|
66
|
+
- uses: actions/setup-node@v4
|
|
67
|
+
with:
|
|
68
|
+
node-version: '20'
|
|
69
|
+
cache: npm
|
|
70
|
+
- run: npm ci
|
|
71
|
+
prevention:
|
|
72
|
+
- "Seed caches on your base branch (main) so merge queue runs can restore from it."
|
|
73
|
+
- "Use branch-agnostic restore-keys prefixes — they survive the gh-readonly-queue/* branch context."
|
|
74
|
+
- "Avoid cache keys that include branch name or github.head_ref — they will never match in merge queue."
|
|
75
|
+
- "setup-node/setup-python cache: integration automatically includes restore-keys and handles this gracefully."
|
|
76
|
+
docs:
|
|
77
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#merge_group"
|
|
78
|
+
label: "GitHub Actions: merge_group trigger"
|
|
79
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows#restrictions-for-accessing-a-cache"
|
|
80
|
+
label: "GitHub Actions: Cache branch access restrictions"
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
id: concurrency-timing-039
|
|
2
|
+
title: "Manual re-run cancels original run when concurrency group omits github.run_attempt"
|
|
3
|
+
category: concurrency-timing
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- concurrency
|
|
7
|
+
- re-run
|
|
8
|
+
- cancel-in-progress
|
|
9
|
+
- run-attempt
|
|
10
|
+
- manual-rerun
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'This run was cancelled'
|
|
13
|
+
flags: i
|
|
14
|
+
- regex: 'run_attempt'
|
|
15
|
+
flags: i
|
|
16
|
+
error_messages:
|
|
17
|
+
- "This run was cancelled."
|
|
18
|
+
- "A run for this workflow is already in progress."
|
|
19
|
+
root_cause: |
|
|
20
|
+
When cancel-in-progress: true is set and the concurrency group key does not
|
|
21
|
+
include github.run_attempt, every manual re-run of a workflow is treated as a
|
|
22
|
+
duplicate of the original run (since run_id and ref are the same). The re-run
|
|
23
|
+
immediately cancels the still-executing original attempt, or the concurrency
|
|
24
|
+
group queues the re-run and cancels any pending run — which may be the active
|
|
25
|
+
original.
|
|
26
|
+
|
|
27
|
+
The run_id is stable across re-runs but run_attempt increments (1, 2, 3...).
|
|
28
|
+
Without run_attempt in the concurrency group key, GitHub has no way to
|
|
29
|
+
distinguish re-run attempt 2 from the still-running attempt 1.
|
|
30
|
+
|
|
31
|
+
This produces confusing CI failures: a developer clicks "Re-run jobs" on a
|
|
32
|
+
failed workflow and immediately sees the original (or the re-run itself)
|
|
33
|
+
cancelled by the concurrency system.
|
|
34
|
+
fix: |
|
|
35
|
+
Include github.run_attempt in the concurrency group key so each attempt is
|
|
36
|
+
treated as a distinct slot. This allows re-runs to coexist with or cleanly
|
|
37
|
+
supersede the original without unexpected cancellations.
|
|
38
|
+
fix_code:
|
|
39
|
+
- language: yaml
|
|
40
|
+
label: "Include run_attempt in concurrency group key"
|
|
41
|
+
code: |
|
|
42
|
+
# WRONG: re-runs and originals share the same concurrency slot
|
|
43
|
+
# concurrency:
|
|
44
|
+
# group: ${{ github.workflow }}-${{ github.ref }}
|
|
45
|
+
# cancel-in-progress: true
|
|
46
|
+
|
|
47
|
+
# CORRECT: each attempt gets its own slot, preventing cross-attempt cancellation
|
|
48
|
+
concurrency:
|
|
49
|
+
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.run_attempt }}
|
|
50
|
+
cancel-in-progress: true
|
|
51
|
+
|
|
52
|
+
- language: yaml
|
|
53
|
+
label: "Alternative: cancel-in-progress only for push/PR, not re-runs"
|
|
54
|
+
code: |
|
|
55
|
+
concurrency:
|
|
56
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
57
|
+
# Only cancel-in-progress for first attempt; re-runs are never cancelled
|
|
58
|
+
cancel-in-progress: ${{ github.run_attempt == 1 }}
|
|
59
|
+
prevention:
|
|
60
|
+
- "Always include github.run_attempt in concurrency group keys when cancel-in-progress: true is set."
|
|
61
|
+
- "Test re-run behavior explicitly — concurrency cancellation bugs only surface when you manually re-run."
|
|
62
|
+
- "Consider using cancel-in-progress: ${{ github.run_attempt == 1 }} to preserve re-run integrity."
|
|
63
|
+
docs:
|
|
64
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#concurrency"
|
|
65
|
+
label: "GitHub Actions: Concurrency syntax"
|
|
66
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#github-context"
|
|
67
|
+
label: "GitHub Actions: github.run_attempt context"
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
id: runner-environment-142
|
|
2
|
+
title: "macOS-15 Sequoia Removes system python and python2 Stubs — Command Not Found in Workflows"
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- macos
|
|
7
|
+
- macos-15
|
|
8
|
+
- macos-latest
|
|
9
|
+
- python2
|
|
10
|
+
- python
|
|
11
|
+
- sequoia
|
|
12
|
+
- setup-python
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: 'python[23]?: command not found'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: '/usr/bin/python.*[Nn]o such file'
|
|
17
|
+
flags: ''
|
|
18
|
+
- regex: 'xcrun: error:.*python.*not a developer tool'
|
|
19
|
+
flags: 'i'
|
|
20
|
+
- regex: 'env: python: No such file or directory'
|
|
21
|
+
flags: ''
|
|
22
|
+
error_messages:
|
|
23
|
+
- "python: command not found"
|
|
24
|
+
- "python2: command not found"
|
|
25
|
+
- "/usr/bin/python: No such file or directory"
|
|
26
|
+
- "env: python: No such file or directory"
|
|
27
|
+
- "xcrun: error: unable to find utility 'python', not a developer tool or in PATH"
|
|
28
|
+
root_cause: |
|
|
29
|
+
Apple removed all Python stubs from macOS in macOS 15 (Sequoia). On macOS 12 through 14,
|
|
30
|
+
running `python` or `python2` would show a dialog prompting users to install Command Line
|
|
31
|
+
Tools, but the stub binary was present in /usr/bin/python so the command was technically
|
|
32
|
+
found (it just exited non-zero in CI where dialogs are suppressed). macOS 15 removed
|
|
33
|
+
these stubs entirely — /usr/bin/python and /usr/bin/python2 no longer exist.
|
|
34
|
+
|
|
35
|
+
GitHub Actions macos-15 runners and macos-latest (which resolves to macos-15 on 2025+
|
|
36
|
+
runners) have no `python` or `python2` in PATH unless explicitly installed via
|
|
37
|
+
actions/setup-python or Homebrew.
|
|
38
|
+
|
|
39
|
+
Affected workflow patterns:
|
|
40
|
+
- `run: python script.py` without a preceding setup-python step
|
|
41
|
+
- Build tools that internally call `python` (node-gyp, certain CMake scripts,
|
|
42
|
+
legacy Makefiles, scons, gyp-based builds)
|
|
43
|
+
- Shell scripts with `#!/usr/bin/env python` shebangs
|
|
44
|
+
- `pip` commands (also absent without setup-python)
|
|
45
|
+
|
|
46
|
+
Python 2 is also fully removed from Homebrew — `brew install python@2` is no longer
|
|
47
|
+
available. Any remaining Python 2 dependency must be ported to Python 3.
|
|
48
|
+
fix: |
|
|
49
|
+
Use actions/setup-python to install Python explicitly on macOS runners.
|
|
50
|
+
Set the python-version to the version your workflow needs (3.12 or higher recommended).
|
|
51
|
+
|
|
52
|
+
For node-gyp or native module builds that internally call `python`, set the
|
|
53
|
+
npm_config_python environment variable to point to the Python 3 binary from
|
|
54
|
+
setup-python.
|
|
55
|
+
|
|
56
|
+
For shell scripts with `#!/usr/bin/env python` shebangs, update the shebang to
|
|
57
|
+
`#!/usr/bin/env python3` or call the script explicitly with `python3 script.py`.
|
|
58
|
+
fix_code:
|
|
59
|
+
- language: yaml
|
|
60
|
+
label: "Add actions/setup-python before any step that needs python"
|
|
61
|
+
code: |
|
|
62
|
+
jobs:
|
|
63
|
+
build:
|
|
64
|
+
runs-on: macos-latest
|
|
65
|
+
steps:
|
|
66
|
+
- uses: actions/checkout@v4
|
|
67
|
+
- uses: actions/setup-python@v5
|
|
68
|
+
with:
|
|
69
|
+
python-version: '3.12'
|
|
70
|
+
- name: Run script
|
|
71
|
+
run: python script.py # resolves to Python 3.12 from setup-python
|
|
72
|
+
- language: yaml
|
|
73
|
+
label: "Fix node-gyp calling python internally (native npm modules)"
|
|
74
|
+
code: |
|
|
75
|
+
steps:
|
|
76
|
+
- uses: actions/setup-python@v5
|
|
77
|
+
with:
|
|
78
|
+
python-version: '3.12'
|
|
79
|
+
- name: Install native modules
|
|
80
|
+
env:
|
|
81
|
+
npm_config_python: ${{ env.pythonLocation }}/bin/python3
|
|
82
|
+
run: npm ci
|
|
83
|
+
- language: yaml
|
|
84
|
+
label: "Cache Python between runs on macOS for faster CI"
|
|
85
|
+
code: |
|
|
86
|
+
steps:
|
|
87
|
+
- uses: actions/setup-python@v5
|
|
88
|
+
with:
|
|
89
|
+
python-version: '3.12'
|
|
90
|
+
cache: 'pip' # caches pip downloads automatically
|
|
91
|
+
- run: pip install -r requirements.txt
|
|
92
|
+
prevention:
|
|
93
|
+
- "Always use actions/setup-python on macOS jobs — never rely on system Python."
|
|
94
|
+
- "Search workflow files for bare `python` calls (without `3` suffix) and update to `python3` or add setup-python."
|
|
95
|
+
- "When migrating from macos-13 or macos-14 to macos-15, audit all steps invoking build tools (node-gyp, CMake, scons) that may call `python` internally."
|
|
96
|
+
- "Pin macos runner versions (e.g., macos-14) and plan an explicit upgrade window when testing macOS version bumps."
|
|
97
|
+
docs:
|
|
98
|
+
- url: "https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md"
|
|
99
|
+
label: "macOS-15 runner image readme"
|
|
100
|
+
- url: "https://github.com/actions/setup-python"
|
|
101
|
+
label: "actions/setup-python"
|
|
102
|
+
- url: "https://developer.apple.com/documentation/xcode-release-notes/xcode-16-release-notes"
|
|
103
|
+
label: "Xcode 16 Release Notes (ships with macOS-15 runners)"
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
id: runner-environment-141
|
|
2
|
+
title: "ubuntu-24.04 MySQL 8.4 Removes mysql_native_password Plugin — Client Authentication Fails"
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- ubuntu-24.04
|
|
7
|
+
- mysql
|
|
8
|
+
- mysql-8.4
|
|
9
|
+
- authentication
|
|
10
|
+
- service-container
|
|
11
|
+
- database
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'Plugin ''mysql_native_password'' is not loaded'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'mysql_native_password.*cannot be loaded'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: 'ER_NOT_SUPPORTED_AUTH_MODE'
|
|
18
|
+
flags: 'i'
|
|
19
|
+
- regex: 'Client does not support authentication protocol requested by server'
|
|
20
|
+
flags: 'i'
|
|
21
|
+
error_messages:
|
|
22
|
+
- "ERROR 1524 (HY000): Plugin 'mysql_native_password' is not loaded"
|
|
23
|
+
- "Authentication plugin 'mysql_native_password' cannot be loaded"
|
|
24
|
+
- "ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client"
|
|
25
|
+
root_cause: |
|
|
26
|
+
Ubuntu 24.04 ships MySQL 8.4 LTS as its default MySQL version. MySQL 8.4 permanently
|
|
27
|
+
removed the `mysql_native_password` authentication plugin that was deprecated in
|
|
28
|
+
MySQL 8.0.4 and disabled by default in MySQL 8.0.34. In MySQL 8.4, the plugin
|
|
29
|
+
binary no longer exists — it cannot be re-enabled via server configuration.
|
|
30
|
+
|
|
31
|
+
The new default authentication plugin is `caching_sha2_password`, which requires
|
|
32
|
+
either a TLS/SSL connection or an RSA public key exchange during authentication.
|
|
33
|
+
Older MySQL client libraries that were compiled expecting mysql_native_password
|
|
34
|
+
behavior cannot authenticate against MySQL 8.4.
|
|
35
|
+
|
|
36
|
+
Commonly affected clients in GitHub Actions workflows:
|
|
37
|
+
- mysql2 Ruby gem versions < 0.5.6
|
|
38
|
+
- mysqljs/mysql npm package (use mysql2 npm package instead)
|
|
39
|
+
- mysql-connector-python < 8.0.28 without SSL configuration
|
|
40
|
+
- phpMyAdmin and other tools linking against older libmysqlclient
|
|
41
|
+
|
|
42
|
+
Workflows that use `image: mysql:latest` in service containers are at highest risk
|
|
43
|
+
as mysql:latest advanced to 8.4 and then 9.x after ubuntu-24.04 was released.
|
|
44
|
+
fix: |
|
|
45
|
+
Option 1 — Pin MySQL service container to mysql:8.0:
|
|
46
|
+
Use `image: mysql:8.0` in your service container definition. MySQL 8.0 supports
|
|
47
|
+
mysql_native_password and is fully compatible with existing client libraries.
|
|
48
|
+
This is the fastest fix for affected workflows.
|
|
49
|
+
|
|
50
|
+
Option 2 — Update the MySQL client library:
|
|
51
|
+
- Ruby: upgrade mysql2 gem to >= 0.5.6 (caching_sha2_password support added)
|
|
52
|
+
- Node.js: replace `mysql` package with `mysql2` (>= 3.x)
|
|
53
|
+
- Python: upgrade mysql-connector-python to latest and configure ssl_disabled: false
|
|
54
|
+
|
|
55
|
+
Option 3 — Configure MySQL 8.4 to allow password auth with --default-auth:
|
|
56
|
+
MySQL 8.4 still supports caching_sha2_password for all connections. The issue is
|
|
57
|
+
the client, not the server. Update the client library — not the server auth policy.
|
|
58
|
+
fix_code:
|
|
59
|
+
- language: yaml
|
|
60
|
+
label: "Pin MySQL service container to 8.0 to preserve native password support"
|
|
61
|
+
code: |
|
|
62
|
+
services:
|
|
63
|
+
mysql:
|
|
64
|
+
image: mysql:8.0 # Pin — mysql:latest is now 8.4+ (native_password removed)
|
|
65
|
+
env:
|
|
66
|
+
MYSQL_ROOT_PASSWORD: rootpassword
|
|
67
|
+
MYSQL_DATABASE: testdb
|
|
68
|
+
options: >-
|
|
69
|
+
--health-cmd="mysqladmin ping -h 127.0.0.1"
|
|
70
|
+
--health-interval=10s
|
|
71
|
+
--health-timeout=5s
|
|
72
|
+
--health-retries=5
|
|
73
|
+
- language: yaml
|
|
74
|
+
label: "Update mysql2 Ruby gem and use mysql:8.4 correctly"
|
|
75
|
+
code: |
|
|
76
|
+
# Gemfile — update to mysql2 >= 0.5.6 for caching_sha2_password support
|
|
77
|
+
# gem 'mysql2', '>= 0.5.6'
|
|
78
|
+
|
|
79
|
+
# Node.js — replace mysql (1.x) with mysql2 (3.x)
|
|
80
|
+
# npm install mysql2 # supports SHA2 auth; old mysql package does not
|
|
81
|
+
|
|
82
|
+
services:
|
|
83
|
+
mysql:
|
|
84
|
+
image: mysql:8.4
|
|
85
|
+
env:
|
|
86
|
+
MYSQL_ROOT_PASSWORD: rootpassword
|
|
87
|
+
MYSQL_DATABASE: testdb
|
|
88
|
+
options: >-
|
|
89
|
+
--health-cmd="mysqladmin ping -h 127.0.0.1"
|
|
90
|
+
--health-interval=10s
|
|
91
|
+
--health-timeout=5s
|
|
92
|
+
--health-retries=5
|
|
93
|
+
prevention:
|
|
94
|
+
- "Always pin service container image versions (e.g., mysql:8.0) — mysql:latest advances silently and introduces breaking changes."
|
|
95
|
+
- "Test with the exact MySQL version your production environment uses, not mysql:latest."
|
|
96
|
+
- "When upgrading MySQL service container versions, update client gems/packages to versions that support caching_sha2_password."
|
|
97
|
+
- "Use the mysql health check option to fail fast when the container is misconfigured rather than timing out later."
|
|
98
|
+
docs:
|
|
99
|
+
- url: "https://dev.mysql.com/doc/relnotes/mysql/8.4/en/news-8-4-0.html"
|
|
100
|
+
label: "MySQL 8.4.0 Release Notes — mysql_native_password removed"
|
|
101
|
+
- url: "https://docs.github.com/en/actions/use-cases-and-examples/using-containerized-services/about-service-containers"
|
|
102
|
+
label: "GitHub Actions: about service containers"
|
|
103
|
+
- url: "https://github.com/brianmario/mysql2"
|
|
104
|
+
label: "mysql2 Ruby gem — caching_sha2_password support"
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
id: runner-environment-140
|
|
2
|
+
title: "ubuntu-24.04 pip install Fails With 'externally-managed-environment' — PEP 668 Blocks System Python"
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- ubuntu-24.04
|
|
7
|
+
- ubuntu-latest
|
|
8
|
+
- python
|
|
9
|
+
- pip
|
|
10
|
+
- pep-668
|
|
11
|
+
- venv
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'error: externally-managed-environment'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'This environment is externally managed'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: 'EXTERNALLY-MANAGED'
|
|
18
|
+
flags: ''
|
|
19
|
+
error_messages:
|
|
20
|
+
- "error: externally-managed-environment"
|
|
21
|
+
- "× This environment is externally managed"
|
|
22
|
+
- "hint: See PEP 668 for the detailed specification."
|
|
23
|
+
root_cause: |
|
|
24
|
+
Ubuntu 24.04 implements PEP 668, which marks the system Python environment as
|
|
25
|
+
"externally managed" — pip is not permitted to install or modify packages into
|
|
26
|
+
the system Python site-packages directory. The restriction is enforced by an
|
|
27
|
+
EXTERNALLY-MANAGED marker file placed at /usr/lib/python3.X/EXTERNALLY-MANAGED
|
|
28
|
+
by the Ubuntu package maintainers.
|
|
29
|
+
|
|
30
|
+
On GitHub Actions ubuntu-24.04 runners (and ubuntu-latest, which resolved to
|
|
31
|
+
ubuntu-24.04 in mid-2025), the default system Python 3 (3.12) ships this marker.
|
|
32
|
+
Any workflow step that calls `pip install` or `pip3 install` without a virtual
|
|
33
|
+
environment or the setup-python action will hit this error immediately.
|
|
34
|
+
|
|
35
|
+
Workflows migrated from ubuntu-22.04 — which did not enforce PEP 668 — will fail
|
|
36
|
+
on first run without any other changes. The error is clear in the output but
|
|
37
|
+
unexpected for workflows that previously relied on system-wide pip installs.
|
|
38
|
+
fix: |
|
|
39
|
+
Option 1 — Use actions/setup-python (recommended):
|
|
40
|
+
Replace the bare system Python with a setup-python step. actions/setup-python
|
|
41
|
+
creates its own isolated Python installation outside the system path, making
|
|
42
|
+
pip install work without virtual environments or bypass flags.
|
|
43
|
+
|
|
44
|
+
Option 2 — Create a virtual environment:
|
|
45
|
+
Run `python3 -m venv .venv && source .venv/bin/activate` before pip install.
|
|
46
|
+
This is the correct long-term fix for any environment.
|
|
47
|
+
|
|
48
|
+
Option 3 — Pass --break-system-packages:
|
|
49
|
+
Append `--break-system-packages` to the pip install command. This bypasses
|
|
50
|
+
PEP 668 enforcement. Acceptable in ephemeral CI environments but not
|
|
51
|
+
recommended for production systems.
|
|
52
|
+
fix_code:
|
|
53
|
+
- language: yaml
|
|
54
|
+
label: "Use actions/setup-python — recommended approach"
|
|
55
|
+
code: |
|
|
56
|
+
steps:
|
|
57
|
+
- uses: actions/checkout@v4
|
|
58
|
+
- uses: actions/setup-python@v5
|
|
59
|
+
with:
|
|
60
|
+
python-version: '3.12'
|
|
61
|
+
- name: Install dependencies
|
|
62
|
+
run: pip install -r requirements.txt # works: isolated Python, not system
|
|
63
|
+
- language: yaml
|
|
64
|
+
label: "Create a virtual environment before pip install"
|
|
65
|
+
code: |
|
|
66
|
+
steps:
|
|
67
|
+
- uses: actions/checkout@v4
|
|
68
|
+
- name: Install in venv
|
|
69
|
+
run: |
|
|
70
|
+
python3 -m venv .venv
|
|
71
|
+
source .venv/bin/activate
|
|
72
|
+
pip install -r requirements.txt
|
|
73
|
+
- language: yaml
|
|
74
|
+
label: "Quick fix: --break-system-packages flag (CI-only workaround)"
|
|
75
|
+
code: |
|
|
76
|
+
steps:
|
|
77
|
+
- name: Install dependencies
|
|
78
|
+
run: pip install --break-system-packages -r requirements.txt
|
|
79
|
+
prevention:
|
|
80
|
+
- "Use actions/setup-python on ubuntu-24.04 runners — do not rely on system Python for pip installs."
|
|
81
|
+
- "Audit all `pip install` steps when migrating from ubuntu-22.04 to ubuntu-24.04 or ubuntu-latest."
|
|
82
|
+
- "Pin your Python version in actions/setup-python to prevent unexpected changes when the runner default Python changes."
|
|
83
|
+
- "Cache the virtual environment with actions/cache using a hash of requirements.txt as the key to speed up runs."
|
|
84
|
+
docs:
|
|
85
|
+
- url: "https://peps.python.org/pep-0668/"
|
|
86
|
+
label: "PEP 668 — Marking Python base environments as externally managed"
|
|
87
|
+
- url: "https://github.com/actions/setup-python"
|
|
88
|
+
label: "actions/setup-python"
|
|
89
|
+
- url: "https://wiki.ubuntu.com/NobleNumbat/ReleaseNotes"
|
|
90
|
+
label: "Ubuntu 24.04 (Noble Numbat) Release Notes"
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
id: runner-environment-143
|
|
2
|
+
title: "snap install Fails on All GitHub-Hosted Runners — snapd Requires systemd Which Is Absent in CI"
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- ubuntu
|
|
7
|
+
- snap
|
|
8
|
+
- snapd
|
|
9
|
+
- systemd
|
|
10
|
+
- package-management
|
|
11
|
+
- runner-limitation
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'cannot communicate with server.*snapd'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'snap: command not found'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: 'snapd\.socket.*connect.*no such file'
|
|
18
|
+
flags: 'i'
|
|
19
|
+
- regex: 'error: cannot list snaps: cannot communicate with server'
|
|
20
|
+
flags: 'i'
|
|
21
|
+
error_messages:
|
|
22
|
+
- "error: cannot communicate with server: Post \"http+unix://%2Frun%2Fsnapd.socket/v2/snaps\": dial unix /run/snapd.socket: connect: no such file or directory"
|
|
23
|
+
- "snapd is not running"
|
|
24
|
+
- "snap: command not found"
|
|
25
|
+
- "cannot communicate with server: Post http+unix:///run/snapd.socket/v2/snaps: dial unix /run/snapd.socket: connect: no such file or directory"
|
|
26
|
+
root_cause: |
|
|
27
|
+
GitHub-hosted Ubuntu runners do not run systemd as PID 1. They use a custom
|
|
28
|
+
initialization environment where systemd is not the init system. The snap package
|
|
29
|
+
manager (snapd) requires systemd for:
|
|
30
|
+
- Daemon lifecycle management (snapd.service unit)
|
|
31
|
+
- D-Bus socket activation (/run/snapd.socket)
|
|
32
|
+
- AppArmor profile enforcement for snap confinement
|
|
33
|
+
- Mount namespace management for snap application isolation
|
|
34
|
+
|
|
35
|
+
Without systemd, the snapd daemon never starts, and /run/snapd.socket does not
|
|
36
|
+
exist. Any `snap install` command immediately fails because the snap client
|
|
37
|
+
cannot reach the daemon socket to submit the install request.
|
|
38
|
+
|
|
39
|
+
This is a structural limitation of GitHub-hosted runners across ALL Ubuntu versions
|
|
40
|
+
(ubuntu-20.04, ubuntu-22.04, ubuntu-24.04, ubuntu-latest) and has not changed
|
|
41
|
+
since Actions was launched. Attempting to start snapd manually with `systemctl start snapd`
|
|
42
|
+
also fails because systemctl is non-functional without systemd.
|
|
43
|
+
|
|
44
|
+
While `snap` binary may be present in PATH on some runner images, it is non-functional
|
|
45
|
+
and the underlying daemon cannot be started in the current runner architecture.
|
|
46
|
+
fix: |
|
|
47
|
+
Replace snap install with an alternative package source:
|
|
48
|
+
|
|
49
|
+
- Use apt/apt-get: Most snap packages have apt equivalents or PPA repositories
|
|
50
|
+
- Use dedicated GitHub Actions: Many popular tools have official or maintained Actions
|
|
51
|
+
(e.g., azure/setup-kubectl, helm/kind-action, hashicorp/setup-terraform)
|
|
52
|
+
- Download official binary releases: curl the release binary from GitHub Releases
|
|
53
|
+
or the tool's official download page, then move to /usr/local/bin
|
|
54
|
+
- Use Homebrew (macOS) or the tool's official install script
|
|
55
|
+
fix_code:
|
|
56
|
+
- language: yaml
|
|
57
|
+
label: "Replace snap install kubectl with the official setup-kubectl action"
|
|
58
|
+
code: |
|
|
59
|
+
steps:
|
|
60
|
+
# Instead of: run: sudo snap install kubectl --classic
|
|
61
|
+
- uses: azure/setup-kubectl@v4
|
|
62
|
+
with:
|
|
63
|
+
version: 'v1.30.0'
|
|
64
|
+
- language: yaml
|
|
65
|
+
label: "Replace snap install helm with the official Helm install script"
|
|
66
|
+
code: |
|
|
67
|
+
steps:
|
|
68
|
+
# Instead of: run: sudo snap install helm --classic
|
|
69
|
+
- name: Install Helm
|
|
70
|
+
run: |
|
|
71
|
+
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
|
72
|
+
- language: yaml
|
|
73
|
+
label: "Generic: replace snap install with direct binary download"
|
|
74
|
+
code: |
|
|
75
|
+
steps:
|
|
76
|
+
- name: Install tool via binary release (snap alternative)
|
|
77
|
+
run: |
|
|
78
|
+
VERSION="1.2.3"
|
|
79
|
+
curl -fsSL "https://example.com/releases/${VERSION}/tool-linux-amd64.tar.gz" \
|
|
80
|
+
| tar -xz -C /usr/local/bin tool
|
|
81
|
+
prevention:
|
|
82
|
+
- "Never use `snap install` in GitHub Actions — snapd does not work on any GitHub-hosted runner."
|
|
83
|
+
- "Search all workflow files for `snap install` and replace with apt, binary downloads, or official GitHub Actions."
|
|
84
|
+
- "When evaluating new tools for CI, prefer those distributed via apt, Homebrew, or binary releases over snap-only distributions."
|
|
85
|
+
- "Check the tool's GitHub repository for an official GitHub Action before writing a custom install step."
|
|
86
|
+
docs:
|
|
87
|
+
- url: "https://github.com/actions/runner-images/issues/3206"
|
|
88
|
+
label: "runner-images #3206: snap install fails on GitHub Actions (long-running issue)"
|
|
89
|
+
- url: "https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners"
|
|
90
|
+
label: "GitHub-hosted runners overview"
|
|
91
|
+
- url: "https://snapcraft.io/docs/installing-snapd"
|
|
92
|
+
label: "Snapcraft: installing snapd (requires systemd)"
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
id: silent-failures-074
|
|
2
|
+
title: "fromJSON() object or array stored in env: block silently becomes '[object Object]'"
|
|
3
|
+
category: silent-failures
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- fromjson
|
|
7
|
+
- env-context
|
|
8
|
+
- type-coercion
|
|
9
|
+
- json-parsing
|
|
10
|
+
- stringification
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'env\s*:.*\$\{\{\s*fromJSON\('
|
|
13
|
+
flags: ims
|
|
14
|
+
error_messages:
|
|
15
|
+
- "[object Object]"
|
|
16
|
+
- "Unexpected token 'o', \"[object O\"... is not valid JSON"
|
|
17
|
+
root_cause: |
|
|
18
|
+
The fromJSON() function in GitHub Actions expressions parses a JSON string
|
|
19
|
+
into a typed value — object, array, boolean, or number. However, when the
|
|
20
|
+
result is assigned to an env: variable, the Actions runner coerces the value
|
|
21
|
+
to a string using JavaScript's default toString(). For objects this produces
|
|
22
|
+
the literal string [object Object]; for arrays it produces a comma-joined
|
|
23
|
+
string (e.g., a,b,c).
|
|
24
|
+
|
|
25
|
+
The step exits with code 0 and the env variable appears set, but its value is
|
|
26
|
+
the stringified form rather than the JSON structure the developer expected.
|
|
27
|
+
Subsequent steps that reference ${{ env.CONFIG }} or echo the variable and
|
|
28
|
+
pipe it through jq will receive [object Object] and fail to parse — or silently
|
|
29
|
+
produce wrong results.
|
|
30
|
+
|
|
31
|
+
Booleans and numbers survive correctly: fromJSON('true') in env: produces the
|
|
32
|
+
string 'true', and fromJSON('42') produces '42' — these are the only safe uses.
|
|
33
|
+
fix: |
|
|
34
|
+
Pass structured JSON data between steps via GITHUB_OUTPUT (as a raw JSON
|
|
35
|
+
string), then consume the stored string with fromJSON() in downstream
|
|
36
|
+
expression contexts. Never store objects or arrays via fromJSON() in env: blocks.
|
|
37
|
+
fix_code:
|
|
38
|
+
- language: yaml
|
|
39
|
+
label: "Store JSON in GITHUB_OUTPUT, consume via fromJSON in expressions"
|
|
40
|
+
code: |
|
|
41
|
+
jobs:
|
|
42
|
+
build:
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
steps:
|
|
45
|
+
# WRONG: fromJSON object in env: becomes '[object Object]'
|
|
46
|
+
# - name: Bad config
|
|
47
|
+
# env:
|
|
48
|
+
# CONFIG: ${{ fromJSON(inputs.config_json) }}
|
|
49
|
+
# run: echo "$CONFIG" | jq .host # fails: '[object Object]' is not JSON
|
|
50
|
+
|
|
51
|
+
# CORRECT: store raw JSON string in GITHUB_OUTPUT
|
|
52
|
+
- name: Store config
|
|
53
|
+
id: cfg
|
|
54
|
+
run: echo 'config=${{ inputs.config_json }}' >> $GITHUB_OUTPUT
|
|
55
|
+
|
|
56
|
+
# Access fields with fromJSON() directly in expression context
|
|
57
|
+
- name: Use config
|
|
58
|
+
run: |
|
|
59
|
+
echo "Host: ${{ fromJSON(steps.cfg.outputs.config).host }}"
|
|
60
|
+
echo "Port: ${{ fromJSON(steps.cfg.outputs.config).port }}"
|
|
61
|
+
|
|
62
|
+
# Scalar fromJSON values are safe in env: (boolean, number)
|
|
63
|
+
- name: Scalar fromJSON is fine
|
|
64
|
+
env:
|
|
65
|
+
IS_PROD: ${{ fromJSON(inputs.is_prod) }}
|
|
66
|
+
TIMEOUT: ${{ fromJSON(inputs.timeout) }}
|
|
67
|
+
run: echo "prod=$IS_PROD timeout=$TIMEOUT"
|
|
68
|
+
prevention:
|
|
69
|
+
- "Never assign fromJSON() results that produce objects or arrays to env: variables."
|
|
70
|
+
- "Use fromJSON() inline in expression contexts (${{ fromJSON(x).field }}) rather than materializing into env vars."
|
|
71
|
+
- "Store JSON blobs as raw strings in GITHUB_OUTPUT and parse with jq in shell or fromJSON() in expressions."
|
|
72
|
+
- "For object env vars, keep the value as a raw JSON string and parse in shell with jq or python -c."
|
|
73
|
+
docs:
|
|
74
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#fromjson"
|
|
75
|
+
label: "GitHub Actions: fromJSON expression function"
|
|
76
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/passing-information-between-jobs"
|
|
77
|
+
label: "GitHub Actions: Passing information between jobs"
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
id: triggers-053
|
|
2
|
+
title: "Unknown or misspelled values in on.<event>.types[] are silently ignored — workflow never triggers"
|
|
3
|
+
category: triggers
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- types-filter
|
|
7
|
+
- trigger
|
|
8
|
+
- typo
|
|
9
|
+
- pull-request
|
|
10
|
+
- silent-failure
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'types\s*:\s*\[.*(?:syncronize|synchronised|synchronize d|re-opened|labeld|assign)\]'
|
|
13
|
+
flags: i
|
|
14
|
+
- regex: 'types\s*:\s*\n(?:\s+-\s+\w+\n)*\s+-\s+(?!opened|closed|reopened|synchronize|labeled|unlabeled|assigned|unassigned|review_requested|ready_for_review|converted_to_draft|locked|unlocked|milestoned|demilestoned|edited)\w'
|
|
15
|
+
flags: im
|
|
16
|
+
error_messages:
|
|
17
|
+
- "Workflow is not triggered"
|
|
18
|
+
- "No runs found"
|
|
19
|
+
root_cause: |
|
|
20
|
+
GitHub Actions silently discards unrecognized values in the types: filter
|
|
21
|
+
array for pull_request, pull_request_target, and other typed events. There is
|
|
22
|
+
no validation error, no schema warning, and no run log entry — the workflow
|
|
23
|
+
simply never fires for the intended activity type.
|
|
24
|
+
|
|
25
|
+
The most common cause is a typo in a well-known type name:
|
|
26
|
+
- syncronize (correct: synchronize)
|
|
27
|
+
- re-opened (correct: reopened)
|
|
28
|
+
- labeld (correct: labeled)
|
|
29
|
+
- closed (correct: closed — note: not 'merged')
|
|
30
|
+
|
|
31
|
+
A second common cause is listing only the new type while forgetting that the
|
|
32
|
+
default types are no longer active. For example, types: [synchronize] drops
|
|
33
|
+
the implicit opened and reopened behaviors, so a newly opened PR will not
|
|
34
|
+
trigger CI at all.
|
|
35
|
+
|
|
36
|
+
actionlint >=0.7.0 can detect unknown type values but is not always used in
|
|
37
|
+
local development workflows.
|
|
38
|
+
fix: |
|
|
39
|
+
Verify all type values against the official list for each event. Include all
|
|
40
|
+
intended types explicitly — once types: is specified, the defaults no longer
|
|
41
|
+
apply.
|
|
42
|
+
fix_code:
|
|
43
|
+
- language: yaml
|
|
44
|
+
label: "Correct types for pull_request CI — always include all intended types"
|
|
45
|
+
code: |
|
|
46
|
+
on:
|
|
47
|
+
pull_request:
|
|
48
|
+
# WRONG examples (silently never trigger):
|
|
49
|
+
# types: [opened, syncronize, re-opened] # typos
|
|
50
|
+
# types: [synchronize] # drops opened/reopened
|
|
51
|
+
|
|
52
|
+
# CORRECT: include all intended activity types
|
|
53
|
+
types:
|
|
54
|
+
- opened
|
|
55
|
+
- synchronize
|
|
56
|
+
- reopened
|
|
57
|
+
|
|
58
|
+
- language: yaml
|
|
59
|
+
label: "All valid pull_request types for reference"
|
|
60
|
+
code: |
|
|
61
|
+
on:
|
|
62
|
+
pull_request:
|
|
63
|
+
types:
|
|
64
|
+
# Commonly needed for CI:
|
|
65
|
+
- opened # new PR created
|
|
66
|
+
- synchronize # new commit pushed to PR branch
|
|
67
|
+
- reopened # closed PR re-opened
|
|
68
|
+
# Useful for label-gated workflows:
|
|
69
|
+
- labeled
|
|
70
|
+
- unlabeled
|
|
71
|
+
# Draft/review flow:
|
|
72
|
+
- ready_for_review
|
|
73
|
+
- converted_to_draft
|
|
74
|
+
# Assignment:
|
|
75
|
+
- assigned
|
|
76
|
+
- unassigned
|
|
77
|
+
- review_requested
|
|
78
|
+
prevention:
|
|
79
|
+
- "Run actionlint (>=0.7.0) in CI to detect unknown type values — it reports them as errors."
|
|
80
|
+
- "When adding types:, explicitly list ALL types you need — defaults no longer apply once types: is present."
|
|
81
|
+
- "After changing types:, trigger one manual test run per type to confirm the filter is working."
|
|
82
|
+
- "Use the GitHub Actions VS Code extension — it underlines unknown type values as warnings."
|
|
83
|
+
docs:
|
|
84
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request"
|
|
85
|
+
label: "GitHub Actions: pull_request event types"
|
|
86
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request_target"
|
|
87
|
+
label: "GitHub Actions: pull_request_target event types"
|
|
88
|
+
- url: "https://rhysd.github.io/actionlint/"
|
|
89
|
+
label: "actionlint: GitHub Actions linter"
|
package/package.json
CHANGED