@htekdev/actions-debugger 1.0.107 → 1.0.109
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/errors/caching-artifacts/cache-key-runner-os-insufficient-ubuntu-version-migration.yml +90 -0
- package/errors/caching-artifacts/caching-artifacts-064.yml +92 -0
- package/errors/known-unsolved/cross-job-tmp-files-separate-runners.yml +121 -0
- package/errors/permissions-auth/create-github-app-token-invalid-key-data.yml +94 -0
- package/errors/permissions-auth/create-github-app-token-v2-default-single-repo-scope.yml +70 -0
- package/errors/silent-failures/github-event-head-commit-null-non-push-events.yml +99 -0
- package/errors/silent-failures/timeout-minutes-result-cancelled-not-failure.yml +95 -0
- package/errors/yaml-syntax/workflow-dispatch-input-type-object-invalid.yml +84 -0
- package/package.json +1 -1
package/errors/caching-artifacts/cache-key-runner-os-insufficient-ubuntu-version-migration.yml
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
id: caching-artifacts-063
|
|
2
|
+
title: "runner.os insufficient in cache key after ubuntu-22.04 to ubuntu-24.04 migration — glibc-incompatible binaries silently restored"
|
|
3
|
+
category: caching-artifacts
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- cache-key
|
|
7
|
+
- runner.os
|
|
8
|
+
- ubuntu-24.04
|
|
9
|
+
- binary-compatibility
|
|
10
|
+
- glibc
|
|
11
|
+
- migration
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'symbol lookup error.*undefined symbol'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'version.*GLIBC.*not found'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: 'GLIBCXX.*not found'
|
|
18
|
+
flags: 'i'
|
|
19
|
+
error_messages:
|
|
20
|
+
- "symbol lookup error: ./bin/app: undefined symbol: __libc_single_threaded"
|
|
21
|
+
- "version `GLIBC_2.38' not found (required by ./bin/app)"
|
|
22
|
+
- "GLIBCXX_3.4.32 not found in /usr/lib/x86_64-linux-gnu/libstdc++.so.6"
|
|
23
|
+
root_cause: |
|
|
24
|
+
`runner.os` returns "Linux" for ALL Linux-based GitHub-hosted runners regardless of
|
|
25
|
+
Ubuntu distribution version: ubuntu-22.04 (glibc 2.35, GCC 11) and ubuntu-24.04
|
|
26
|
+
(glibc 2.39, GCC 13) both return "Linux".
|
|
27
|
+
|
|
28
|
+
When a workflow migrates from `runs-on: ubuntu-22.04` to `runs-on: ubuntu-latest`
|
|
29
|
+
(which became ubuntu-24.04 in March 2025), cache keys using only `${{ runner.os }}`
|
|
30
|
+
continue to match previously saved caches from ubuntu-22.04. Compiled native binaries
|
|
31
|
+
— Rust/Cargo target directories, CMake build outputs, Go CGO artifacts, Python
|
|
32
|
+
Cython-compiled extensions, pre-built Node.js native addons — are restored from
|
|
33
|
+
the ubuntu-22.04 cache onto an ubuntu-24.04 runner.
|
|
34
|
+
|
|
35
|
+
Because ubuntu-24.04 ships a newer glibc (2.39 vs 2.35) and updated libstdc++, binaries
|
|
36
|
+
compiled against the older ABI fail at runtime with dynamic linker errors:
|
|
37
|
+
|
|
38
|
+
symbol lookup error: ./bin/app: undefined symbol: __libc_single_threaded
|
|
39
|
+
version `GLIBC_2.38' not found (required by ./bin/app)
|
|
40
|
+
|
|
41
|
+
The cache restore step succeeds and shows a green checkmark. The failure surfaces only
|
|
42
|
+
when the restored binary is executed later in the pipeline, potentially hours into a
|
|
43
|
+
build. Because the compile step is skipped (cache hit), the error appears to come from
|
|
44
|
+
the execution step with no indication that a stale cross-version cache is the cause.
|
|
45
|
+
fix: |
|
|
46
|
+
Add the runner image version to the cache key so that binary artifacts are not shared
|
|
47
|
+
across different Ubuntu distribution versions. GitHub-hosted runners expose the image
|
|
48
|
+
version as the `ImageVersion` environment variable (e.g. "20250312.1"). Alternatively,
|
|
49
|
+
hash `/etc/os-release` as a portable OS version fingerprint.
|
|
50
|
+
fix_code:
|
|
51
|
+
- language: yaml
|
|
52
|
+
label: "Include ImageVersion in cache key to isolate per Ubuntu release"
|
|
53
|
+
code: |
|
|
54
|
+
- name: Cache Cargo build artifacts
|
|
55
|
+
uses: actions/cache@v4
|
|
56
|
+
with:
|
|
57
|
+
path: |
|
|
58
|
+
~/.cargo/registry
|
|
59
|
+
~/.cargo/git
|
|
60
|
+
target/
|
|
61
|
+
# ImageVersion (e.g. "20250312.1") differs between ubuntu-22.04 and ubuntu-24.04
|
|
62
|
+
# Prevents restoring ubuntu-22.04 glibc-2.35 binaries on ubuntu-24.04 glibc-2.39
|
|
63
|
+
key: ${{ runner.os }}-${{ env.ImageVersion }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
|
64
|
+
restore-keys: |
|
|
65
|
+
${{ runner.os }}-${{ env.ImageVersion }}-cargo-
|
|
66
|
+
- language: yaml
|
|
67
|
+
label: "Alternative: hash /etc/os-release for portable OS version fingerprint"
|
|
68
|
+
code: |
|
|
69
|
+
- name: Cache compiled artifacts
|
|
70
|
+
uses: actions/cache@v4
|
|
71
|
+
with:
|
|
72
|
+
path: build/
|
|
73
|
+
key: >-
|
|
74
|
+
${{ runner.os }}-
|
|
75
|
+
${{ hashFiles('/etc/os-release') }}-
|
|
76
|
+
cmake-${{ hashFiles('CMakeLists.txt', '**/CMakeLists.txt') }}
|
|
77
|
+
restore-keys: |
|
|
78
|
+
${{ runner.os }}-${{ hashFiles('/etc/os-release') }}-cmake-
|
|
79
|
+
prevention:
|
|
80
|
+
- "After migrating `runs-on` from a specific ubuntu version to `ubuntu-latest`, bust existing caches by adding a new key prefix or bumping a cache version counter"
|
|
81
|
+
- "Include `${{ env.ImageVersion }}` in cache keys whenever the cached content contains compiled native binaries"
|
|
82
|
+
- "Use `runner.arch` for x64/ARM64 differences and `ImageVersion` for OS version differences together for complete binary cache isolation"
|
|
83
|
+
- "Prefer caching dependency manifests and source-level artifacts over compiled binaries when cross-version compatibility is uncertain"
|
|
84
|
+
docs:
|
|
85
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows"
|
|
86
|
+
label: "GitHub Actions — caching dependencies"
|
|
87
|
+
- url: "https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md"
|
|
88
|
+
label: "ubuntu-24.04 runner image specification (glibc and GCC versions)"
|
|
89
|
+
- url: "https://github.blog/changelog/2025-03-05-github-actions-ubuntu-latest-is-now-ubuntu-24-04/"
|
|
90
|
+
label: "GitHub Changelog — ubuntu-latest is now ubuntu-24.04 (March 2025)"
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
id: caching-artifacts-064
|
|
2
|
+
title: 'Third-party actions bundling @actions/cache npm v3 return "Cache service responded with 422" after Dec 2024 backend migration'
|
|
3
|
+
category: caching-artifacts
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- actions-cache
|
|
7
|
+
- deprecated-api
|
|
8
|
+
- cache-backend
|
|
9
|
+
- 422
|
|
10
|
+
- npm-package
|
|
11
|
+
- third-party-action
|
|
12
|
+
- migration
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: 'Cache service responded with 422'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'Failed to save cache.*422|Failed to restore cache.*422'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
- regex: 'cache.*HTTP 422|HTTP 422.*cache'
|
|
19
|
+
flags: 'i'
|
|
20
|
+
error_messages:
|
|
21
|
+
- "Cache service responded with 422"
|
|
22
|
+
- "Error: Cache service responded with 422"
|
|
23
|
+
- "Failed to save cache: Cache service responded with 422"
|
|
24
|
+
- "Warning: Failed to restore cache: Cache service responded with 422"
|
|
25
|
+
root_cause: |
|
|
26
|
+
In December 2024, GitHub migrated the Actions cache backend to a new service API.
|
|
27
|
+
The deprecated v3 cache API endpoints now return HTTP 422 instead of processing
|
|
28
|
+
cache requests. Any action that embeds `@actions/cache` npm package at v3.x sends
|
|
29
|
+
requests to the old endpoint and receives 422 responses.
|
|
30
|
+
|
|
31
|
+
This affects any action — not just `actions/cache` itself — that bundles the old
|
|
32
|
+
`@actions/cache` npm package internally. Common affected actions:
|
|
33
|
+
- `actions/setup-node@v2` / `@v3` (embed @actions/cache v3)
|
|
34
|
+
- `actions/setup-python@v4` and earlier
|
|
35
|
+
- `actions/setup-go@v4` and earlier
|
|
36
|
+
- Custom or third-party JavaScript/composite actions that haven't updated
|
|
37
|
+
their package-lock.json since early 2024
|
|
38
|
+
|
|
39
|
+
The 422 error appears in the step output but the visible message does not mention
|
|
40
|
+
deprecated API versions or npm package issues — it only shows the HTTP status code.
|
|
41
|
+
|
|
42
|
+
Note: This is distinct from `caching-artifacts-056` (actions/cache v1/v2 hard
|
|
43
|
+
deprecation which shows "automatically failed because it uses a deprecated version").
|
|
44
|
+
That error comes from the version check; this error comes from the actual API call.
|
|
45
|
+
fix: |
|
|
46
|
+
Upgrade the affected action to a version that bundles `@actions/cache` npm v4+.
|
|
47
|
+
For first-party GitHub actions, use the latest major version:
|
|
48
|
+
- `actions/setup-node` → upgrade to @v4 or @v5
|
|
49
|
+
- `actions/setup-python` → upgrade to @v5
|
|
50
|
+
- `actions/setup-go` → upgrade to @v5
|
|
51
|
+
- `actions/cache` used directly → upgrade to @v4
|
|
52
|
+
|
|
53
|
+
For third-party actions, open an issue asking the maintainer to update
|
|
54
|
+
@actions/cache in their package-lock.json and re-bundle the action.
|
|
55
|
+
|
|
56
|
+
As a temporary workaround, disable caching in the action to unblock CI:
|
|
57
|
+
fix_code:
|
|
58
|
+
- language: yaml
|
|
59
|
+
label: 'Upgrade setup-* actions to latest major version with updated cache client'
|
|
60
|
+
code: |
|
|
61
|
+
# Before (bundled @actions/cache v3 — returns 422 after Dec 2024 migration)
|
|
62
|
+
- uses: actions/setup-node@v2
|
|
63
|
+
with:
|
|
64
|
+
node-version: '18'
|
|
65
|
+
cache: 'npm'
|
|
66
|
+
|
|
67
|
+
# After (@actions/cache v4+ bundled — compatible with current cache service)
|
|
68
|
+
- uses: actions/setup-node@v4
|
|
69
|
+
with:
|
|
70
|
+
node-version: '18'
|
|
71
|
+
cache: 'npm'
|
|
72
|
+
- language: yaml
|
|
73
|
+
label: 'Disable caching as temporary workaround if action cannot be upgraded'
|
|
74
|
+
code: |
|
|
75
|
+
- uses: actions/setup-node@v2
|
|
76
|
+
with:
|
|
77
|
+
node-version: '18'
|
|
78
|
+
cache: '' # empty string disables cache, avoids 422 until action is upgraded
|
|
79
|
+
prevention:
|
|
80
|
+
- 'Keep all setup-* actions at their latest major version to stay compatible with the cache service API'
|
|
81
|
+
- 'Audit all uses: references for versions older than January 2024 — they may bundle stale @actions/cache v3'
|
|
82
|
+
- 'Enable Dependabot version updates for GitHub Actions to automatically surface major version bumps'
|
|
83
|
+
- 'After any GitHub changelog cache-migration notice, scan workflows for outdated action pins'
|
|
84
|
+
docs:
|
|
85
|
+
- url: 'https://github.blog/changelog/2024-12-05-notice-of-upcoming-releases-and-breaking-changes-for-github-actions'
|
|
86
|
+
label: 'GitHub Changelog — Notice of cache migration and deprecated action versions (Dec 2024)'
|
|
87
|
+
- url: 'https://github.com/actions/toolkit/tree/main/packages/cache'
|
|
88
|
+
label: 'actions/toolkit — @actions/cache npm package changelog'
|
|
89
|
+
- url: 'https://github.com/actions/setup-node/issues/1275'
|
|
90
|
+
label: 'actions/setup-node#1275 — Cache service 422 errors with older action versions (13 reactions)'
|
|
91
|
+
- url: 'https://github.com/orgs/community/discussions/155534'
|
|
92
|
+
label: 'GitHub Community — Cache service 422 flaky restores during Dec 2024 migration'
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
id: known-unsolved-057
|
|
2
|
+
title: 'Jobs run on separate fresh runners — /tmp and filesystem are not shared between jobs'
|
|
3
|
+
category: known-unsolved
|
|
4
|
+
severity: limitation
|
|
5
|
+
tags:
|
|
6
|
+
- jobs
|
|
7
|
+
- runner
|
|
8
|
+
- filesystem
|
|
9
|
+
- tmp
|
|
10
|
+
- isolation
|
|
11
|
+
- artifacts
|
|
12
|
+
- cross-job
|
|
13
|
+
- runner-environment
|
|
14
|
+
patterns:
|
|
15
|
+
- regex: 'No such file or directory.*/tmp/'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: 'ENOENT.*no such file.*tmp|cannot.*open.*/tmp/.*no such'
|
|
18
|
+
flags: 'i'
|
|
19
|
+
- regex: 'file.*not found.*/tmp|/tmp/.*does not exist'
|
|
20
|
+
flags: 'i'
|
|
21
|
+
error_messages:
|
|
22
|
+
- "/tmp/output.json: No such file or directory"
|
|
23
|
+
- "Error: ENOENT: no such file or directory, open '/tmp/result.txt'"
|
|
24
|
+
- "/tmp/build-manifest.json: No such file or directory"
|
|
25
|
+
root_cause: |
|
|
26
|
+
Each job in a GitHub Actions workflow runs on a completely separate, freshly
|
|
27
|
+
provisioned runner instance. There is NO shared filesystem between jobs. Files
|
|
28
|
+
written to `/tmp`, `$RUNNER_TEMP`, `$GITHUB_WORKSPACE`, or any other path during
|
|
29
|
+
one job are invisible to all subsequent jobs.
|
|
30
|
+
|
|
31
|
+
This is a fundamental architectural property: GitHub provisions a new virtual machine
|
|
32
|
+
for each job. The previous job's VM is terminated before the next job starts. No
|
|
33
|
+
filesystem state survives the job boundary.
|
|
34
|
+
|
|
35
|
+
Common patterns that fail for this reason:
|
|
36
|
+
1. Build job writes `/tmp/report.json` → deploy job tries to read `/tmp/report.json`
|
|
37
|
+
2. Test job saves coverage to `$RUNNER_TEMP/coverage.xml` → reporter job looks for it
|
|
38
|
+
3. Compile job produces `./dist/app` → signing job tries to use `./dist/app` without
|
|
39
|
+
re-downloading it via artifacts
|
|
40
|
+
4. First job exports env vars via `$GITHUB_ENV` → second job expects those env vars
|
|
41
|
+
(env vars set via GITHUB_ENV are also job-scoped and do not persist)
|
|
42
|
+
5. Steps within the SAME job DO share `/tmp` and the workspace — the limitation is
|
|
43
|
+
specifically at the JOB boundary
|
|
44
|
+
|
|
45
|
+
Self-hosted runner pools with persistent workspaces can accidentally appear to share
|
|
46
|
+
state between jobs on the same machine, but this is unreliable (another job may have
|
|
47
|
+
cleaned the directory) and creates security risks (secret leakage between runs).
|
|
48
|
+
fix: |
|
|
49
|
+
There is no mechanism to share filesystem state between jobs without explicitly
|
|
50
|
+
transferring the data. Two patterns solve this:
|
|
51
|
+
|
|
52
|
+
1. Use `actions/upload-artifact` at the end of the producing job and
|
|
53
|
+
`actions/download-artifact` at the start of the consuming job.
|
|
54
|
+
Best for: files, binaries, test results, build outputs.
|
|
55
|
+
|
|
56
|
+
2. Use job `outputs:` to pass small string values. The producing job emits
|
|
57
|
+
`echo "key=value" >> $GITHUB_OUTPUT` and declares it under `outputs:`.
|
|
58
|
+
The consuming job reads it as `needs.<job>.outputs.<key>`.
|
|
59
|
+
Best for: version strings, commit SHAs, boolean flags, counts.
|
|
60
|
+
fix_code:
|
|
61
|
+
- language: yaml
|
|
62
|
+
label: 'Pass files between jobs using upload-artifact / download-artifact'
|
|
63
|
+
code: |
|
|
64
|
+
jobs:
|
|
65
|
+
build:
|
|
66
|
+
runs-on: ubuntu-latest
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v4
|
|
69
|
+
|
|
70
|
+
- name: Build binary
|
|
71
|
+
run: make build # produces ./dist/app
|
|
72
|
+
|
|
73
|
+
- name: Upload for next job
|
|
74
|
+
uses: actions/upload-artifact@v4
|
|
75
|
+
with:
|
|
76
|
+
name: app-binary
|
|
77
|
+
path: ./dist/app # upload so sign job can download it
|
|
78
|
+
|
|
79
|
+
sign:
|
|
80
|
+
needs: build
|
|
81
|
+
runs-on: ubuntu-latest
|
|
82
|
+
steps:
|
|
83
|
+
- name: Download binary
|
|
84
|
+
uses: actions/download-artifact@v4
|
|
85
|
+
with:
|
|
86
|
+
name: app-binary
|
|
87
|
+
path: ./dist
|
|
88
|
+
|
|
89
|
+
- name: Sign binary
|
|
90
|
+
run: cosign sign ./dist/app
|
|
91
|
+
- language: yaml
|
|
92
|
+
label: 'Pass small string data between jobs using job outputs'
|
|
93
|
+
code: |
|
|
94
|
+
jobs:
|
|
95
|
+
compute-version:
|
|
96
|
+
runs-on: ubuntu-latest
|
|
97
|
+
outputs:
|
|
98
|
+
version: ${{ steps.ver.outputs.version }}
|
|
99
|
+
steps:
|
|
100
|
+
- id: ver
|
|
101
|
+
run: echo "version=$(cat VERSION)" >> "$GITHUB_OUTPUT"
|
|
102
|
+
|
|
103
|
+
deploy:
|
|
104
|
+
needs: compute-version
|
|
105
|
+
runs-on: ubuntu-latest
|
|
106
|
+
steps:
|
|
107
|
+
- run: echo "Deploying v${{ needs.compute-version.outputs.version }}"
|
|
108
|
+
prevention:
|
|
109
|
+
- 'Never rely on /tmp, $RUNNER_TEMP, or workspace paths to share data between jobs — use artifacts or job outputs'
|
|
110
|
+
- 'Remember: only steps within the same job share a filesystem; different jobs always get separate runners'
|
|
111
|
+
- 'Use actions/upload-artifact@v4 for files; use job outputs for strings; use caches only for dependency restoration'
|
|
112
|
+
- 'Environment variables set with GITHUB_ENV are also job-scoped and do not persist across job boundaries'
|
|
113
|
+
docs:
|
|
114
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/storing-and-sharing-data-from-a-workflow'
|
|
115
|
+
label: 'GitHub Docs — Storing and sharing data between jobs using artifacts'
|
|
116
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/passing-information-between-jobs'
|
|
117
|
+
label: 'GitHub Docs — Passing information between jobs using outputs'
|
|
118
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-where-your-workflow-runs/about-github-hosted-runners'
|
|
119
|
+
label: 'GitHub Docs — About GitHub-hosted runners (each job gets a fresh VM)'
|
|
120
|
+
- url: 'https://github.com/orgs/community/discussions/26671'
|
|
121
|
+
label: 'GitHub Community — Sharing files and filesystem data between workflow jobs'
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
id: permissions-auth-062
|
|
2
|
+
title: 'create-github-app-token "Invalid keyData" — private key passed via env var with escaped \\n sequences'
|
|
3
|
+
category: permissions-auth
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- github-app
|
|
7
|
+
- private-key
|
|
8
|
+
- invalid-key-data
|
|
9
|
+
- environment-variable
|
|
10
|
+
- newlines
|
|
11
|
+
- create-github-app-token
|
|
12
|
+
- webcrypto
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: 'Invalid keyData'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'DOMException.*Invalid keyData|DataError.*Invalid keyData'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
- regex: 'Failed to create token for .+ \(attempt \d+\): Invalid keyData'
|
|
19
|
+
flags: 'i'
|
|
20
|
+
error_messages:
|
|
21
|
+
- "DOMException [DataError]: Invalid keyData"
|
|
22
|
+
- "Failed to create token for \"repo-name\" (attempt 1): Invalid keyData"
|
|
23
|
+
- "Failed to create token for \"repo-name\" (attempt 2): Invalid keyData"
|
|
24
|
+
- "Error: Invalid keyData"
|
|
25
|
+
root_cause: |
|
|
26
|
+
The `actions/create-github-app-token` action v2+ uses the Web Crypto API
|
|
27
|
+
(`crypto.subtle.importKey()`) to load the GitHub App private key. This API
|
|
28
|
+
is strict about key formatting — it throws `DOMException [DataError]: Invalid keyData`
|
|
29
|
+
if the PEM key material is malformed at the byte level.
|
|
30
|
+
|
|
31
|
+
The most common trigger is passing the private key via an environment variable
|
|
32
|
+
where literal `\n` two-character sequences appear instead of actual newline (0x0A)
|
|
33
|
+
bytes. This happens when:
|
|
34
|
+
1. The key is constructed inline in YAML with `"-----BEGIN...\nMIIE...\n-----END..."`
|
|
35
|
+
where `\n` is a YAML string escape, not a real newline in the multi-line base64 body
|
|
36
|
+
2. An external CI system or secrets manager serializes the PEM key as a single line
|
|
37
|
+
with literal backslash-n separators before injecting it into the Actions environment
|
|
38
|
+
3. Shell variable interpolation collapses the newlines (e.g., `echo $PRIVATE_KEY`)
|
|
39
|
+
|
|
40
|
+
The Web Crypto SubtleCrypto API attempts to Base64-decode the key body. When the
|
|
41
|
+
PEM line breaks are backslash-n characters (0x5C 0x6E) instead of 0x0A, the Base64
|
|
42
|
+
chunks are malformed and importKey() throws "Invalid keyData" immediately — before
|
|
43
|
+
any GitHub API call is made.
|
|
44
|
+
|
|
45
|
+
This is distinct from "A JSON web token could not be decoded" (permissions-auth-021)
|
|
46
|
+
which occurs when the key IS imported successfully but the resulting JWT is rejected
|
|
47
|
+
by GitHub's API — a later-stage failure caused by different formatting issues such
|
|
48
|
+
as trailing whitespace, CRLF endings, or missing PEM headers.
|
|
49
|
+
fix: |
|
|
50
|
+
Pass the private key directly as an action input using the GitHub Actions secret
|
|
51
|
+
expression `${{ secrets.APP_PRIVATE_KEY }}`. When GitHub resolves a secret, it
|
|
52
|
+
preserves the original stored bytes including actual newlines. Do NOT pass the key
|
|
53
|
+
through env: variables or inline string construction.
|
|
54
|
+
|
|
55
|
+
To store the key with correct newlines, set the secret from the downloaded .pem file
|
|
56
|
+
using the GitHub CLI:
|
|
57
|
+
gh secret set APP_PRIVATE_KEY < my-app.private-key.pem
|
|
58
|
+
fix_code:
|
|
59
|
+
- language: yaml
|
|
60
|
+
label: 'Correct: pass private key directly as action input from secret'
|
|
61
|
+
code: |
|
|
62
|
+
- uses: actions/create-github-app-token@v1
|
|
63
|
+
id: app-token
|
|
64
|
+
with:
|
|
65
|
+
app-id: ${{ vars.APP_ID }}
|
|
66
|
+
private-key: ${{ secrets.APP_PRIVATE_KEY }} # newlines preserved by Actions runtime
|
|
67
|
+
- language: yaml
|
|
68
|
+
label: 'Wrong: constructing key inline with \\n escape sequences (causes Invalid keyData)'
|
|
69
|
+
code: |
|
|
70
|
+
# DO NOT DO THIS — \n are literal two-char sequences, not newlines
|
|
71
|
+
- name: Broken token generation
|
|
72
|
+
env:
|
|
73
|
+
KEY: "-----BEGIN RSA PRIVATE KEY-----\nMIIEow...\n-----END RSA PRIVATE KEY-----"
|
|
74
|
+
run: |
|
|
75
|
+
echo "$KEY" > /tmp/key.pem
|
|
76
|
+
# The action will fail with: DOMException [DataError]: Invalid keyData
|
|
77
|
+
- language: shell
|
|
78
|
+
label: 'Set secret from .pem file using GitHub CLI (preserves real newlines)'
|
|
79
|
+
code: |
|
|
80
|
+
gh secret set APP_PRIVATE_KEY < my-app.2024-01-15.private-key.pem
|
|
81
|
+
prevention:
|
|
82
|
+
- 'Always set APP_PRIVATE_KEY secret using `gh secret set KEY < file.pem`, not by pasting the raw PEM text with \\n sequences'
|
|
83
|
+
- 'Pass the key exclusively as `private-key: ${{ secrets.KEY }}` — never via env: or inline string interpolation'
|
|
84
|
+
- 'If importing from an external secrets manager, ensure the manager preserves actual newline bytes (0x0A) when injecting into GitHub Actions secrets'
|
|
85
|
+
- 'Verify the secret was set correctly: run `gh secret list` and confirm the key was recently updated'
|
|
86
|
+
docs:
|
|
87
|
+
- url: 'https://github.com/actions/create-github-app-token'
|
|
88
|
+
label: 'actions/create-github-app-token README'
|
|
89
|
+
- url: 'https://github.com/actions/create-github-app-token/issues/184'
|
|
90
|
+
label: 'actions/create-github-app-token#184 — Invalid keyData when key passed via environment variable'
|
|
91
|
+
- url: 'https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey'
|
|
92
|
+
label: 'MDN — SubtleCrypto.importKey() — DOMException DataError causes'
|
|
93
|
+
- url: 'https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-private-key-for-a-github-app'
|
|
94
|
+
label: 'GitHub Docs — Generating a private key for a GitHub App'
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
id: permissions-auth-061
|
|
2
|
+
title: "actions/create-github-app-token v2 — default token scope limited to current repository only"
|
|
3
|
+
category: permissions-auth
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- github-app
|
|
7
|
+
- create-github-app-token
|
|
8
|
+
- multi-repo
|
|
9
|
+
- token-scope
|
|
10
|
+
- v2-migration
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'Resource not accessible by integration'
|
|
13
|
+
flags: 'i'
|
|
14
|
+
- regex: 'actions/create-github-app-token@v2'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
error_messages:
|
|
17
|
+
- "Resource not accessible by integration"
|
|
18
|
+
- "RequestError [HttpError]: Resource not accessible by integration"
|
|
19
|
+
root_cause: |
|
|
20
|
+
actions/create-github-app-token underwent a breaking scope change in v2 (released 2024).
|
|
21
|
+
|
|
22
|
+
In v1: when no `repositories` input is specified, the generated token is scoped to ALL
|
|
23
|
+
repositories the GitHub App installation has access to.
|
|
24
|
+
|
|
25
|
+
In v2: when no `repositories` or `owner` input is specified, the token is scoped ONLY
|
|
26
|
+
to the current repository where the workflow is running. This matches the GitHub App
|
|
27
|
+
installation token API default behavior when requesting a per-repository token.
|
|
28
|
+
|
|
29
|
+
Workflows that used v1 and relied on the token to access other repositories (for
|
|
30
|
+
cross-repo clones, API calls, pushes, or artifact publishing) silently receive a
|
|
31
|
+
limited-scope token in v2. Operations on other repos return "Resource not accessible
|
|
32
|
+
by integration" or "HTTP 404 Not Found" with no clear indication that a v2 migration
|
|
33
|
+
caused the regression.
|
|
34
|
+
fix: |
|
|
35
|
+
Explicitly declare the repositories the token should cover using the `repositories`
|
|
36
|
+
input (comma-separated repository names, without the org prefix). To grant access to
|
|
37
|
+
all repositories the app has access to within the same organization, use the `owner`
|
|
38
|
+
input instead.
|
|
39
|
+
fix_code:
|
|
40
|
+
- language: yaml
|
|
41
|
+
label: "Explicit multi-repo token scope (v2)"
|
|
42
|
+
code: |
|
|
43
|
+
- name: Generate token
|
|
44
|
+
id: app-token
|
|
45
|
+
uses: actions/create-github-app-token@v2
|
|
46
|
+
with:
|
|
47
|
+
app-id: ${{ vars.APP_ID }}
|
|
48
|
+
private-key: ${{ secrets.PRIVATE_KEY }}
|
|
49
|
+
# List every repository the token needs access to
|
|
50
|
+
repositories: "repo-a,repo-b,infra-configs"
|
|
51
|
+
- language: yaml
|
|
52
|
+
label: "Org-wide token scope using owner input (v2)"
|
|
53
|
+
code: |
|
|
54
|
+
- name: Generate token
|
|
55
|
+
id: app-token
|
|
56
|
+
uses: actions/create-github-app-token@v2
|
|
57
|
+
with:
|
|
58
|
+
app-id: ${{ vars.APP_ID }}
|
|
59
|
+
private-key: ${{ secrets.PRIVATE_KEY }}
|
|
60
|
+
# Grants access to all repos the app has access to in the org
|
|
61
|
+
owner: ${{ github.repository_owner }}
|
|
62
|
+
prevention:
|
|
63
|
+
- "When upgrading from v1 to v2, audit all usages for cross-repo operations and add an explicit `repositories:` or `owner:` input"
|
|
64
|
+
- "Pin to a major version tag and review the CHANGELOG before upgrading any action that generates authentication tokens"
|
|
65
|
+
- "Test cross-repo operations in a staging workflow immediately after a major version upgrade"
|
|
66
|
+
docs:
|
|
67
|
+
- url: "https://github.com/actions/create-github-app-token/releases/tag/v2.0.0"
|
|
68
|
+
label: "actions/create-github-app-token v2.0.0 release notes (scope change)"
|
|
69
|
+
- url: "https://github.com/actions/create-github-app-token/blob/main/README.md#inputs"
|
|
70
|
+
label: "actions/create-github-app-token README — repositories and owner inputs"
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
id: silent-failures-095
|
|
2
|
+
title: "github.event.head_commit is null on non-push events — commit message checks silently return false"
|
|
3
|
+
category: silent-failures
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- github-context
|
|
7
|
+
- head-commit
|
|
8
|
+
- workflow-dispatch
|
|
9
|
+
- event-context
|
|
10
|
+
- commit-message
|
|
11
|
+
- null-context
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'github\.event\.head_commit\.message'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'github\.event\.head_commit\b'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
error_messages:
|
|
18
|
+
- "contains(github.event.head_commit.message, ...) returns false on workflow_dispatch"
|
|
19
|
+
- "github.event.head_commit is null"
|
|
20
|
+
root_cause: |
|
|
21
|
+
The `github.event.head_commit` context object is only populated on `push` events.
|
|
22
|
+
On all other trigger types — `workflow_dispatch`, `pull_request`, `pull_request_target`,
|
|
23
|
+
`schedule`, `workflow_call`, `workflow_run`, `release`, and others — the property is
|
|
24
|
+
null, and all child fields evaluate to empty string `""` in expressions.
|
|
25
|
+
|
|
26
|
+
A very common workflow pattern is to gate deployment or release steps based on the
|
|
27
|
+
commit message:
|
|
28
|
+
|
|
29
|
+
if: contains(github.event.head_commit.message, '[deploy]')
|
|
30
|
+
|
|
31
|
+
When this condition is evaluated on a `workflow_dispatch` run, a scheduled run, or
|
|
32
|
+
any non-push trigger, `github.event.head_commit` is null and `contains()` receives
|
|
33
|
+
an empty string. The expression silently returns false and the step is skipped.
|
|
34
|
+
|
|
35
|
+
No error, no warning, and no indication in the workflow log that the condition was
|
|
36
|
+
never evaluated against real commit message data. Developers manually triggering the
|
|
37
|
+
workflow see their step silently skipped with no explanation.
|
|
38
|
+
|
|
39
|
+
This is particularly confusing because:
|
|
40
|
+
- The workflow completes successfully with a green checkmark
|
|
41
|
+
- The step appears in the log as skipped with no reason given
|
|
42
|
+
- Manual `workflow_dispatch` runs show no null-context warning
|
|
43
|
+
fix: |
|
|
44
|
+
Guard the commit message check with an explicit event type condition, or provide a
|
|
45
|
+
workflow_dispatch input as an equivalent gate for manual runs.
|
|
46
|
+
fix_code:
|
|
47
|
+
- language: yaml
|
|
48
|
+
label: "Guard commit message check to push events only"
|
|
49
|
+
code: |
|
|
50
|
+
jobs:
|
|
51
|
+
deploy:
|
|
52
|
+
runs-on: ubuntu-latest
|
|
53
|
+
steps:
|
|
54
|
+
- name: Deploy on tagged commit message
|
|
55
|
+
# Only evaluate head_commit.message on push events where it is defined
|
|
56
|
+
if: >-
|
|
57
|
+
github.event_name == 'push' &&
|
|
58
|
+
contains(github.event.head_commit.message, '[deploy]')
|
|
59
|
+
run: ./scripts/deploy.sh
|
|
60
|
+
- language: yaml
|
|
61
|
+
label: "Support push and manual dispatch with input fallback"
|
|
62
|
+
code: |
|
|
63
|
+
on:
|
|
64
|
+
push:
|
|
65
|
+
branches: [main]
|
|
66
|
+
workflow_dispatch:
|
|
67
|
+
inputs:
|
|
68
|
+
deploy:
|
|
69
|
+
description: 'Trigger deployment manually'
|
|
70
|
+
type: boolean
|
|
71
|
+
default: false
|
|
72
|
+
|
|
73
|
+
jobs:
|
|
74
|
+
deploy:
|
|
75
|
+
runs-on: ubuntu-latest
|
|
76
|
+
steps:
|
|
77
|
+
- name: Resolve deploy flag
|
|
78
|
+
id: flag
|
|
79
|
+
run: |
|
|
80
|
+
if [[ "${{ github.event_name }}" == "push" ]]; then
|
|
81
|
+
MSG="${{ github.event.head_commit.message }}"
|
|
82
|
+
echo "enabled=$([[ "$MSG" == *'[deploy]'* ]] && echo true || echo false)" >> $GITHUB_OUTPUT
|
|
83
|
+
else
|
|
84
|
+
echo "enabled=${{ inputs.deploy }}" >> $GITHUB_OUTPUT
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
- name: Deploy
|
|
88
|
+
if: steps.flag.outputs.enabled == 'true'
|
|
89
|
+
run: ./scripts/deploy.sh
|
|
90
|
+
prevention:
|
|
91
|
+
- "Never use `github.event.head_commit.*` without first checking `github.event_name == 'push'`"
|
|
92
|
+
- "Use `workflow_dispatch` inputs with boolean type as the manual-trigger equivalent of commit-message gates"
|
|
93
|
+
- "Document which events activate each step — add inline comments explaining gating conditions"
|
|
94
|
+
- "Test multi-trigger workflows by manually running them and verifying steps behave as expected"
|
|
95
|
+
docs:
|
|
96
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#push"
|
|
97
|
+
label: "GitHub Actions push event — head_commit availability"
|
|
98
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/contexts#github-context"
|
|
99
|
+
label: "GitHub context reference — github.event object"
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
id: silent-failures-096
|
|
2
|
+
title: "Job timeout-minutes sets result to 'cancelled' not 'failure' — if: failure() notification jobs silently skip timed-out jobs"
|
|
3
|
+
category: silent-failures
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- timeout-minutes
|
|
7
|
+
- job-result
|
|
8
|
+
- if-failure
|
|
9
|
+
- notification
|
|
10
|
+
- cancelled
|
|
11
|
+
- cleanup-job
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'if:.*failure\(\)'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'timeout-minutes:\s*\d+'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
error_messages:
|
|
18
|
+
- "This step was skipped because a previous step failed"
|
|
19
|
+
- "notification job skipped — upstream job timed out but result is 'cancelled' not 'failure'"
|
|
20
|
+
root_cause: |
|
|
21
|
+
When a job exceeds its `timeout-minutes:` limit, GitHub Actions cancels the job and
|
|
22
|
+
sets its `result` to `"cancelled"` — NOT `"failure"`. This is a consistent but
|
|
23
|
+
widely misunderstood behavior.
|
|
24
|
+
|
|
25
|
+
A standard pattern is to add a notification or cleanup job that runs when builds fail:
|
|
26
|
+
|
|
27
|
+
notify:
|
|
28
|
+
needs: build
|
|
29
|
+
if: failure()
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
|
|
32
|
+
The `failure()` status check function returns true only when at least one upstream job
|
|
33
|
+
has result `"failure"`. It does NOT match `"cancelled"`. When `build` times out,
|
|
34
|
+
`needs.build.result` is `"cancelled"`, so `if: failure()` evaluates to false and
|
|
35
|
+
the notification job is silently skipped.
|
|
36
|
+
|
|
37
|
+
The four terminal job result values are: "success", "failure", "cancelled", "skipped".
|
|
38
|
+
The built-in functions map to:
|
|
39
|
+
- `failure()` → true when any upstream job result is "failure"
|
|
40
|
+
- `cancelled()` → true when any upstream job result is "cancelled"
|
|
41
|
+
- `success()` → true when all upstream jobs result in "success" (default)
|
|
42
|
+
- `always()` → always true regardless of upstream results
|
|
43
|
+
|
|
44
|
+
Developers are often surprised that a timed-out build does not trigger their alerting
|
|
45
|
+
job. The UI shows the timed-out job in orange ("Cancelled"), while the notification
|
|
46
|
+
job appears grey ("Skipped") — there is no direct indication that the skip is due to
|
|
47
|
+
the timeout rather than an unrelated condition.
|
|
48
|
+
fix: |
|
|
49
|
+
Expand the notification job condition to explicitly cover both `failure` and `cancelled`
|
|
50
|
+
results, using `always()` to ensure the job runs regardless of upstream outcomes.
|
|
51
|
+
fix_code:
|
|
52
|
+
- language: yaml
|
|
53
|
+
label: "Catch both failure and timeout (cancelled) in notification job"
|
|
54
|
+
code: |
|
|
55
|
+
jobs:
|
|
56
|
+
build:
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
timeout-minutes: 30
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/checkout@v4
|
|
61
|
+
- run: make build
|
|
62
|
+
|
|
63
|
+
notify:
|
|
64
|
+
needs: build
|
|
65
|
+
# Use always() so the job runs; then check for failure OR cancelled (timeout)
|
|
66
|
+
if: always() && (needs.build.result == 'failure' || needs.build.result == 'cancelled')
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
steps:
|
|
69
|
+
- name: Send alert
|
|
70
|
+
run: |
|
|
71
|
+
echo "Build result: ${{ needs.build.result }}"
|
|
72
|
+
# call your notification webhook here
|
|
73
|
+
- language: yaml
|
|
74
|
+
label: "Multi-job pipeline — catch any non-success terminal state"
|
|
75
|
+
code: |
|
|
76
|
+
jobs:
|
|
77
|
+
report:
|
|
78
|
+
needs: [build, test, deploy]
|
|
79
|
+
if: >-
|
|
80
|
+
always() &&
|
|
81
|
+
(contains(needs.*.result, 'failure') ||
|
|
82
|
+
contains(needs.*.result, 'cancelled'))
|
|
83
|
+
runs-on: ubuntu-latest
|
|
84
|
+
steps:
|
|
85
|
+
- run: echo "Pipeline did not complete successfully"
|
|
86
|
+
prevention:
|
|
87
|
+
- "Replace bare `if: failure()` with `if: always() && (needs.X.result == 'failure' || needs.X.result == 'cancelled')` whenever upstream jobs have `timeout-minutes:` set"
|
|
88
|
+
- "Treat `timeout-minutes` as a cancellation mechanism — timed-out jobs report `cancelled` not `failure`"
|
|
89
|
+
- "Test your notification path by temporarily reducing `timeout-minutes` to confirm the alerting logic fires on timeout"
|
|
90
|
+
- "Document in team runbooks that CI timeouts appear orange ('Cancelled') not red ('Failed') in the Actions UI"
|
|
91
|
+
docs:
|
|
92
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/using-conditions-to-control-job-execution"
|
|
93
|
+
label: "GitHub Actions — status check functions (failure, cancelled, always)"
|
|
94
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes"
|
|
95
|
+
label: "GitHub Actions workflow syntax — timeout-minutes"
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
id: yaml-syntax-067
|
|
2
|
+
title: 'workflow_dispatch input type: object is not valid — "Unexpected value" validation error'
|
|
3
|
+
category: yaml-syntax
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- workflow_dispatch
|
|
7
|
+
- inputs
|
|
8
|
+
- type-object
|
|
9
|
+
- validation-error
|
|
10
|
+
- yaml
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'on\.workflow_dispatch\.inputs\.\w+\.type.*Unexpected value'
|
|
13
|
+
flags: 'i'
|
|
14
|
+
- regex: "Unexpected value 'object'"
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'Input type .object. is not supported'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
error_messages:
|
|
19
|
+
- "Invalid workflow file: on.workflow_dispatch.inputs.config.type: Unexpected value 'object'"
|
|
20
|
+
- "Invalid workflow file: .github/workflows/deploy.yml: Unexpected value 'object'"
|
|
21
|
+
root_cause: |
|
|
22
|
+
`workflow_dispatch` inputs support only five types: `string`, `boolean`, `choice`,
|
|
23
|
+
`environment`, and `number`. There is no `object` type. Developers attempting to pass
|
|
24
|
+
complex structured data (JSON objects, arrays) via a workflow_dispatch input often
|
|
25
|
+
try `type: object`, which causes an immediate YAML schema validation error and
|
|
26
|
+
prevents the workflow from running at all.
|
|
27
|
+
|
|
28
|
+
The valid type list:
|
|
29
|
+
- string — plain text value
|
|
30
|
+
- boolean — true/false checkbox in UI
|
|
31
|
+
- choice — dropdown from a fixed options list
|
|
32
|
+
- environment — GitHub environment picker
|
|
33
|
+
- number — numeric value (coerced to string at runtime)
|
|
34
|
+
|
|
35
|
+
There is no object, array, list, or json type for workflow_dispatch inputs.
|
|
36
|
+
The workflow file fails validation and does not appear as runnable in the
|
|
37
|
+
Actions UI.
|
|
38
|
+
fix: |
|
|
39
|
+
Use `type: string` and serialize the complex data as a JSON string. Parse it inside
|
|
40
|
+
the workflow using the `fromJSON()` expression function or `jq` in a run step.
|
|
41
|
+
fix_code:
|
|
42
|
+
- language: yaml
|
|
43
|
+
label: 'Pass complex data as a JSON string — use type: string, not type: object'
|
|
44
|
+
code: |
|
|
45
|
+
on:
|
|
46
|
+
workflow_dispatch:
|
|
47
|
+
inputs:
|
|
48
|
+
config:
|
|
49
|
+
type: string # NOT type: object
|
|
50
|
+
description: 'JSON config e.g. {"env":"prod","replicas":3}'
|
|
51
|
+
default: '{}'
|
|
52
|
+
required: false
|
|
53
|
+
|
|
54
|
+
jobs:
|
|
55
|
+
deploy:
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
steps:
|
|
58
|
+
- name: Parse config input
|
|
59
|
+
run: |
|
|
60
|
+
ENV=$(echo '${{ inputs.config }}' | jq -r .env)
|
|
61
|
+
REPLICAS=$(echo '${{ inputs.config }}' | jq -r .replicas)
|
|
62
|
+
echo "Deploying to $ENV with $REPLICAS replicas"
|
|
63
|
+
- language: yaml
|
|
64
|
+
label: 'Access nested fields with fromJSON() in expressions'
|
|
65
|
+
code: |
|
|
66
|
+
jobs:
|
|
67
|
+
deploy:
|
|
68
|
+
runs-on: ubuntu-latest
|
|
69
|
+
env:
|
|
70
|
+
ENV_NAME: ${{ fromJSON(inputs.config).env }}
|
|
71
|
+
steps:
|
|
72
|
+
- run: echo "Environment is $ENV_NAME"
|
|
73
|
+
prevention:
|
|
74
|
+
- 'Only use type: string, boolean, choice, environment, or number for workflow_dispatch inputs'
|
|
75
|
+
- 'For structured data, serialize as a JSON string and parse inside the job with jq or fromJSON()'
|
|
76
|
+
- 'Use actionlint to catch unsupported input types before pushing the workflow file'
|
|
77
|
+
- 'Document the expected JSON schema in the input description field so callers know the format'
|
|
78
|
+
docs:
|
|
79
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_dispatch'
|
|
80
|
+
label: 'GitHub Docs — workflow_dispatch inputs (valid types: string, boolean, choice, environment, number)'
|
|
81
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#fromjson'
|
|
82
|
+
label: 'GitHub Docs — fromJSON() expression function'
|
|
83
|
+
- url: 'https://stackoverflow.com/questions/76181396/github-actions-workflow-with-input-type-object-not-running'
|
|
84
|
+
label: 'Stack Overflow — workflow_dispatch with input type object not running'
|
package/package.json
CHANGED