@htekdev/actions-debugger 1.0.0 → 1.0.1

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.
Files changed (53) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +108 -108
  3. package/errors/_schema.json +89 -89
  4. package/errors/caching-artifacts/artifact-storage-quota-exceeded.yml +118 -0
  5. package/errors/caching-artifacts/cache-miss.yml +56 -56
  6. package/errors/caching-artifacts/cache-save-cancelled-job.yml +82 -0
  7. package/errors/caching-artifacts/cache-v3-to-v4-breaking-changes.yml +95 -0
  8. package/errors/caching-artifacts/cross-repo-artifacts-not-supported.yml +102 -0
  9. package/errors/caching-artifacts/upload-artifact-no-files-found.yml +92 -0
  10. package/errors/caching-artifacts/upload-artifact-v4-breaking.yml +67 -67
  11. package/errors/concurrency-timing/cancel-in-progress-deploy-drops.yml +97 -0
  12. package/errors/concurrency-timing/jobs-cancelled-unexpectedly.yml +60 -60
  13. package/errors/concurrency-timing/skipped-needs-cascade.yml +103 -0
  14. package/errors/concurrency-timing/workflow-run-conclusion-unchecked.yml +100 -0
  15. package/errors/known-unsolved/composite-input-env-vars-missing.yml +91 -0
  16. package/errors/known-unsolved/composite-nested-outputs-null.yml +101 -0
  17. package/errors/known-unsolved/no-dynamic-secret-access.yml +111 -0
  18. package/errors/known-unsolved/no-step-level-rerun.yml +94 -0
  19. package/errors/known-unsolved/no-step-retry.yml +53 -53
  20. package/errors/permissions-auth/checkout-submodule-private-auth.yml +91 -0
  21. package/errors/permissions-auth/fork-pr-secrets-unavailable.yml +97 -0
  22. package/errors/permissions-auth/github-token-403.yml +64 -64
  23. package/errors/permissions-auth/github-token-protected-branch-push.yml +109 -0
  24. package/errors/permissions-auth/oidc-aws-failure.yml +85 -85
  25. package/errors/permissions-auth/oidc-azure-subject-mismatch.yml +91 -0
  26. package/errors/runner-environment/disk-space.yml +57 -57
  27. package/errors/runner-environment/docker-buildx-not-setup.yml +106 -0
  28. package/errors/runner-environment/macos-homebrew-path.yml +90 -0
  29. package/errors/runner-environment/node-runtime-deprecation.yml +56 -56
  30. package/errors/runner-environment/npm-ci-lockfile-mismatch.yml +112 -0
  31. package/errors/runner-environment/self-hosted-stale-toolcache.yml +73 -0
  32. package/errors/runner-environment/setup-node-version-file-missing.yml +105 -0
  33. package/errors/runner-environment/windows-execution-policy.yml +83 -0
  34. package/errors/silent-failures/add-mask-no-retroactive-masking.yml +75 -0
  35. package/errors/silent-failures/composite-boolean-inputs-as-strings.yml +110 -0
  36. package/errors/silent-failures/conditional-output-null-downstream.yml +82 -0
  37. package/errors/silent-failures/continue-on-error-masks-failure.yml +86 -0
  38. package/errors/silent-failures/github-token-no-trigger.yml +57 -57
  39. package/errors/silent-failures/reusable-workflow-env-secrets-empty.yml +90 -0
  40. package/errors/silent-failures/scheduled-workflow-disabled.yml +59 -59
  41. package/errors/triggers/cron-schedule-late.yml +59 -59
  42. package/errors/triggers/pull-request-target-rce-risk.yml +117 -0
  43. package/errors/triggers/workflow-not-triggering.yml +60 -60
  44. package/errors/triggers/workflow-run-default-branch-requirement.yml +78 -0
  45. package/errors/yaml-syntax/anchors-not-supported.yml +95 -0
  46. package/errors/yaml-syntax/dynamic-matrix-fromjson-failure.yml +99 -0
  47. package/errors/yaml-syntax/if-always-true.yml +52 -52
  48. package/errors/yaml-syntax/missing-expression-wrapper.yml +67 -0
  49. package/errors/yaml-syntax/needs-indirect-outputs.yml +91 -0
  50. package/errors/yaml-syntax/secrets-in-if.yml +55 -55
  51. package/errors/yaml-syntax/unexpected-yaml-key.yml +69 -69
  52. package/errors/yaml-syntax/working-directory-ignored-on-uses.yml +66 -0
  53. package/package.json +70 -67
@@ -0,0 +1,90 @@
1
+ id: runner-environment-011
2
+ title: "macOS Runner Homebrew Binaries Not on PATH After brew install"
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - macos
7
+ - homebrew
8
+ - PATH
9
+ - runner
10
+ - shell
11
+ - binary
12
+ patterns:
13
+ - regex: "command not found.*brew"
14
+ flags: "i"
15
+ - regex: "brew: command not found"
16
+ flags: "i"
17
+ - regex: "/opt/homebrew/bin.*not found"
18
+ flags: "i"
19
+ - regex: "zsh: command not found"
20
+ flags: "i"
21
+ error_messages:
22
+ - "zsh: command not found: <tool>"
23
+ - "Error: Process completed with exit code 127."
24
+ - "/usr/bin/env: '<tool>': No such file or directory"
25
+ root_cause: |
26
+ GitHub Actions macOS runners (including `macos-14` and `macos-15` on Apple Silicon)
27
+ use zsh as the default shell. Homebrew installs binaries to `/opt/homebrew/bin` on
28
+ Apple Silicon (`macos-14`+) and `/usr/local/bin` on Intel (`macos-13`), but these
29
+ paths are not always added to `$PATH` for subsequent steps automatically.
30
+
31
+ When a step runs `brew install sometool` and then a **later step** attempts to use
32
+ `sometool`, the binary may not be on `$PATH` because Homebrew's shellenv was never
33
+ sourced into the Actions runner's shell environment.
34
+
35
+ Additionally, `macos-14` moved to Apple Silicon, changing the Homebrew prefix from
36
+ `/usr/local` to `/opt/homebrew`, which breaks hardcoded path assumptions in scripts
37
+ that worked on `macos-13`.
38
+ fix: |
39
+ After installing with Homebrew, explicitly add the binary path to `$GITHUB_PATH`
40
+ (which persists across subsequent steps in the same job). Alternatively, use
41
+ `brew --prefix` to get the correct path regardless of architecture.
42
+ fix_code:
43
+ - language: yaml
44
+ label: "WRONG — tool installed but not accessible in next step"
45
+ code: |
46
+ jobs:
47
+ build:
48
+ runs-on: macos-latest
49
+ steps:
50
+ - name: Install tool
51
+ run: brew install sometool
52
+
53
+ - name: Use tool
54
+ run: sometool --version # Error: zsh: command not found: sometool
55
+ - language: yaml
56
+ label: "CORRECT — add brew prefix to GITHUB_PATH"
57
+ code: |
58
+ jobs:
59
+ build:
60
+ runs-on: macos-latest
61
+ steps:
62
+ - name: Install tool
63
+ run: |
64
+ brew install sometool
65
+ # Add homebrew bin to path for all subsequent steps
66
+ echo "$(brew --prefix)/bin" >> $GITHUB_PATH
67
+
68
+ - name: Use tool
69
+ run: sometool --version # works
70
+ - language: yaml
71
+ label: "CORRECT — source shellenv in a single step"
72
+ code: |
73
+ jobs:
74
+ build:
75
+ runs-on: macos-latest
76
+ steps:
77
+ - name: Install and run in same step
78
+ run: |
79
+ brew install sometool
80
+ eval "$(brew shellenv)"
81
+ sometool --version
82
+ prevention:
83
+ - "After `brew install`, append `$(brew --prefix)/bin` to `$GITHUB_PATH` to persist it across steps."
84
+ - "Use `brew --prefix <formula>` to get formula-specific paths rather than hardcoding `/usr/local` or `/opt/homebrew`."
85
+ - "When upgrading from `macos-13` to `macos-14`+, audit any hardcoded `/usr/local` paths for the Homebrew prefix change."
86
+ docs:
87
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#adding-a-system-path"
88
+ label: "Adding a system path (GITHUB_PATH)"
89
+ - url: "https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources"
90
+ label: "GitHub-hosted runners — supported environments"
@@ -1,56 +1,56 @@
1
- id: runner-environment-009
2
- title: "Node.js Runtime Deprecation"
3
- category: runner-environment
4
- severity: warning
5
- tags:
6
- - node
7
- - runtime
8
- - deprecation
9
- - marketplace-actions
10
- - compatibility
11
- patterns:
12
- - regex: "Node\\.js 16 actions are deprecated"
13
- flags: "i"
14
- - regex: "Please update the following actions to use Node\\.js 20"
15
- flags: "i"
16
- - regex: "runs using Node 16 are deprecated"
17
- flags: "i"
18
- error_messages:
19
- - "Node.js 16 actions are deprecated."
20
- - "Please update the following actions to use Node.js 20."
21
- root_cause: |
22
- Some marketplace actions bundle a Node.js runtime. When GitHub deprecates an older
23
- runtime such as Node 16, workflows can start emitting warnings or eventually fail if the
24
- referenced action version has not been updated.
25
-
26
- This is usually caused by pinning an old major version of an action long after the runner
27
- platform has moved on.
28
- fix: |
29
- Upgrade the affected action to a maintained version that uses the current supported Node
30
- runtime. Review pinned SHAs and major versions for checkout, setup, artifact, and cache
31
- actions first because they are common sources of these warnings.
32
- fix_code:
33
- - language: yaml
34
- label: "Upgrade action versions to Node 20-compatible releases"
35
- code: |
36
- steps:
37
- - uses: actions/checkout@v4
38
- - uses: actions/setup-node@v4
39
- with:
40
- node-version: 20
41
- - uses: actions/upload-artifact@v4
42
- with:
43
- name: build-output
44
- path: dist/
45
- prevention:
46
- - "Review GitHub Actions deprecation notices and keep marketplace action versions current."
47
- - "Prefer supported major versions from official `actions/*` repositories."
48
- - "Audit pinned SHAs periodically so old runtimes do not linger unnoticed."
49
- docs:
50
- - url: "https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-javascript-actions"
51
- label: "JavaScript action runtime metadata"
52
- - url: "https://docs.github.com/en/actions/automating-your-workflow-with-github-actions/metadata-syntax-for-github-actions"
53
- label: "Metadata syntax for GitHub Actions"
54
- source:
55
- article: "https://htek.dev/articles/github-actions-debugging-guide"
56
- section: "Node runtime deprecation warnings"
1
+ id: runner-environment-009
2
+ title: "Node.js Runtime Deprecation"
3
+ category: runner-environment
4
+ severity: warning
5
+ tags:
6
+ - node
7
+ - runtime
8
+ - deprecation
9
+ - marketplace-actions
10
+ - compatibility
11
+ patterns:
12
+ - regex: "Node\\.js 16 actions are deprecated"
13
+ flags: "i"
14
+ - regex: "Please update the following actions to use Node\\.js 20"
15
+ flags: "i"
16
+ - regex: "runs using Node 16 are deprecated"
17
+ flags: "i"
18
+ error_messages:
19
+ - "Node.js 16 actions are deprecated."
20
+ - "Please update the following actions to use Node.js 20."
21
+ root_cause: |
22
+ Some marketplace actions bundle a Node.js runtime. When GitHub deprecates an older
23
+ runtime such as Node 16, workflows can start emitting warnings or eventually fail if the
24
+ referenced action version has not been updated.
25
+
26
+ This is usually caused by pinning an old major version of an action long after the runner
27
+ platform has moved on.
28
+ fix: |
29
+ Upgrade the affected action to a maintained version that uses the current supported Node
30
+ runtime. Review pinned SHAs and major versions for checkout, setup, artifact, and cache
31
+ actions first because they are common sources of these warnings.
32
+ fix_code:
33
+ - language: yaml
34
+ label: "Upgrade action versions to Node 20-compatible releases"
35
+ code: |
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+ - uses: actions/setup-node@v4
39
+ with:
40
+ node-version: 20
41
+ - uses: actions/upload-artifact@v4
42
+ with:
43
+ name: build-output
44
+ path: dist/
45
+ prevention:
46
+ - "Review GitHub Actions deprecation notices and keep marketplace action versions current."
47
+ - "Prefer supported major versions from official `actions/*` repositories."
48
+ - "Audit pinned SHAs periodically so old runtimes do not linger unnoticed."
49
+ docs:
50
+ - url: "https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-javascript-actions"
51
+ label: "JavaScript action runtime metadata"
52
+ - url: "https://docs.github.com/en/actions/automating-your-workflow-with-github-actions/metadata-syntax-for-github-actions"
53
+ label: "Metadata syntax for GitHub Actions"
54
+ source:
55
+ article: "https://htek.dev/articles/github-actions-debugging-guide"
56
+ section: "Node runtime deprecation warnings"
@@ -0,0 +1,112 @@
1
+ id: runner-environment-015
2
+ title: "npm ci Fails with Lockfile Mismatch or Missing package-lock.json"
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - npm
7
+ - npm-ci
8
+ - lockfile
9
+ - package-lock.json
10
+ - dependencies
11
+ - node
12
+ - reproducible
13
+ patterns:
14
+ - regex: "npm ci.*can only install.*package-lock\\.json"
15
+ flags: "i"
16
+ - regex: "Missing script.*ci"
17
+ flags: "i"
18
+ - regex: "npm ERR! code EUSAGE"
19
+ flags: "i"
20
+ - regex: "npm warn saveError ENOENT.*package-lock\\.json"
21
+ flags: "i"
22
+ - regex: "npm ERR!.*lock file.*older npm"
23
+ flags: "i"
24
+ - regex: "EBADENGINE"
25
+ flags: "i"
26
+ error_messages:
27
+ - "npm error The `npm ci` command can only install with an existing package-lock.json"
28
+ - "npm warn saveError ENOENT: no such file or directory, open '/home/runner/work/.../package-lock.json'"
29
+ - "npm error `npm ci` can only install packages when your package.json and package-lock.json are in sync."
30
+ - "npm error Missing: <package>@<version> from lock file"
31
+ root_cause: |
32
+ `npm ci` is strict by design — it requires `package-lock.json` to be present and
33
+ exactly in sync with `package.json`. It fails in several common CI scenarios:
34
+
35
+ 1. **No lockfile committed** — developers add `package-lock.json` to `.gitignore`
36
+ (common in library repos) — `npm ci` refuses to run.
37
+
38
+ 2. **Lockfile out of sync** — a developer ran `npm install` locally which updated
39
+ the lockfile, but committed `package.json` without the updated lockfile, or vice versa.
40
+ `npm ci` reports "Missing: package@version from lock file."
41
+
42
+ 3. **Lockfile from incompatible npm version** — npm v6 lockfiles (lockfileVersion 1)
43
+ cannot be used with `npm ci` in npm v7+ projects that use workspaces, and vice versa.
44
+
45
+ 4. **Monorepo workspace packages not locked** — `package-lock.json` at root does not
46
+ lock workspace packages listed in `packages/*` if each sub-package has its own
47
+ `package.json` without being part of the root workspaces config.
48
+ fix: |
49
+ Commit `package-lock.json` to the repository (do not gitignore it in apps). Keep
50
+ `package.json` and `package-lock.json` in sync by running `npm install` locally
51
+ after any manifest change and committing both files together.
52
+ fix_code:
53
+ - language: yaml
54
+ label: "CORRECT — npm ci with Node version matrix and lockfile caching"
55
+ code: |
56
+ jobs:
57
+ test:
58
+ runs-on: ubuntu-latest
59
+ strategy:
60
+ matrix:
61
+ node-version: ['18.x', '20.x']
62
+ steps:
63
+ - uses: actions/checkout@v4
64
+
65
+ - uses: actions/setup-node@v4
66
+ with:
67
+ node-version: ${{ matrix.node-version }}
68
+ cache: npm # caches ~/.npm using package-lock.json hash
69
+
70
+ - name: Install dependencies
71
+ run: npm ci # fails fast if lockfile is out of sync
72
+
73
+ - name: Run tests
74
+ run: npm test
75
+ - language: yaml
76
+ label: "Detect lockfile sync issues before CI"
77
+ code: |
78
+ steps:
79
+ - uses: actions/checkout@v4
80
+ - uses: actions/setup-node@v4
81
+ with:
82
+ node-version: 20
83
+
84
+ - name: Verify lockfile is up to date
85
+ run: |
86
+ npm install --package-lock-only
87
+ git diff --exit-code package-lock.json || {
88
+ echo "::error::package-lock.json is out of sync with package.json"
89
+ echo "Run 'npm install' locally and commit the updated lockfile"
90
+ exit 1
91
+ }
92
+
93
+ - run: npm ci
94
+ - language: bash
95
+ label: "Fix gitignore — ensure lockfile is tracked"
96
+ code: |
97
+ # If package-lock.json is gitignored, remove it from .gitignore
98
+ grep -v "package-lock.json" .gitignore > .gitignore.tmp && mv .gitignore.tmp .gitignore
99
+ git add package-lock.json
100
+ git commit -m "chore: track package-lock.json for reproducible CI"
101
+ prevention:
102
+ - "Always commit `package-lock.json` to git — never gitignore it in application repos."
103
+ - "Run `npm install` (not just `npm ci`) locally after any `package.json` change and commit both files atomically."
104
+ - "Add a `Verify lockfile` step to CI that runs `npm install --package-lock-only && git diff --exit-code package-lock.json` to catch drift early."
105
+ - "Renovate Bot and Dependabot automatically keep lockfiles in sync when configured correctly."
106
+ docs:
107
+ - url: "https://docs.npmjs.com/cli/v10/commands/npm-ci"
108
+ label: "npm ci (npmjs docs)"
109
+ - url: "https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#caching-npm-packages"
110
+ label: "Caching npm packages"
111
+ - url: "https://github.com/actions/setup-node#caching-global-packages-data"
112
+ label: "actions/setup-node — npm caching"
@@ -0,0 +1,73 @@
1
+ id: runner-environment-013
2
+ title: "Self-Hosted Runner Stale Tool Cache Serves Outdated Versions"
3
+ category: runner-environment
4
+ severity: silent-failure
5
+ tags:
6
+ - self-hosted
7
+ - tool-cache
8
+ - setup-node
9
+ - setup-python
10
+ - setup-java
11
+ - outdated
12
+ - toolcache
13
+ patterns:
14
+ - regex: "Found in cache"
15
+ flags: "i"
16
+ - regex: "Resolved .* from tool-cache"
17
+ flags: "i"
18
+ - regex: "Tool cache hit.*[0-9]+\\.[0-9]+"
19
+ flags: "i"
20
+ error_messages:
21
+ - "Found in cache @ /opt/hostedtoolcache/node/18.12.0/x64"
22
+ - "Resolved Node 18.12.0 from tool-cache"
23
+ root_cause: |
24
+ `actions/setup-node`, `actions/setup-python`, `actions/setup-java`, and similar setup
25
+ actions maintain a **tool cache** on the runner host. On GitHub-hosted runners this
26
+ cache is wiped between jobs (fresh VMs), but on **self-hosted runners** the cache
27
+ persists indefinitely across runs.
28
+
29
+ When a self-hosted runner's tool cache has a matching version range (e.g., `node-version: 18.x`)
30
+ it returns the cached version without downloading a fresh copy. If that cached version
31
+ contains a security vulnerability or a bug that was patched in a newer patch release,
32
+ workflows silently continue using the vulnerable version. There is no warning — the log
33
+ shows "Found in cache" and proceeds.
34
+
35
+ This also happens when teams pin to `18.x` intending to get the latest 18 minor but the
36
+ cache serves the version that was first downloaded months ago.
37
+ fix: |
38
+ Pin to exact versions in production workflows. Periodically purge the tool cache on
39
+ self-hosted runners. Use the `check-latest` input to force setup actions to verify
40
+ whether a newer patch release is available.
41
+ fix_code:
42
+ - language: yaml
43
+ label: "WRONG — loose version range silently serves cached old version"
44
+ code: |
45
+ steps:
46
+ - uses: actions/setup-node@v4
47
+ with:
48
+ node-version: 18 # resolves to whatever 18.x is in cache
49
+ - language: yaml
50
+ label: "CORRECT — pin exact version for reproducibility"
51
+ code: |
52
+ steps:
53
+ - uses: actions/setup-node@v4
54
+ with:
55
+ node-version: '18.20.4' # exact version, cache miss forces fresh download
56
+ - language: yaml
57
+ label: "CORRECT — use check-latest to force freshness check"
58
+ code: |
59
+ steps:
60
+ - uses: actions/setup-node@v4
61
+ with:
62
+ node-version: '18.x'
63
+ check-latest: true # verifies cache against upstream, downloads if newer available
64
+ prevention:
65
+ - "Pin to exact tool versions (`18.20.4` not `18.x`) on self-hosted runners to ensure cache hits are intentional."
66
+ - "Schedule periodic purges of `/opt/hostedtoolcache` (or Windows equivalent) on self-hosted runners."
67
+ - "Use `check-latest: true` on self-hosted runners when using semver ranges."
68
+ - "Document your self-hosted runner's tool cache contents and last purge date."
69
+ docs:
70
+ - url: "https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners"
71
+ label: "About self-hosted runners"
72
+ - url: "https://github.com/actions/setup-node#check-latest-version"
73
+ label: "actions/setup-node — check-latest input"
@@ -0,0 +1,105 @@
1
+ id: runner-environment-010
2
+ title: "actions/setup-node Fails When .nvmrc or node-version-file Is Missing"
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - setup-node
7
+ - nvmrc
8
+ - node-version
9
+ - node-version-file
10
+ - version-resolution
11
+ patterns:
12
+ - regex: "The specified node version file at.*does not exist"
13
+ flags: "i"
14
+ - regex: "Unable to find Node version '\\$\\{.*\\}'"
15
+ flags: "i"
16
+ - regex: "Unable to find Node version '.*' for platform"
17
+ flags: "i"
18
+ - regex: "Cache service responded with 422"
19
+ flags: "i"
20
+ error_messages:
21
+ - "The specified node version file at: /__w/actions/actions/.nvmrc does not exist"
22
+ - "##[error]Unable to find Node version '${NVMRC}' for platform linux and architecture x64."
23
+ - "##[error]Unable to find Node version '16.99.0' for platform linux and architecture x64."
24
+ - "Error: Cache service responded with 422"
25
+ root_cause: |
26
+ `actions/setup-node` supports three ways to specify a Node.js version:
27
+ `node-version` (inline), `node-version-file` (reads from a file), or auto-detection.
28
+ These fail in distinct ways:
29
+
30
+ 1. **Missing version file** (`node-version-file: '.nvmrc'` or `'.node-version'`):
31
+ If the file referenced by `node-version-file` does not exist on the runner at the
32
+ path provided, setup-node throws "The specified node version file … does not exist"
33
+ and the step fails. This commonly happens when the file exists in the repo root but
34
+ the workflow runs in a subdirectory, or when the checkout step runs after setup-node.
35
+
36
+ 2. **Unresolved environment variable** (`node-version: '${{ env.NVMRC }}'`):
37
+ Using a shell env var (e.g., `$NVMRC`) instead of an Actions expression
38
+ (`${{ env.NVMRC }}`) means the value is never substituted — setup-node receives a
39
+ literal `${NVMRC}` string, which is not a valid version, and fails with "Unable to
40
+ find Node version '${NVMRC}'". Similarly, if `env.NVMRC` is not set at the point
41
+ setup-node runs, the expression evaluates to empty string.
42
+
43
+ 3. **Non-existent or misspelled version** (`node-version: '16.99.0'`):
44
+ Requesting a version that GitHub's node distribution manifest does not list causes
45
+ "Unable to find Node version." This can happen after pinning to a patch version
46
+ that was later delisted.
47
+
48
+ 4. **Old setup-node version + cache service 422**:
49
+ Older setup-node versions (v1/v2) use a deprecated cache service API that now
50
+ returns HTTP 422. The fix is upgrading to setup-node@v3 or v4.
51
+ fix: |
52
+ 1. Ensure `actions/checkout` runs **before** any `actions/setup-node` step that reads
53
+ `node-version-file` — the file must exist on the runner when setup-node reads it.
54
+ 2. Use Actions expressions (`${{ env.VAR }}`) not shell syntax (`$VAR`) for
55
+ `node-version` values.
56
+ 3. For `.nvmrc`, prefer the `node-version-file: '.nvmrc'` parameter directly rather
57
+ than reading the file in a shell step and passing it to `node-version`.
58
+ 4. Upgrade to `actions/setup-node@v4` to avoid the deprecated cache service 422 error.
59
+ fix_code:
60
+ - language: yaml
61
+ label: "Correct order: checkout before setup-node with node-version-file"
62
+ code: |
63
+ steps:
64
+ - uses: actions/checkout@v4 # Must come BEFORE setup-node
65
+ - uses: actions/setup-node@v4
66
+ with:
67
+ node-version-file: '.nvmrc' # Reads .nvmrc from the checked-out repo
68
+ cache: 'npm'
69
+ - language: yaml
70
+ label: "Inline version — use Actions expression, not shell variable"
71
+ code: |
72
+ env:
73
+ NODE_VERSION: '20'
74
+
75
+ steps:
76
+ - uses: actions/checkout@v4
77
+ - uses: actions/setup-node@v4
78
+ with:
79
+ node-version: ${{ env.NODE_VERSION }} # ✅ Actions expression
80
+ # node-version: $NODE_VERSION # ❌ Shell syntax — not expanded
81
+ - language: yaml
82
+ label: "Read .nvmrc manually when node-version-file is insufficient"
83
+ code: |
84
+ steps:
85
+ - uses: actions/checkout@v4
86
+ - name: Read .nvmrc
87
+ id: nvmrc
88
+ run: echo "version=$(cat .nvmrc)" >> $GITHUB_OUTPUT
89
+ - uses: actions/setup-node@v4
90
+ with:
91
+ node-version: ${{ steps.nvmrc.outputs.version }}
92
+ prevention:
93
+ - "Always run `actions/checkout` before any step that reads files from the repository, including `node-version-file`."
94
+ - "Use `actions/setup-node@v4` — v1/v2 are deprecated and trigger cache service 422 errors."
95
+ - "Prefer `node-version-file: '.nvmrc'` over reading the file in a shell step to avoid shell escaping issues."
96
+ - "Pin to a Node.js major version (e.g., `20`) rather than a full SemVer patch to avoid version-not-found errors."
97
+ docs:
98
+ - url: "https://github.com/actions/setup-node"
99
+ label: "actions/setup-node — README and usage"
100
+ - url: "https://github.com/actions/setup-node/issues/613"
101
+ label: "setup-node#613 — node-version-file does not exist error"
102
+ - url: "https://github.com/actions/setup-node/issues/32"
103
+ label: "setup-node#32 — Using .nvmrc with env variable substitution"
104
+ - url: "https://github.com/actions/setup-node/issues/1275"
105
+ label: "setup-node#1275 — Cache service 422 — upgrade to v3/v4"
@@ -0,0 +1,83 @@
1
+ id: runner-environment-012
2
+ title: "Windows Runner PowerShell Execution Policy Blocks Custom Scripts"
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - windows
7
+ - powershell
8
+ - execution-policy
9
+ - scripts
10
+ - runner
11
+ - security
12
+ patterns:
13
+ - regex: "cannot be loaded because running scripts is disabled"
14
+ flags: "i"
15
+ - regex: "execution policy"
16
+ flags: "i"
17
+ - regex: "UnauthorizedAccess.*\\.ps1"
18
+ flags: "i"
19
+ - regex: "File .+\\.ps1 cannot be loaded"
20
+ flags: "i"
21
+ error_messages:
22
+ - "File C:\\...\\script.ps1 cannot be loaded because running scripts is disabled on this system."
23
+ - "UnauthorizedAccess: File C:\\...\\script.ps1 cannot be loaded because running scripts is disabled on this system. For more information, see about_Execution_Policies"
24
+ root_cause: |
25
+ Windows GitHub-hosted runners default to the `RemoteSigned` execution policy, which
26
+ requires that downloaded scripts be digitally signed. Scripts created inline during a
27
+ workflow or checked out from the repo can trigger this restriction depending on how
28
+ they are invoked, especially when called via `powershell.exe` directly or from a
29
+ third-party action that spawns a new PowerShell session with a more restrictive default.
30
+
31
+ This is particularly common when a workflow uses `shell: powershell` (legacy
32
+ `powershell.exe` v5) where the execution policy is stricter, or when a script file
33
+ is written to disk by a previous step and then invoked.
34
+ fix: |
35
+ Use `shell: pwsh` (PowerShell 7+) which defaults to `Bypass` execution policy in
36
+ GitHub Actions workflows. For `shell: powershell` sessions, prefix the script
37
+ invocation with `Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass`.
38
+ fix_code:
39
+ - language: yaml
40
+ label: "WRONG — script fails with execution policy error"
41
+ code: |
42
+ jobs:
43
+ build:
44
+ runs-on: windows-latest
45
+ steps:
46
+ - uses: actions/checkout@v4
47
+
48
+ - name: Run build script
49
+ shell: powershell
50
+ run: .\scripts\build.ps1 # may fail: execution policy
51
+ - language: yaml
52
+ label: "CORRECT — use pwsh (PowerShell 7) which defaults to Bypass"
53
+ code: |
54
+ jobs:
55
+ build:
56
+ runs-on: windows-latest
57
+ steps:
58
+ - uses: actions/checkout@v4
59
+
60
+ - name: Run build script
61
+ shell: pwsh # PowerShell 7+ — Bypass policy by default
62
+ run: .\scripts\build.ps1
63
+ - language: yaml
64
+ label: "CORRECT — explicitly bypass in legacy powershell session"
65
+ code: |
66
+ jobs:
67
+ build:
68
+ runs-on: windows-latest
69
+ steps:
70
+ - name: Run legacy PS script
71
+ shell: powershell
72
+ run: |
73
+ Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force
74
+ .\scripts\build.ps1
75
+ prevention:
76
+ - "Prefer `shell: pwsh` over `shell: powershell` for all new Windows workflows — it's PowerShell 7+ and more permissive."
77
+ - "Avoid calling `.ps1` files from non-PowerShell shells (cmd, bash) — invoke them via `pwsh -File script.ps1` instead."
78
+ - "Test Windows workflows locally with the same shell version (`pwsh` vs `powershell`) before pushing."
79
+ docs:
80
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell"
81
+ label: "jobs.<job_id>.steps[*].shell"
82
+ - url: "https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy"
83
+ label: "Set-ExecutionPolicy (Microsoft Learn)"
@@ -0,0 +1,75 @@
1
+ id: silent-failures-006
2
+ title: "add-mask Does Not Retroactively Redact Values Already Printed"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - secrets
7
+ - masking
8
+ - add-mask
9
+ - security
10
+ - log-redaction
11
+ - sensitive-data
12
+ patterns:
13
+ - regex: "::add-mask::"
14
+ flags: "i"
15
+ - regex: "add_mask"
16
+ flags: "i"
17
+ error_messages:
18
+ - "Warning: Secret value was printed to log before masking was applied."
19
+ root_cause: |
20
+ The `add-mask` workflow command (`echo "::add-mask::$VALUE"`) tells the runner to
21
+ redact all future occurrences of `$VALUE` from log output. However, it only applies
22
+ **from the point it is issued forward** — any log lines already written before the
23
+ `add-mask` command are not retroactively redacted.
24
+
25
+ This creates a silent security failure when a step prints a sensitive value in an
26
+ earlier `run:` command and only calls `add-mask` later. The value appears in plain
27
+ text in the workflow log for the duration the log is retained (90 days by default).
28
+
29
+ A common pattern that triggers this: computing a token at the start of a long `run:`
30
+ script, printing it for debugging, and only masking it several lines later.
31
+ fix: |
32
+ Issue `add-mask` as the very first operation after obtaining a sensitive value —
33
+ before any `echo`, `cat`, or other command that might emit it. Prefer using
34
+ built-in `secrets.*` context (which is auto-masked) over dynamically computed
35
+ sensitive values wherever possible.
36
+ fix_code:
37
+ - language: yaml
38
+ label: "WRONG — value printed before add-mask is issued"
39
+ code: |
40
+ steps:
41
+ - name: Get dynamic token
42
+ run: |
43
+ TOKEN=$(curl -s https://api.example.com/token | jq -r .access_token)
44
+ echo "Got token: $TOKEN" # PRINTED IN PLAIN TEXT
45
+ echo "::add-mask::$TOKEN" # too late — above line already logged
46
+ echo "TOKEN=$TOKEN" >> $GITHUB_ENV
47
+ - language: yaml
48
+ label: "CORRECT — mask before any output"
49
+ code: |
50
+ steps:
51
+ - name: Get dynamic token
52
+ run: |
53
+ TOKEN=$(curl -s https://api.example.com/token | jq -r .access_token)
54
+ echo "::add-mask::$TOKEN" # mask FIRST
55
+ echo "TOKEN=$TOKEN" >> $GITHUB_ENV
56
+ echo "Token acquired and masked successfully" # no value, safe to log
57
+ - language: yaml
58
+ label: "CORRECT — use secrets context (auto-masked)"
59
+ code: |
60
+ steps:
61
+ - name: Use pre-configured secret
62
+ env:
63
+ API_TOKEN: ${{ secrets.API_TOKEN }} # automatically masked everywhere
64
+ run: |
65
+ curl -H "Authorization: Bearer $API_TOKEN" https://api.example.com/data
66
+ prevention:
67
+ - "Always call `add-mask` as the very first line after obtaining a sensitive value."
68
+ - "Prefer `secrets.*` context values over dynamically fetched tokens where possible."
69
+ - "Never print sensitive values for debugging — use `echo 'Token acquired (masked)'` instead."
70
+ - "Audit workflows that call external APIs and store tokens in env vars for missing `add-mask`."
71
+ docs:
72
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#masking-a-value-in-a-log"
73
+ label: "Masking a value in a log"
74
+ - url: "https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions"
75
+ label: "Security hardening for GitHub Actions"