@htekdev/actions-debugger 1.0.90 → 1.0.92
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/errors/caching-artifacts/caching-artifacts-051.yml +86 -0
- package/errors/permissions-auth/permissions-auth-051.yml +103 -0
- package/errors/runner-environment/runner-environment-157.yml +92 -0
- package/errors/runner-environment/windows-max-path-260-npm-build-failure.yml +87 -0
- package/errors/silent-failures/pull-request-branches-filter-not-inherited.yml +73 -0
- package/errors/triggers/delete-event-fires-branch-and-tag.yml +75 -0
- package/errors/triggers/pull-request-review-all-types-default.yml +69 -0
- package/errors/yaml-syntax/yaml-syntax-057.yml +93 -0
- package/package.json +1 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
id: caching-artifacts-051
|
|
2
|
+
title: 'download-artifact@v4 places each artifact in a named subdirectory, breaking v3 flat path assumption'
|
|
3
|
+
category: caching-artifacts
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- download-artifact
|
|
7
|
+
- v4-migration
|
|
8
|
+
- directory-structure
|
|
9
|
+
- breaking-change
|
|
10
|
+
- path
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'Downloading artifact.*to.*'
|
|
13
|
+
flags: 'i'
|
|
14
|
+
- regex: 'ENOENT.*no such file or directory'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'no such file or directory.*dist\/'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
error_messages:
|
|
19
|
+
- "Downloading artifact: my-artifact to /home/runner/work/repo/dist"
|
|
20
|
+
- "Error: ENOENT: no such file or directory, open 'dist/index.js'"
|
|
21
|
+
- "Error: Cannot find module '/home/runner/work/repo/dist/index.js'"
|
|
22
|
+
- "cp: cannot stat 'dist/main.js': No such file or directory"
|
|
23
|
+
root_cause: |
|
|
24
|
+
In actions/download-artifact@v3, downloading a named artifact with `path: dist`
|
|
25
|
+
placed files directly inside the `dist/` directory (flat layout). In v4,
|
|
26
|
+
the action changed to place each artifact in a subdirectory named after the
|
|
27
|
+
artifact: files land at `dist/<artifact-name>/filename` instead of `dist/filename`.
|
|
28
|
+
|
|
29
|
+
This is a silent failure: the `download-artifact` step succeeds with exit code 0
|
|
30
|
+
and emits no warning about the path change. Downstream steps that reference
|
|
31
|
+
`dist/index.js` fail with "no such file" errors — the file is actually at
|
|
32
|
+
`dist/my-artifact/index.js`. The behavior is especially confusing in matrix
|
|
33
|
+
workflows where each job uploads an artifact with a unique name, and the
|
|
34
|
+
consuming job downloads all artifacts into a single `path:`.
|
|
35
|
+
|
|
36
|
+
The change was made to support downloading multiple artifacts into the same
|
|
37
|
+
`path:` without name collisions, but it breaks any workflow that migrated from
|
|
38
|
+
v3 without adjusting downstream path references.
|
|
39
|
+
fix: |
|
|
40
|
+
Option 1 (recommended): Set the `path:` to a staging directory and reference
|
|
41
|
+
files using the artifact subdirectory path, or use `merge-multiple: true` to
|
|
42
|
+
flatten all artifacts into the `path:` directory.
|
|
43
|
+
|
|
44
|
+
Option 2: Name the artifact the same as the target directory and download into
|
|
45
|
+
the parent, so the subdirectory becomes the expected location.
|
|
46
|
+
|
|
47
|
+
Option 3: Add a step to move the artifact contents up one level after download.
|
|
48
|
+
fix_code:
|
|
49
|
+
- language: yaml
|
|
50
|
+
label: 'Use merge-multiple: true to restore v3 flat behavior for single artifact'
|
|
51
|
+
code: |
|
|
52
|
+
- uses: actions/download-artifact@v4
|
|
53
|
+
with:
|
|
54
|
+
name: dist-bundle
|
|
55
|
+
path: dist
|
|
56
|
+
merge-multiple: true # Flattens into dist/ directly, matching v3 behavior
|
|
57
|
+
- language: yaml
|
|
58
|
+
label: 'Adjust downstream path to include artifact subdirectory'
|
|
59
|
+
code: |
|
|
60
|
+
- uses: actions/download-artifact@v4
|
|
61
|
+
with:
|
|
62
|
+
name: dist-bundle
|
|
63
|
+
path: staging
|
|
64
|
+
|
|
65
|
+
# Files land at staging/dist-bundle/index.js — reference accordingly
|
|
66
|
+
- run: node staging/dist-bundle/index.js
|
|
67
|
+
- language: yaml
|
|
68
|
+
label: 'Download all matrix artifacts and merge into one directory'
|
|
69
|
+
code: |
|
|
70
|
+
- uses: actions/download-artifact@v4
|
|
71
|
+
with:
|
|
72
|
+
pattern: build-* # Matches all matrix artifacts
|
|
73
|
+
path: dist
|
|
74
|
+
merge-multiple: true # All files merged flat into dist/
|
|
75
|
+
prevention:
|
|
76
|
+
- "When migrating from download-artifact@v3 to v4, audit all `path:` references and downstream file access patterns"
|
|
77
|
+
- "Use `merge-multiple: true` if you need the v3 flat download behavior for a single named artifact"
|
|
78
|
+
- "Set `path:` to a staging directory and explicitly reference the `path/<artifact-name>/` subdirectory in downstream steps"
|
|
79
|
+
- "Run the workflow once after migrating and check the action log for 'Downloading artifact: X to Y' to verify the actual destination path"
|
|
80
|
+
docs:
|
|
81
|
+
- url: 'https://github.com/actions/download-artifact/blob/main/docs/migration-guide.md'
|
|
82
|
+
label: 'download-artifact migration guide: v3 to v4 breaking changes'
|
|
83
|
+
- url: 'https://github.com/actions/download-artifact?tab=readme-ov-file#inputs'
|
|
84
|
+
label: 'download-artifact@v4 inputs reference — merge-multiple option'
|
|
85
|
+
- url: 'https://github.com/actions/upload-artifact/discussions/562'
|
|
86
|
+
label: 'Community discussion: v4 directory structure change from v3'
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
id: permissions-auth-051
|
|
2
|
+
title: 'GITHUB_TOKEN push blocked by repository ruleset despite contents: write permission'
|
|
3
|
+
category: permissions-auth
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- github-token
|
|
7
|
+
- rulesets
|
|
8
|
+
- contents-write
|
|
9
|
+
- branch-protection
|
|
10
|
+
- bypass-list
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'GH013: Repository rule violations found for refs\/'
|
|
13
|
+
flags: 'i'
|
|
14
|
+
- regex: 'remote: error: Changes must be made through a pull request'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'refusing to allow.*to create or update'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
error_messages:
|
|
19
|
+
- "remote: error: GH013: Repository rule violations found for refs/heads/main."
|
|
20
|
+
- "remote: error: GH013: Repository rule violations found for refs/tags/v1.0.0."
|
|
21
|
+
- "remote: error: Changes must be made through a pull request."
|
|
22
|
+
- "error: failed to push some refs to 'https://github.com/ORG/REPO.git'"
|
|
23
|
+
- "refusing to allow a GitHub App to create or update file"
|
|
24
|
+
root_cause: |
|
|
25
|
+
GitHub Rulesets (generally available January 2025) allow organization and repository
|
|
26
|
+
administrators to define push rules that enforce requirements such as "all pushes
|
|
27
|
+
must come through a pull request", "signed commits required", or "tag patterns
|
|
28
|
+
must match a format". Unlike legacy branch protection rules, rulesets apply to
|
|
29
|
+
ALL actors including GitHub Apps and the GITHUB_TOKEN by default — regardless of
|
|
30
|
+
the `contents: write` permission granted in the workflow's `permissions:` block.
|
|
31
|
+
|
|
32
|
+
The `contents: write` permission only controls whether the token is *authorized*
|
|
33
|
+
to make write API calls; it does not grant exemption from repository rulesets.
|
|
34
|
+
Rulesets have a separate "bypass list" in Settings > Rules > Rulesets that must
|
|
35
|
+
explicitly include "GitHub Actions" (or a specific GitHub App) to allow workflow
|
|
36
|
+
pushes to bypass ruleset restrictions.
|
|
37
|
+
|
|
38
|
+
This error affects workflows that push commits directly (e.g., auto-format,
|
|
39
|
+
changelog generation, version bump commits) or push tags (e.g., release tagging)
|
|
40
|
+
to branches or tags governed by a ruleset.
|
|
41
|
+
fix: |
|
|
42
|
+
Option 1 (recommended): Add GitHub Actions to the ruleset bypass list.
|
|
43
|
+
Go to Settings > Rules > Rulesets > (select the ruleset) > Bypass list >
|
|
44
|
+
Add bypass > select "GitHub Actions". This allows workflow GITHUB_TOKEN
|
|
45
|
+
pushes to bypass the ruleset.
|
|
46
|
+
|
|
47
|
+
Option 2: Use a Personal Access Token (PAT) or GitHub App token from a user
|
|
48
|
+
account that is in the bypass list. Pass the token via a secret and use it
|
|
49
|
+
in the push step.
|
|
50
|
+
|
|
51
|
+
Option 3: Restructure the workflow to push via a pull request instead of
|
|
52
|
+
directly to the protected branch, satisfying the "PR required" ruleset rule.
|
|
53
|
+
fix_code:
|
|
54
|
+
- language: yaml
|
|
55
|
+
label: 'Use a PAT secret to push when GITHUB_TOKEN is blocked by rulesets'
|
|
56
|
+
code: |
|
|
57
|
+
jobs:
|
|
58
|
+
release:
|
|
59
|
+
runs-on: ubuntu-latest
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@v4
|
|
62
|
+
with:
|
|
63
|
+
token: ${{ secrets.RELEASE_PAT }} # PAT from bypass-listed account
|
|
64
|
+
fetch-depth: 0
|
|
65
|
+
|
|
66
|
+
# ... version bump or commit steps ...
|
|
67
|
+
|
|
68
|
+
- name: Push release commit and tag
|
|
69
|
+
env:
|
|
70
|
+
GITHUB_TOKEN: ${{ secrets.RELEASE_PAT }}
|
|
71
|
+
run: |
|
|
72
|
+
# Use the PAT-authenticated remote for push
|
|
73
|
+
echo "Push authorized via PAT from bypass-listed account"
|
|
74
|
+
- language: yaml
|
|
75
|
+
label: 'Use a GitHub App token with bypass list membership'
|
|
76
|
+
code: |
|
|
77
|
+
jobs:
|
|
78
|
+
release:
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
steps:
|
|
81
|
+
- uses: actions/create-github-app-token@v2
|
|
82
|
+
id: app-token
|
|
83
|
+
with:
|
|
84
|
+
app-id: ${{ vars.RELEASE_APP_ID }}
|
|
85
|
+
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
|
|
86
|
+
|
|
87
|
+
- uses: actions/checkout@v4
|
|
88
|
+
with:
|
|
89
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
90
|
+
|
|
91
|
+
# Push step uses the App token — ensure the App is in bypass list
|
|
92
|
+
prevention:
|
|
93
|
+
- "When enabling rulesets on a repository or organization, immediately check CI/CD workflows that push directly to protected branches or tags"
|
|
94
|
+
- "Add GitHub Actions to ruleset bypass lists proactively when creating rulesets that restrict direct pushes"
|
|
95
|
+
- "Prefer pushing via pull requests (open PR, auto-merge) over direct commits in automated workflows — this satisfies 'PR required' rules and avoids bypass list management"
|
|
96
|
+
- "Audit existing legacy branch protection rules when migrating to rulesets — bypass behavior differs: branch protection 'Restrict who can push' exempts admins by default; rulesets do not"
|
|
97
|
+
docs:
|
|
98
|
+
- url: 'https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets'
|
|
99
|
+
label: 'GitHub Docs: Available rules for rulesets'
|
|
100
|
+
- url: 'https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/creating-rulesets-for-a-repository#granting-bypass-permissions-for-your-ruleset'
|
|
101
|
+
label: 'GitHub Docs: Granting bypass permissions for a ruleset'
|
|
102
|
+
- url: 'https://github.blog/changelog/2025-01-29-github-rulesets-are-generally-available/'
|
|
103
|
+
label: 'GitHub Changelog: Rulesets generally available — January 2025'
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
id: runner-environment-157
|
|
2
|
+
title: 'setup-python EOL Python version triggers slow pyenv compilation on ubuntu-24.04'
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: warning
|
|
5
|
+
tags:
|
|
6
|
+
- setup-python
|
|
7
|
+
- pyenv
|
|
8
|
+
- ubuntu-24.04
|
|
9
|
+
- python-version
|
|
10
|
+
- toolcache
|
|
11
|
+
- build-time
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'Version \d+\.\d+\.\d+ was not found in the local cache'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'pyenv install python-\d+\.\d+\.\d+'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: 'python-build: .*not installed'
|
|
18
|
+
flags: 'i'
|
|
19
|
+
error_messages:
|
|
20
|
+
- "Version 3.8.20 was not found in the local cache"
|
|
21
|
+
- "Version 3.9.19 was not found in the local cache"
|
|
22
|
+
- "pyenv install python-3.8.20"
|
|
23
|
+
- "python-build: python not found in PATH"
|
|
24
|
+
- "Successfully installed cpython: 3.9.18 (took: 523.19 seconds)"
|
|
25
|
+
root_cause: |
|
|
26
|
+
ubuntu-24.04 runners ship with Python 3.11, 3.12, and 3.13 in the pre-installed
|
|
27
|
+
toolcache. Python 3.8 (EOL October 2024), 3.9, and 3.10 were removed from the
|
|
28
|
+
ubuntu-24.04 toolcache entirely. When actions/setup-python requests one of these
|
|
29
|
+
versions, it cannot find a cached build and falls back to compiling Python from
|
|
30
|
+
source via pyenv. The compilation process — downloading Python source, running
|
|
31
|
+
./configure, make, make install with GCC — typically takes 5–10 minutes and can
|
|
32
|
+
exhaust the default 6-hour job timeout in heavily parallelized pipelines or
|
|
33
|
+
cause unexpectedly slow CI on free-tier runners. The warning "Version X was not
|
|
34
|
+
found in the local cache" is emitted but easy to miss in long logs, and the
|
|
35
|
+
action still exits 0 on success, making the slowdown invisible until CI bills
|
|
36
|
+
or timeout failures appear.
|
|
37
|
+
fix: |
|
|
38
|
+
Option 1 (recommended): Upgrade to a Python version pre-installed on ubuntu-24.04
|
|
39
|
+
(3.11, 3.12, or 3.13). These are available instantly from the toolcache.
|
|
40
|
+
|
|
41
|
+
Option 2: Pin the runner to ubuntu-22.04, which retains Python 3.9 and 3.10
|
|
42
|
+
in the toolcache through its support window.
|
|
43
|
+
|
|
44
|
+
Option 3: Add the deadsnakes PPA before calling setup-python to provide fast
|
|
45
|
+
pre-built binaries for older Python versions on ubuntu-24.
|
|
46
|
+
|
|
47
|
+
Option 4: Use a container image that pre-bundles your Python version to avoid
|
|
48
|
+
the toolcache entirely.
|
|
49
|
+
fix_code:
|
|
50
|
+
- language: yaml
|
|
51
|
+
label: 'Upgrade to a toolcache-available Python version'
|
|
52
|
+
code: |
|
|
53
|
+
- uses: actions/setup-python@v5
|
|
54
|
+
with:
|
|
55
|
+
python-version: '3.12' # Pre-installed on ubuntu-24.04; no pyenv fallback
|
|
56
|
+
- language: yaml
|
|
57
|
+
label: 'Use ubuntu-22.04 runner if 3.9 or 3.10 is required'
|
|
58
|
+
code: |
|
|
59
|
+
jobs:
|
|
60
|
+
test:
|
|
61
|
+
runs-on: ubuntu-22.04 # Retains Python 3.9/3.10 in toolcache
|
|
62
|
+
steps:
|
|
63
|
+
- uses: actions/setup-python@v5
|
|
64
|
+
with:
|
|
65
|
+
python-version: '3.10'
|
|
66
|
+
- language: yaml
|
|
67
|
+
label: 'Deadsnakes PPA for fast pre-built older Python on ubuntu-24.04'
|
|
68
|
+
code: |
|
|
69
|
+
jobs:
|
|
70
|
+
test:
|
|
71
|
+
runs-on: ubuntu-24.04
|
|
72
|
+
steps:
|
|
73
|
+
- name: Add deadsnakes PPA
|
|
74
|
+
run: |
|
|
75
|
+
sudo add-apt-repository ppa:deadsnakes/ppa
|
|
76
|
+
sudo apt-get update
|
|
77
|
+
sudo apt-get install -y python3.9 python3.9-venv python3.9-dev
|
|
78
|
+
- uses: actions/setup-python@v5
|
|
79
|
+
with:
|
|
80
|
+
python-version: '3.9'
|
|
81
|
+
prevention:
|
|
82
|
+
- "Avoid pinning `python-version` to EOL releases (3.8 EOL Oct 2024, 3.9 EOL Oct 2025)"
|
|
83
|
+
- "Check the ubuntu-24.04 runner toolcache inventory at github.com/actions/runner-images for available Python versions"
|
|
84
|
+
- "Use `python-version-file: .python-version` or `pyproject.toml` to track the project's minimum supported version and update it when runners drop EOL toolcache entries"
|
|
85
|
+
- "Set a `timeout-minutes` on the job so pyenv compilation failures surface quickly rather than running for hours"
|
|
86
|
+
docs:
|
|
87
|
+
- url: 'https://github.com/actions/setup-python/issues/726'
|
|
88
|
+
label: 'setup-python: Python 3.8/3.9 not found in toolcache on ubuntu-24.04'
|
|
89
|
+
- url: 'https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md'
|
|
90
|
+
label: 'ubuntu-24.04 runner image readme — pre-installed Python versions'
|
|
91
|
+
- url: 'https://devguide.python.org/versions/'
|
|
92
|
+
label: 'Python release lifecycle — EOL dates by version'
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
id: runner-environment-158
|
|
2
|
+
title: 'Windows MAX_PATH 260-character limit causes npm and build tool failures'
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- windows
|
|
7
|
+
- max-path
|
|
8
|
+
- npm
|
|
9
|
+
- node_modules
|
|
10
|
+
- path-length
|
|
11
|
+
- enoent
|
|
12
|
+
- build
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: 'The filename or extension is too long'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'ENOENT.*node_modules.*node_modules'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
- regex: 'error MSB3095.*path.*too long'
|
|
19
|
+
flags: 'i'
|
|
20
|
+
- regex: 'The system cannot find the path specified'
|
|
21
|
+
flags: 'i'
|
|
22
|
+
error_messages:
|
|
23
|
+
- "The filename or extension is too long."
|
|
24
|
+
- "ENOENT: no such file or directory, open 'C:\\Users\\runner\\work\\..."
|
|
25
|
+
- "error MSB3095: Invalid argument. 'path' is too long."
|
|
26
|
+
- "npm ERR! path C:\\Users\\runner\\work\\..."
|
|
27
|
+
root_cause: |
|
|
28
|
+
Windows enforces a 260-character maximum path length (MAX_PATH) inherited from
|
|
29
|
+
the Win32 API. Deep node_modules dependency trees easily exceed this limit: the
|
|
30
|
+
GitHub-hosted runner workspace is already at
|
|
31
|
+
C:\Users\runner\work\<repository>\<repository>\ (~50 characters) before any
|
|
32
|
+
source files are added. A typical transitive npm dependency path like
|
|
33
|
+
node_modules\pkg\node_modules\sub\node_modules\deep\index.js can push the total
|
|
34
|
+
well past 260 characters. MSBuild, Java build tools, and other Windows toolchains
|
|
35
|
+
have the same limitation.
|
|
36
|
+
|
|
37
|
+
GitHub-hosted Windows runners (windows-2022, windows-latest) have the
|
|
38
|
+
LongPathsEnabled registry key set to 1 at the OS level, but Git must still be
|
|
39
|
+
separately configured with core.longpaths = true, and some Node.js internal APIs
|
|
40
|
+
call the legacy Win32 CreateFile path which ignores the registry opt-in unless
|
|
41
|
+
the application explicitly declares long-path awareness in its executable manifest.
|
|
42
|
+
The result is ENOENT or "path too long" failures that appear to indicate missing
|
|
43
|
+
files rather than a path-length limit.
|
|
44
|
+
fix: |
|
|
45
|
+
Option 1 (most effective): Use a short path: in actions/checkout to reduce the
|
|
46
|
+
base path length. path: a sets the workspace to C:\...\work\repo\a.
|
|
47
|
+
Option 2: Configure Git long paths and use --legacy-peer-deps to flatten
|
|
48
|
+
npm dependency nesting.
|
|
49
|
+
Option 3: Shorten the repository name, which directly reduces the workspace
|
|
50
|
+
path length.
|
|
51
|
+
fix_code:
|
|
52
|
+
- language: yaml
|
|
53
|
+
label: 'Use short checkout path to reduce base path length'
|
|
54
|
+
code: |
|
|
55
|
+
jobs:
|
|
56
|
+
build:
|
|
57
|
+
runs-on: windows-latest
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@v4
|
|
60
|
+
with:
|
|
61
|
+
path: a # Reduces base path by ~20-30 characters vs default
|
|
62
|
+
- run: npm ci
|
|
63
|
+
working-directory: a
|
|
64
|
+
- language: yaml
|
|
65
|
+
label: 'Enable Git long paths and flatten npm tree'
|
|
66
|
+
code: |
|
|
67
|
+
jobs:
|
|
68
|
+
build:
|
|
69
|
+
runs-on: windows-latest
|
|
70
|
+
steps:
|
|
71
|
+
- name: Configure Git long paths
|
|
72
|
+
run: git config --global core.longpaths true
|
|
73
|
+
- uses: actions/checkout@v4
|
|
74
|
+
- name: Install with flattened dependencies
|
|
75
|
+
run: npm ci --legacy-peer-deps
|
|
76
|
+
prevention:
|
|
77
|
+
- 'Use path: a (or another single-char name) in actions/checkout to reduce baseline path length on Windows'
|
|
78
|
+
- 'Keep GitHub repository names short when Windows CI is required'
|
|
79
|
+
- 'Avoid deeply nested workspace directory structures'
|
|
80
|
+
- 'Run npm ci --legacy-peer-deps to reduce node_modules nesting on npm 7+ which introduced deeper trees'
|
|
81
|
+
docs:
|
|
82
|
+
- url: 'https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation'
|
|
83
|
+
label: 'Microsoft Docs: Maximum file path limitation (MAX_PATH)'
|
|
84
|
+
- url: 'https://git-scm.com/docs/git-config#Documentation/git-config.txt-coreprotectNTFS'
|
|
85
|
+
label: 'Git: core.longpaths config'
|
|
86
|
+
- url: 'https://docs.npmjs.com/cli/v10/commands/npm-ci'
|
|
87
|
+
label: 'npm ci — clean install'
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
id: silent-failures-086
|
|
2
|
+
title: 'on.pull_request does not inherit branches filter from sibling on.push trigger'
|
|
3
|
+
category: silent-failures
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- pull_request
|
|
7
|
+
- push
|
|
8
|
+
- branches-filter
|
|
9
|
+
- trigger
|
|
10
|
+
- unexpected-runs
|
|
11
|
+
- filter-inheritance
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'on:\s*\n\s*push:\s*\n\s*branches:\s*\n.*\n\s*pull_request:\s*\n(?!\s*branches:)'
|
|
14
|
+
flags: 'ms'
|
|
15
|
+
error_messages: []
|
|
16
|
+
root_cause: |
|
|
17
|
+
When a workflow defines multiple triggers under on:, each trigger's configuration
|
|
18
|
+
is fully independent — there is no filter inheritance between sibling triggers.
|
|
19
|
+
A common pattern is to restrict on.push to specific branches (e.g., main,
|
|
20
|
+
release/**) while adding on.pull_request with no branches: key, expecting the
|
|
21
|
+
PR trigger to respect the same branch scope.
|
|
22
|
+
|
|
23
|
+
In YAML mapping semantics, on.push.branches: [main] applies exclusively to push
|
|
24
|
+
events. on.pull_request with no branches: key means "trigger for pull requests
|
|
25
|
+
targeting ANY branch in the repository." This causes the workflow to run on every
|
|
26
|
+
PR opened against feature branches, release candidates, or any other branch —
|
|
27
|
+
running expensive CI on PRs the developer intended to exclude.
|
|
28
|
+
|
|
29
|
+
The GitHub Actions UI shows these runs as triggered by pull_request with no
|
|
30
|
+
indication that the branches: filter was missing. The behavior appears correct
|
|
31
|
+
(workflow ran) but occurs on unintended PRs.
|
|
32
|
+
fix: |
|
|
33
|
+
Explicitly add a branches: filter to on.pull_request that defines the target
|
|
34
|
+
branches for which CI should run. Note that on.pull_request.branches matches the
|
|
35
|
+
BASE branch (the branch the PR targets), not the head/feature branch.
|
|
36
|
+
fix_code:
|
|
37
|
+
- language: yaml
|
|
38
|
+
label: 'Explicit branches filter on both triggers'
|
|
39
|
+
code: |
|
|
40
|
+
on:
|
|
41
|
+
push:
|
|
42
|
+
branches: [main, 'release/**']
|
|
43
|
+
pull_request:
|
|
44
|
+
branches: [main, 'release/**'] # Required — NOT inherited from on.push
|
|
45
|
+
jobs:
|
|
46
|
+
ci:
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
steps:
|
|
49
|
+
- run: npm test
|
|
50
|
+
- language: yaml
|
|
51
|
+
label: 'Common mistake — missing branches on pull_request'
|
|
52
|
+
code: |
|
|
53
|
+
# WRONG — pull_request triggers for ALL target branches
|
|
54
|
+
on:
|
|
55
|
+
push:
|
|
56
|
+
branches: [main]
|
|
57
|
+
pull_request: # No branches filter — triggers for every PR
|
|
58
|
+
# CORRECT
|
|
59
|
+
on:
|
|
60
|
+
push:
|
|
61
|
+
branches: [main]
|
|
62
|
+
pull_request:
|
|
63
|
+
branches: [main] # Only PRs targeting main
|
|
64
|
+
prevention:
|
|
65
|
+
- 'Review each trigger block independently — on.push and on.pull_request filters are never shared'
|
|
66
|
+
- 'Add an explicit branches: under on.pull_request whenever you use branches: under on.push'
|
|
67
|
+
- 'Remember: on.pull_request.branches matches the BASE branch of the PR, not the feature branch'
|
|
68
|
+
- 'Use actionlint to validate trigger configurations before committing'
|
|
69
|
+
docs:
|
|
70
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#using-filters'
|
|
71
|
+
label: 'GitHub Docs: Using filters — each trigger is configured independently'
|
|
72
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#onpull_requestpull_request_targetbranchesbranches-ignore'
|
|
73
|
+
label: 'GitHub Actions: pull_request branches filter matches base branch'
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
id: triggers-061
|
|
2
|
+
title: 'on.delete fires for branch and tag deletion — no ref_type filter at trigger level'
|
|
3
|
+
category: triggers
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- delete
|
|
7
|
+
- ref_type
|
|
8
|
+
- branch
|
|
9
|
+
- tag
|
|
10
|
+
- unexpected-runs
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'on:\s*\n\s*delete:'
|
|
13
|
+
flags: 'ms'
|
|
14
|
+
error_messages: []
|
|
15
|
+
root_cause: |
|
|
16
|
+
The on.delete event fires whenever any branch or tag is deleted in the repository.
|
|
17
|
+
Unlike some events that support a types: activity filter, on.delete has no types
|
|
18
|
+
option — there is no trigger-level way to restrict it to branch deletions only or
|
|
19
|
+
tag deletions only. Workflows that perform branch-specific cleanup (removing
|
|
20
|
+
temporary deployment environments, rotating secrets, updating external project
|
|
21
|
+
boards, or archiving feature branch artifacts) run for EVERY tag deletion as well,
|
|
22
|
+
unless an explicit runtime condition is added inside the workflow.
|
|
23
|
+
|
|
24
|
+
The on.create event has the same dual-fire behavior (documented separately). Both
|
|
25
|
+
events expose github.event.ref_type in the workflow context as either 'branch' or
|
|
26
|
+
'tag', but this value is only available inside the workflow body — it cannot be
|
|
27
|
+
used as a trigger-level filter.
|
|
28
|
+
|
|
29
|
+
A common scenario: a workflow cleans up branch-specific cloud environments on
|
|
30
|
+
delete. When a developer deletes the release tag v1.2.3, the workflow fires
|
|
31
|
+
unexpectedly — potentially tearing down a production environment that was deployed
|
|
32
|
+
from that tag.
|
|
33
|
+
fix: |
|
|
34
|
+
Add an if: condition using github.event.ref_type to guard jobs or steps that
|
|
35
|
+
should only execute for one type of deletion. Use 'branch' or 'tag' as the
|
|
36
|
+
comparison value.
|
|
37
|
+
fix_code:
|
|
38
|
+
- language: yaml
|
|
39
|
+
label: 'Guard cleanup by ref_type at the job level'
|
|
40
|
+
code: |
|
|
41
|
+
on:
|
|
42
|
+
delete:
|
|
43
|
+
jobs:
|
|
44
|
+
cleanup-branch-environment:
|
|
45
|
+
# Only run for branch deletions — skip tag deletions
|
|
46
|
+
if: github.event.ref_type == 'branch'
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
steps:
|
|
49
|
+
- name: Remove branch-specific deployment
|
|
50
|
+
run: echo "Cleaning up env for branch ${{ github.event.ref }}"
|
|
51
|
+
- language: yaml
|
|
52
|
+
label: 'Separate jobs for branch vs tag deletion'
|
|
53
|
+
code: |
|
|
54
|
+
on:
|
|
55
|
+
delete:
|
|
56
|
+
jobs:
|
|
57
|
+
cleanup-branch:
|
|
58
|
+
if: github.event.ref_type == 'branch'
|
|
59
|
+
runs-on: ubuntu-latest
|
|
60
|
+
steps:
|
|
61
|
+
- run: echo "Branch deleted ${{ github.event.ref }}"
|
|
62
|
+
cleanup-tag:
|
|
63
|
+
if: github.event.ref_type == 'tag'
|
|
64
|
+
runs-on: ubuntu-latest
|
|
65
|
+
steps:
|
|
66
|
+
- run: echo "Tag deleted ${{ github.event.ref }}"
|
|
67
|
+
prevention:
|
|
68
|
+
- 'Always guard on.delete workflow jobs with if: github.event.ref_type == ''branch'' or ''tag'''
|
|
69
|
+
- 'Be aware that on.create has the same behavior — both create and delete fire for branches and tags'
|
|
70
|
+
- 'Test delete workflows by deleting both a branch and a tag to verify they behave as expected'
|
|
71
|
+
docs:
|
|
72
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#delete'
|
|
73
|
+
label: 'GitHub Docs: delete event — fires for branches and tags'
|
|
74
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/contexts#github-context'
|
|
75
|
+
label: 'GitHub Docs: github.event.ref_type context'
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
id: triggers-062
|
|
2
|
+
title: 'on.pull_request_review fires for all review types (submitted, edited, dismissed) when types is omitted'
|
|
3
|
+
category: triggers
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- pull_request_review
|
|
7
|
+
- review
|
|
8
|
+
- types
|
|
9
|
+
- dismissed
|
|
10
|
+
- submitted
|
|
11
|
+
- unexpected-runs
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'on:\s*\n\s*pull_request_review:\s*\n(?!\s*types:)'
|
|
14
|
+
flags: 'ms'
|
|
15
|
+
error_messages: []
|
|
16
|
+
root_cause: |
|
|
17
|
+
The pull_request_review event fires for three activity types:
|
|
18
|
+
- submitted: a new review is posted (approved, changes_requested, or commented)
|
|
19
|
+
- edited: a reviewer edits their review comment text
|
|
20
|
+
- dismissed: an existing approval or changes_requested review is dismissed
|
|
21
|
+
|
|
22
|
+
When on.pull_request_review: is specified without a types: filter, GitHub fires
|
|
23
|
+
the workflow for ALL three activity types. Developers typically use this event to
|
|
24
|
+
trigger a deployment or notification on PR approval. Without types: [submitted],
|
|
25
|
+
the workflow also runs when a reviewer edits their comment spelling or when an
|
|
26
|
+
approval is dismissed by a maintainer — often causing incorrect or failed workflow
|
|
27
|
+
runs in contexts where the PR is no longer in an approved state.
|
|
28
|
+
|
|
29
|
+
This behavior mirrors on.pull_request without types: (which fires for opened,
|
|
30
|
+
synchronize, and reopened by default) but is arguably more surprising because
|
|
31
|
+
"editing a review comment" and "dismissing a review" are far less common
|
|
32
|
+
developer actions than submitting a new review.
|
|
33
|
+
fix: |
|
|
34
|
+
Add types: [submitted] to restrict the trigger to new review submissions.
|
|
35
|
+
If you only want to react to approvals specifically, also add an if: condition
|
|
36
|
+
checking github.event.review.state == 'approved'.
|
|
37
|
+
fix_code:
|
|
38
|
+
- language: yaml
|
|
39
|
+
label: 'Restrict to submitted reviews only'
|
|
40
|
+
code: |
|
|
41
|
+
on:
|
|
42
|
+
pull_request_review:
|
|
43
|
+
types: [submitted] # Only new review submissions — not edited or dismissed
|
|
44
|
+
jobs:
|
|
45
|
+
notify-on-review:
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
steps:
|
|
48
|
+
- run: echo "Review state ${{ github.event.review.state }}"
|
|
49
|
+
- language: yaml
|
|
50
|
+
label: 'Trigger only on PR approvals'
|
|
51
|
+
code: |
|
|
52
|
+
on:
|
|
53
|
+
pull_request_review:
|
|
54
|
+
types: [submitted]
|
|
55
|
+
jobs:
|
|
56
|
+
deploy-on-approval:
|
|
57
|
+
if: github.event.review.state == 'approved'
|
|
58
|
+
runs-on: ubuntu-latest
|
|
59
|
+
steps:
|
|
60
|
+
- run: echo "PR approved — proceeding with staging deploy"
|
|
61
|
+
prevention:
|
|
62
|
+
- 'Always specify types: [submitted] under on.pull_request_review unless dismissed or edited is explicitly needed'
|
|
63
|
+
- 'Combine types: [submitted] with if: github.event.review.state == ''approved'' for approval-gated workflows'
|
|
64
|
+
- 'Test pull_request_review workflows by also dismissing reviews to ensure unexpected runs are avoided'
|
|
65
|
+
docs:
|
|
66
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request_review'
|
|
67
|
+
label: 'GitHub Docs: pull_request_review event — activity types'
|
|
68
|
+
- url: 'https://docs.github.com/en/webhooks/webhook-events-and-payloads#pull_request_review'
|
|
69
|
+
label: 'GitHub Webhooks: pull_request_review payload — review.state values'
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
id: yaml-syntax-057
|
|
2
|
+
title: 'needs: referencing undefined job ID causes instant workflow validation failure'
|
|
3
|
+
category: yaml-syntax
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- needs
|
|
7
|
+
- job-id
|
|
8
|
+
- validation
|
|
9
|
+
- typo
|
|
10
|
+
- workflow-syntax
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: "Job '.*' depends on unknown job '.*'"
|
|
13
|
+
flags: 'i'
|
|
14
|
+
- regex: "A job named '.*' does not exist in this workflow"
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'The workflow is not valid.*depends on unknown job'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
error_messages:
|
|
19
|
+
- "The workflow is not valid. .github/workflows/ci.yml (Line 42, Col 14): Job 'deploy' depends on unknown job 'biuld'."
|
|
20
|
+
- "A job named 'biuld' does not exist in this workflow."
|
|
21
|
+
- "Job 'release' depends on unknown job 'test-and-build'."
|
|
22
|
+
- "The workflow is not valid. .github/workflows/release.yml: Job 'publish' depends on unknown job 'build_and_test'."
|
|
23
|
+
root_cause: |
|
|
24
|
+
The `needs:` key in a job definition must exactly reference the IDs of other jobs
|
|
25
|
+
defined under `jobs:` in the same workflow file. Job IDs are the YAML map keys
|
|
26
|
+
(e.g., `jobs.build:`, `jobs.test:`), not the `name:` display values.
|
|
27
|
+
|
|
28
|
+
A typo in a `needs:` value (e.g., `needs: [biuld]` instead of `needs: [build]`,
|
|
29
|
+
or `needs: test-and-build` when the job is named `test_and_build`) causes GitHub
|
|
30
|
+
Actions to reject the entire workflow at parse time with a validation error.
|
|
31
|
+
No jobs run — the workflow fails before any step executes.
|
|
32
|
+
|
|
33
|
+
This error is particularly common after renaming jobs, since the `name:` field
|
|
34
|
+
(display name in the UI) can be changed without affecting the job ID used in
|
|
35
|
+
`needs:`. Developers who update `name:` but forget to update downstream `needs:`
|
|
36
|
+
references see the workflow fail immediately on next push with no prior warning.
|
|
37
|
+
fix: |
|
|
38
|
+
Ensure every value in `needs:` exactly matches a job ID key defined at the
|
|
39
|
+
same level under `jobs:`. Job IDs are case-sensitive and use the exact YAML key
|
|
40
|
+
name — not the `name:` display value.
|
|
41
|
+
|
|
42
|
+
Use `actionlint` locally or in pre-commit hooks to catch unknown `needs:` references
|
|
43
|
+
before pushing.
|
|
44
|
+
fix_code:
|
|
45
|
+
- language: yaml
|
|
46
|
+
label: 'Correct needs: to match the exact job ID key'
|
|
47
|
+
code: |
|
|
48
|
+
jobs:
|
|
49
|
+
build: # <-- This is the job ID (the YAML key)
|
|
50
|
+
name: Build and Test # This is the display name — NOT used in needs:
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
steps:
|
|
53
|
+
- run: echo "building"
|
|
54
|
+
|
|
55
|
+
deploy:
|
|
56
|
+
needs: [build] # Must reference the job ID key, not the name: value
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
steps:
|
|
59
|
+
- run: echo "deploying"
|
|
60
|
+
- language: yaml
|
|
61
|
+
label: 'Rename both job ID and needs: reference after a job rename'
|
|
62
|
+
code: |
|
|
63
|
+
# WRONG — job was renamed from 'build' to 'build-and-test' but needs: not updated
|
|
64
|
+
# jobs:
|
|
65
|
+
# build-and-test:
|
|
66
|
+
# ...
|
|
67
|
+
# deploy:
|
|
68
|
+
# needs: [build] # Error: 'build' no longer exists
|
|
69
|
+
|
|
70
|
+
# CORRECT — update needs: to match the new job ID
|
|
71
|
+
jobs:
|
|
72
|
+
build-and-test:
|
|
73
|
+
runs-on: ubuntu-latest
|
|
74
|
+
steps:
|
|
75
|
+
- run: echo "building"
|
|
76
|
+
|
|
77
|
+
deploy:
|
|
78
|
+
needs: [build-and-test] # Updated to match renamed job ID
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
steps:
|
|
81
|
+
- run: echo "deploying"
|
|
82
|
+
prevention:
|
|
83
|
+
- "Use `actionlint` (rhysd/actionlint) locally or as a pre-commit hook — it validates `needs:` references against defined job IDs at lint time"
|
|
84
|
+
- "Keep job IDs short and stable (e.g., `build`, `test`, `deploy`); use the `name:` field for human-readable display names that can be changed freely"
|
|
85
|
+
- "When renaming a job ID, search the entire workflow file for all `needs:` references to that ID before committing"
|
|
86
|
+
- "Enable the actionlint GitHub Actions workflow check in your repository to catch validation errors in PRs before merge"
|
|
87
|
+
docs:
|
|
88
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idneeds'
|
|
89
|
+
label: 'GitHub Docs: jobs.<job_id>.needs syntax'
|
|
90
|
+
- url: 'https://rhysd.github.io/actionlint/'
|
|
91
|
+
label: 'actionlint — static checker for GitHub Actions workflow files'
|
|
92
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idname'
|
|
93
|
+
label: 'GitHub Docs: jobs.<job_id>.name vs job ID distinction'
|
package/package.json
CHANGED