@htekdev/actions-debugger 1.0.117 → 1.0.118
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-069.yml +133 -0
- package/errors/concurrency-timing/workflow-run-head-branch-null-schedule-dispatch-concurrency.yml +135 -0
- package/errors/known-unsolved/node-action-post-step-wrong-inputs-nested-composite.yml +133 -0
- package/errors/known-unsolved/ubuntu-24-04-arm64-missing-binder-ashmem-kernel-modules.yml +149 -0
- package/errors/permissions-auth/permissions-auth-069.yml +161 -0
- package/errors/runner-environment/arc-autoscalinglistener-ephemeralrunnerset-stale-after-upgrade.yml +134 -0
- package/errors/runner-environment/broker-server-socket-exception-nat-timeout-linux.yml +114 -0
- package/errors/runner-environment/runner-environment-210.yml +105 -0
- package/errors/runner-environment/runner-environment-213.yml +142 -0
- package/errors/runner-environment/ubuntu-24-man-db-dpkg-trigger-apt-install-stall.yml +94 -0
- package/errors/runner-environment/ubuntu-26-04-missing-preinstalled-tools.yml +178 -0
- package/errors/runner-environment/upload-artifact-v6-proxy-headers-leak-strict-proxy-fail.yml +101 -0
- package/errors/silent-failures/silent-failures-108.yml +108 -0
- package/errors/triggers/pull-request-labeled-fires-all-labels-no-name-filter.yml +110 -0
- package/errors/yaml-syntax/duplicate-step-id-within-job-scope-validation-error.yml +130 -0
- package/package.json +1 -1
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
id: caching-artifacts-069
|
|
2
|
+
title: 'actions/cache save@v5 "Unable to Reserve Cache" When Key Already Exists for Same Branch'
|
|
3
|
+
category: caching-artifacts
|
|
4
|
+
severity: warning
|
|
5
|
+
tags:
|
|
6
|
+
- cache
|
|
7
|
+
- cache-save
|
|
8
|
+
- v5
|
|
9
|
+
- immutable
|
|
10
|
+
- key-exists
|
|
11
|
+
- save-only
|
|
12
|
+
- reserve-cache
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: 'Unable to reserve cache with key .+, another job may be creating this cache'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'More Details: Key already reserved duplicate'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
- regex: 'Failed to save: Unable to reserve cache'
|
|
19
|
+
flags: 'i'
|
|
20
|
+
error_messages:
|
|
21
|
+
- 'Failed to save: Unable to reserve cache with key my-cache-key, another job may be creating this cache.'
|
|
22
|
+
- 'Warning: Cache save failed.'
|
|
23
|
+
- 'More Details: Key already reserved duplicate'
|
|
24
|
+
root_cause: |
|
|
25
|
+
GitHub's cache service is write-once per key+branch combination. Once a cache entry
|
|
26
|
+
has been successfully written for a given key on a given branch/ref, that key cannot
|
|
27
|
+
be overwritten. The slot is permanently "reserved" by the first writer.
|
|
28
|
+
|
|
29
|
+
When using `actions/cache/save@v5` (the standalone save action, separate from the
|
|
30
|
+
combined restore+save `actions/cache@v5`), the action does NOT automatically skip the
|
|
31
|
+
save if an exact cache key match already exists. It attempts to write the cache, the
|
|
32
|
+
service returns "Key already reserved duplicate" (v5 API uses proper JSON errors
|
|
33
|
+
unlike v3/v4 which returned HTML DOCTYPE responses), and the action emits:
|
|
34
|
+
"Failed to save: Unable to reserve cache with key X, another job may be creating this cache."
|
|
35
|
+
"Warning: Cache save failed."
|
|
36
|
+
|
|
37
|
+
This differs from the combined `actions/cache@v5` which checks the CACHE_HIT output
|
|
38
|
+
from its restore step and automatically skips the save on an exact key match. When
|
|
39
|
+
using the split restore/save pattern (actions/cache/restore + actions/cache/save),
|
|
40
|
+
the save action has no restore step context, so it always attempts to write —
|
|
41
|
+
triggering this warning when the key already exists from a previous workflow run.
|
|
42
|
+
|
|
43
|
+
Common trigger scenarios:
|
|
44
|
+
- Using actions/cache/save@v5 in an always() post step to save a cache built during
|
|
45
|
+
the job, on the second+ run of the same workflow on the same branch
|
|
46
|
+
- Using @actions/cache npm package's saveCache() directly without first checking
|
|
47
|
+
whether the key was already restored (restoreCache returned an exact match)
|
|
48
|
+
- Parallel jobs on the same branch all attempting to save under the same static key
|
|
49
|
+
fix: |
|
|
50
|
+
Option 1 (recommended): Gate the save step on cache-miss.
|
|
51
|
+
Use actions/cache/restore@v5 first and only run the save step when the primary key
|
|
52
|
+
was not an exact hit:
|
|
53
|
+
|
|
54
|
+
- name: Restore cache
|
|
55
|
+
id: restore
|
|
56
|
+
uses: actions/cache/restore@v5
|
|
57
|
+
with:
|
|
58
|
+
key: ${{ env.CACHE_KEY }}
|
|
59
|
+
path: ~/.cache/my-tool
|
|
60
|
+
|
|
61
|
+
- name: Build
|
|
62
|
+
run: make build
|
|
63
|
+
|
|
64
|
+
- name: Save cache
|
|
65
|
+
if: steps.restore.outputs.cache-hit != 'true'
|
|
66
|
+
uses: actions/cache/save@v5
|
|
67
|
+
with:
|
|
68
|
+
key: ${{ env.CACHE_KEY }}
|
|
69
|
+
path: ~/.cache/my-tool
|
|
70
|
+
|
|
71
|
+
Option 2: Use the combined actions/cache@v5 which handles this automatically.
|
|
72
|
+
|
|
73
|
+
Option 3 (programmatic): If using @actions/cache npm package, check restoreCache
|
|
74
|
+
return value before calling saveCache — skip save if the return value matches the
|
|
75
|
+
primary key (exact hit).
|
|
76
|
+
fix_code:
|
|
77
|
+
- language: yaml
|
|
78
|
+
label: 'Option 1 — gate save on cache-miss from restore step'
|
|
79
|
+
code: |
|
|
80
|
+
steps:
|
|
81
|
+
- name: Restore cache
|
|
82
|
+
id: cache-restore
|
|
83
|
+
uses: actions/cache/restore@v5
|
|
84
|
+
with:
|
|
85
|
+
key: ${{ runner.os }}-build-${{ hashFiles('**/lockfiles') }}
|
|
86
|
+
restore-keys: |
|
|
87
|
+
${{ runner.os }}-build-
|
|
88
|
+
path: |
|
|
89
|
+
~/.cache/my-tool
|
|
90
|
+
node_modules
|
|
91
|
+
|
|
92
|
+
- name: Build
|
|
93
|
+
run: make all
|
|
94
|
+
|
|
95
|
+
# Only save when the primary key was not an exact hit
|
|
96
|
+
- name: Save cache
|
|
97
|
+
if: steps.cache-restore.outputs.cache-hit != 'true'
|
|
98
|
+
uses: actions/cache/save@v5
|
|
99
|
+
with:
|
|
100
|
+
key: ${{ runner.os }}-build-${{ hashFiles('**/lockfiles') }}
|
|
101
|
+
path: |
|
|
102
|
+
~/.cache/my-tool
|
|
103
|
+
node_modules
|
|
104
|
+
- language: yaml
|
|
105
|
+
label: 'Option 2 — use combined cache action (auto-skips save on exact hit)'
|
|
106
|
+
code: |
|
|
107
|
+
steps:
|
|
108
|
+
- name: Cache dependencies
|
|
109
|
+
uses: actions/cache@v5
|
|
110
|
+
with:
|
|
111
|
+
key: ${{ runner.os }}-build-${{ hashFiles('**/lockfiles') }}
|
|
112
|
+
restore-keys: |
|
|
113
|
+
${{ runner.os }}-build-
|
|
114
|
+
path: |
|
|
115
|
+
~/.cache/my-tool
|
|
116
|
+
node_modules
|
|
117
|
+
prevention:
|
|
118
|
+
- 'Prefer the combined actions/cache@v5 over split restore/save when the primary key
|
|
119
|
+
is static or content-hash-based — the combined action skips save on exact hit automatically'
|
|
120
|
+
- 'When using split restore/save, always gate the save step with
|
|
121
|
+
if: steps.<restore-id>.outputs.cache-hit != ''true'''
|
|
122
|
+
- 'Never treat "Warning: Cache save failed." as a hard error when using static cache keys
|
|
123
|
+
across repeated runs — add continue-on-error: true to the save step if the warning
|
|
124
|
+
is expected and the restored cache is already valid'
|
|
125
|
+
- 'For programmatic use via @actions/cache npm package, check the return value of
|
|
126
|
+
restoreCache() before calling saveCache() — skip save when result === primaryKey'
|
|
127
|
+
docs:
|
|
128
|
+
- url: 'https://github.com/actions/cache/issues/1707'
|
|
129
|
+
label: 'actions/cache#1707 — Unable to reserve cache (actions/cache/save@v5)'
|
|
130
|
+
- url: 'https://github.com/actions/cache/tree/main/save#readme'
|
|
131
|
+
label: 'actions/cache save action README — Case 1: reuse key as-is'
|
|
132
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows'
|
|
133
|
+
label: 'GitHub Docs — Caching dependencies to speed up workflows'
|
package/errors/concurrency-timing/workflow-run-head-branch-null-schedule-dispatch-concurrency.yml
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
id: concurrency-timing-055
|
|
2
|
+
title: '`github.event.workflow_run.head_branch` is null for `schedule`- and `workflow_dispatch`-triggered
|
|
3
|
+
parent workflows — concurrency group key collapses all downstream runs into one slot'
|
|
4
|
+
category: concurrency-timing
|
|
5
|
+
severity: silent-failure
|
|
6
|
+
tags:
|
|
7
|
+
- workflow_run
|
|
8
|
+
- concurrency
|
|
9
|
+
- head_branch
|
|
10
|
+
- schedule
|
|
11
|
+
- null-key
|
|
12
|
+
- deployment
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: 'on:\s+workflow_run:'
|
|
15
|
+
flags: 'si'
|
|
16
|
+
- regex: 'group:.*event\.workflow_run\.head_branch'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
error_messages:
|
|
19
|
+
- "Canceling since a higher priority waiting run was found for the same concurrency group"
|
|
20
|
+
- "This run has been cancelled. Concurrency group: deploy-"
|
|
21
|
+
root_cause: |
|
|
22
|
+
`github.event.workflow_run.head_branch` is null/empty when the triggering (upstream)
|
|
23
|
+
workflow was itself triggered by `schedule`, `workflow_dispatch`, `repository_dispatch`,
|
|
24
|
+
or any other non-branch event. Only workflows triggered by branch-based events (push,
|
|
25
|
+
pull_request, etc.) produce a non-null head_branch value.
|
|
26
|
+
|
|
27
|
+
The standard recommendation for workflow_run-triggered workflows (see also
|
|
28
|
+
concurrency-timing-045) is to key the concurrency group on head_branch:
|
|
29
|
+
|
|
30
|
+
concurrency:
|
|
31
|
+
group: deploy-${{ github.event.workflow_run.head_branch }}
|
|
32
|
+
|
|
33
|
+
For branch-based parent triggers this works correctly. For schedule- or
|
|
34
|
+
workflow_dispatch-triggered parent workflows, head_branch is null, making the
|
|
35
|
+
concurrency group key evaluate to `deploy-` (empty suffix). Every downstream run
|
|
36
|
+
where the parent was triggered by schedule or dispatch shares the SAME concurrency
|
|
37
|
+
slot. The second scheduled downstream run cancels the first — silently, because
|
|
38
|
+
`${{ null }}` evaluates to an empty string in GitHub Actions expressions with no
|
|
39
|
+
warning or error.
|
|
40
|
+
|
|
41
|
+
This is commonly introduced when teams follow a deploy-after-CI pattern where the
|
|
42
|
+
nightly build (schedule) triggers a downstream deploy/notify workflow_run workflow
|
|
43
|
+
and copy the branch-scoped concurrency pattern from another workflow.
|
|
44
|
+
fix: |
|
|
45
|
+
Add a fallback value to handle null head_branch, or use a more robust key.
|
|
46
|
+
|
|
47
|
+
Option 1 — head_branch with workflow_run.id fallback (recommended):
|
|
48
|
+
Use head_branch when available (branch-based parent) and fall back to the unique
|
|
49
|
+
workflow_run id (schedule/dispatch parent) to guarantee no cross-run collisions.
|
|
50
|
+
|
|
51
|
+
Option 2 — workflow_run.id only:
|
|
52
|
+
If the workflow_run-triggered downstream workflow is exclusively for non-branch
|
|
53
|
+
parents (schedule, dispatch), key the group on github.event.workflow_run.id.
|
|
54
|
+
Every downstream run gets its own unique slot.
|
|
55
|
+
|
|
56
|
+
Option 3 — Restrict trigger with branches: filter:
|
|
57
|
+
Limit the workflow_run trigger to branch-based parent runs using `branches:`.
|
|
58
|
+
Schedule/dispatch-triggered completions are silently ignored so there is no
|
|
59
|
+
concurrency collision to manage.
|
|
60
|
+
fix_code:
|
|
61
|
+
- language: yaml
|
|
62
|
+
label: 'WRONG — head_branch is null for schedule-triggered parents; all runs share one slot'
|
|
63
|
+
code: |
|
|
64
|
+
on:
|
|
65
|
+
workflow_run:
|
|
66
|
+
workflows: ["Nightly Build"]
|
|
67
|
+
types: [completed]
|
|
68
|
+
|
|
69
|
+
concurrency:
|
|
70
|
+
group: deploy-${{ github.event.workflow_run.head_branch }}
|
|
71
|
+
cancel-in-progress: true
|
|
72
|
+
|
|
73
|
+
jobs:
|
|
74
|
+
deploy:
|
|
75
|
+
if: github.event.workflow_run.conclusion == 'success'
|
|
76
|
+
runs-on: ubuntu-latest
|
|
77
|
+
steps:
|
|
78
|
+
- run: echo "Deploying..."
|
|
79
|
+
- language: yaml
|
|
80
|
+
label: 'RIGHT — fallback to workflow_run.id prevents slot collision for schedule parents'
|
|
81
|
+
code: |
|
|
82
|
+
on:
|
|
83
|
+
workflow_run:
|
|
84
|
+
workflows: ["Nightly Build"]
|
|
85
|
+
types: [completed]
|
|
86
|
+
|
|
87
|
+
# head_branch is populated for push/pull_request-triggered parents
|
|
88
|
+
# workflow_run.id is always unique — prevents cross-run collision for schedule/dispatch parents
|
|
89
|
+
concurrency:
|
|
90
|
+
group: deploy-${{ github.event.workflow_run.head_branch || github.event.workflow_run.id }}
|
|
91
|
+
cancel-in-progress: true
|
|
92
|
+
|
|
93
|
+
jobs:
|
|
94
|
+
deploy:
|
|
95
|
+
if: github.event.workflow_run.conclusion == 'success'
|
|
96
|
+
runs-on: ubuntu-latest
|
|
97
|
+
steps:
|
|
98
|
+
- run: echo "Deploying commit ${{ github.event.workflow_run.head_sha }}"
|
|
99
|
+
- language: yaml
|
|
100
|
+
label: 'RIGHT — restrict workflow_run to branch-based parents only'
|
|
101
|
+
code: |
|
|
102
|
+
on:
|
|
103
|
+
workflow_run:
|
|
104
|
+
workflows: ["CI"]
|
|
105
|
+
types: [completed]
|
|
106
|
+
branches: [main, 'release/**']
|
|
107
|
+
# schedule- and workflow_dispatch-triggered parent completions have no branch;
|
|
108
|
+
# the branches: filter excludes them, so no null head_branch issue
|
|
109
|
+
|
|
110
|
+
concurrency:
|
|
111
|
+
group: deploy-${{ github.event.workflow_run.head_branch }}
|
|
112
|
+
cancel-in-progress: true
|
|
113
|
+
|
|
114
|
+
jobs:
|
|
115
|
+
deploy:
|
|
116
|
+
if: github.event.workflow_run.conclusion == 'success'
|
|
117
|
+
runs-on: ubuntu-latest
|
|
118
|
+
steps:
|
|
119
|
+
- run: echo "Deploying branch ${{ github.event.workflow_run.head_branch }}"
|
|
120
|
+
prevention:
|
|
121
|
+
- 'Always check whether parent workflows may be triggered by schedule or workflow_dispatch before
|
|
122
|
+
keying a workflow_run downstream concurrency group on head_branch.'
|
|
123
|
+
- 'Add a || fallback for any workflow_run context property that may be null — head_branch, head_sha,
|
|
124
|
+
and pull_requests are null for schedule/dispatch-triggered parents.'
|
|
125
|
+
- 'Add a debug step that echoes github.event.workflow_run.head_branch early in the workflow to verify
|
|
126
|
+
it is populated for all expected parent trigger types during initial rollout.'
|
|
127
|
+
- 'Use branches: on the workflow_run trigger to restrict to branch-based events if schedule/dispatch
|
|
128
|
+
parent completions do not need to be handled.'
|
|
129
|
+
docs:
|
|
130
|
+
- url: 'https://docs.github.com/en/webhooks/webhook-events-and-payloads#workflow_run'
|
|
131
|
+
label: 'GitHub Webhook Docs: workflow_run payload — head_branch property'
|
|
132
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_run'
|
|
133
|
+
label: 'GitHub Docs: workflow_run event trigger'
|
|
134
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/using-concurrency'
|
|
135
|
+
label: 'GitHub Docs: Using concurrency'
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
id: known-unsolved-066
|
|
2
|
+
title: 'Node Action Post Step Receives Wrong INPUT_* Env Vars When Called Through Nested Composite Action'
|
|
3
|
+
category: known-unsolved
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- composite-actions
|
|
7
|
+
- post-step
|
|
8
|
+
- node-action
|
|
9
|
+
- nested
|
|
10
|
+
- inputs
|
|
11
|
+
- runner-bug
|
|
12
|
+
- savestate
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: 'Input required and not supplied:\s*\S+'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'Post job cleanup\.\s*\n.*Input required'
|
|
17
|
+
flags: 'im'
|
|
18
|
+
- regex: 'post.*wrong.*input|INPUT_.*post.*ancestor'
|
|
19
|
+
flags: 'i'
|
|
20
|
+
error_messages:
|
|
21
|
+
- 'Input required and not supplied: token'
|
|
22
|
+
- 'Input required and not supplied: test'
|
|
23
|
+
- 'Error: Input required and not supplied: <input-name>'
|
|
24
|
+
- 'Post job cleanup.'
|
|
25
|
+
root_cause: |
|
|
26
|
+
Runner bug (actions/runner#3514, actions/runner#2030, open since 2022): when a Node.js
|
|
27
|
+
action that has a `post:` step is invoked through one or more composite action layers,
|
|
28
|
+
the runner restores the wrong `INPUT_*` environment variables for the post step execution.
|
|
29
|
+
|
|
30
|
+
At post-step execution time, the runner sets environment variables from the nearest
|
|
31
|
+
ancestor composite action's inputs, not from the inputs actually passed to the Node
|
|
32
|
+
action itself. For example:
|
|
33
|
+
|
|
34
|
+
Workflow → outer-composite (inputs: image-tag: "foo") → inner-composite
|
|
35
|
+
→ node-action (inputs: image-tag: "foo")
|
|
36
|
+
|
|
37
|
+
The node action's main step correctly sees INPUT_IMAGE_TAG=foo.
|
|
38
|
+
In the post step, INPUT_IMAGE_TAG is absent or overwritten by the outer composite's
|
|
39
|
+
INPUT_IMAGE_TAG value (or another ancestor composite's value), causing:
|
|
40
|
+
- Required inputs to appear missing → visible error in post cleanup
|
|
41
|
+
- Optional inputs to resolve to wrong values → silent wrong behavior (e.g.,
|
|
42
|
+
devcontainers/ci pushes image with wrong tag; codeql-action uploads SARIF with
|
|
43
|
+
wrong token)
|
|
44
|
+
|
|
45
|
+
This affects ANY Node action with a post step that is called through composite
|
|
46
|
+
action nesting (depth ≥ 2). First-party actions affected include github/codeql-action
|
|
47
|
+
(fixed via workaround in codeql-action#2557) and pnpm/action-setup (issue #253).
|
|
48
|
+
fix: |
|
|
49
|
+
GitHub has not fixed the runner bug. The canonical workaround is to persist inputs
|
|
50
|
+
in the action's main step using `core.saveState()` and read them back in the post
|
|
51
|
+
step using `core.getState()` instead of `core.getInput()`.
|
|
52
|
+
|
|
53
|
+
Actions consuming this workaround pattern:
|
|
54
|
+
- github/codeql-action (PR #2557): saveState for upload inputs
|
|
55
|
+
- Any action that reads inputs in its post step
|
|
56
|
+
|
|
57
|
+
If you maintain a Node action with a post step, add to your main.ts:
|
|
58
|
+
core.saveState('my-input', core.getInput('my-input'));
|
|
59
|
+
And in your post.ts:
|
|
60
|
+
const val = core.getState('my-input'); // use this instead of core.getInput
|
|
61
|
+
|
|
62
|
+
If you are a workflow author calling a third-party action through composite layers
|
|
63
|
+
and seeing wrong post-step behavior, check whether the action uses `core.getInput`
|
|
64
|
+
in its post step. If so, file an issue with the action maintainer referencing
|
|
65
|
+
actions/runner#3514 and the saveState workaround.
|
|
66
|
+
fix_code:
|
|
67
|
+
- language: typescript
|
|
68
|
+
label: 'Action main.ts — persist inputs to state before post step runs'
|
|
69
|
+
code: |
|
|
70
|
+
import * as core from '@actions/core';
|
|
71
|
+
|
|
72
|
+
async function run() {
|
|
73
|
+
// Read inputs normally in main
|
|
74
|
+
const token = core.getInput('token', { required: true });
|
|
75
|
+
const imageName = core.getInput('image-name');
|
|
76
|
+
|
|
77
|
+
// Persist for post step (workaround for runner#3514)
|
|
78
|
+
core.saveState('token', token);
|
|
79
|
+
core.saveState('image-name', imageName);
|
|
80
|
+
|
|
81
|
+
// ... rest of main logic
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
run();
|
|
85
|
+
- language: typescript
|
|
86
|
+
label: 'Action post.ts — read from state, NOT core.getInput'
|
|
87
|
+
code: |
|
|
88
|
+
import * as core from '@actions/core';
|
|
89
|
+
|
|
90
|
+
async function runPost() {
|
|
91
|
+
// Use getState, NOT getInput — inputs are wrong in post step
|
|
92
|
+
// when called through nested composite action (runner#3514)
|
|
93
|
+
const token = core.getState('token');
|
|
94
|
+
const imageName = core.getState('image-name');
|
|
95
|
+
|
|
96
|
+
// ... post step logic using state values
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
runPost();
|
|
100
|
+
- language: yaml
|
|
101
|
+
label: 'action.yml — declare post step'
|
|
102
|
+
code: |
|
|
103
|
+
name: 'My Action'
|
|
104
|
+
inputs:
|
|
105
|
+
token:
|
|
106
|
+
required: true
|
|
107
|
+
image-name:
|
|
108
|
+
required: false
|
|
109
|
+
runs:
|
|
110
|
+
using: 'node20'
|
|
111
|
+
main: 'dist/main.js'
|
|
112
|
+
post: 'dist/post.js'
|
|
113
|
+
post-if: always()
|
|
114
|
+
prevention:
|
|
115
|
+
- 'In any Node action with a post: step, always use core.saveState/core.getState for
|
|
116
|
+
inputs consumed in post, never core.getInput — this is defensive programming regardless
|
|
117
|
+
of nesting depth'
|
|
118
|
+
- 'Test your action in a composite action wrapper (at least 2 layers deep) to catch
|
|
119
|
+
this bug before publishing'
|
|
120
|
+
- 'Check release notes of actions/runner for fixes to this bug before assuming
|
|
121
|
+
the built-in behavior is fixed'
|
|
122
|
+
- 'When using actions with known post-step input bugs through composite layers,
|
|
123
|
+
consider calling them directly from the workflow (not nested in a composite) as
|
|
124
|
+
a temporary workaround'
|
|
125
|
+
docs:
|
|
126
|
+
- url: 'https://github.com/actions/runner/issues/3514'
|
|
127
|
+
label: 'actions/runner#3514 — Wrong environment passed to node post when called by composite called by composite'
|
|
128
|
+
- url: 'https://github.com/actions/runner/issues/2030'
|
|
129
|
+
label: 'actions/runner#2030 — Composite: Nested actions post steps have the wrong context (open since 2022)'
|
|
130
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#sending-values-to-the-pre-and-post-actions'
|
|
131
|
+
label: 'GitHub Docs — Sending values to pre and post actions (saveState/getState)'
|
|
132
|
+
- url: 'https://github.com/github/codeql-action/pull/2557'
|
|
133
|
+
label: 'codeql-action#2557 — Fix: persist inputs between upload action and post step (reference implementation)'
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
id: known-unsolved-065
|
|
2
|
+
title: 'ubuntu-24.04-arm64 Hosted Runner Kernel Missing binder_linux and ashmem_linux Modules — Android Container Tests Fail'
|
|
3
|
+
category: known-unsolved
|
|
4
|
+
severity: limitation
|
|
5
|
+
tags:
|
|
6
|
+
- ubuntu-24.04-arm64
|
|
7
|
+
- arm64
|
|
8
|
+
- kernel-modules
|
|
9
|
+
- android
|
|
10
|
+
- binder
|
|
11
|
+
- ashmem
|
|
12
|
+
- container
|
|
13
|
+
- known-limitation
|
|
14
|
+
patterns:
|
|
15
|
+
- regex: 'modprobe: FATAL: Module binder_linux not found|modprobe.*binder_linux.*not found'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: 'modprobe: FATAL: Module ashmem_linux not found|modprobe.*ashmem_linux.*not found'
|
|
18
|
+
flags: 'i'
|
|
19
|
+
- regex: '/dev/binder: No such file or directory|/dev/ashmem: No such file or directory'
|
|
20
|
+
flags: 'i'
|
|
21
|
+
- regex: 'CONFIG_ANDROID_BINDER_IPC.*not set|binder_linux.*absent.*kernel'
|
|
22
|
+
flags: 'i'
|
|
23
|
+
error_messages:
|
|
24
|
+
- 'modprobe: FATAL: Module binder_linux not found in directory /lib/modules/<kernel>'
|
|
25
|
+
- 'modprobe: FATAL: Module ashmem_linux not found in directory /lib/modules/<kernel>'
|
|
26
|
+
- '/dev/binder: No such file or directory'
|
|
27
|
+
- '/dev/ashmem: No such file or directory'
|
|
28
|
+
- 'modprobe binder_linux exited with code 1'
|
|
29
|
+
root_cause: |
|
|
30
|
+
The ubuntu-24.04-arm64 GitHub Actions hosted runner kernel is compiled WITHOUT
|
|
31
|
+
`CONFIG_ANDROID_BINDER_IPC=m` and `CONFIG_ANDROID_BINDERFS=m`. This means the
|
|
32
|
+
`binder_linux` and `ashmem_linux` kernel modules do not exist in
|
|
33
|
+
`/lib/modules/$(uname -r)/` on ARM64 runners.
|
|
34
|
+
|
|
35
|
+
Attempting `modprobe binder_linux` fails silently (exits 1) on ARM64 because
|
|
36
|
+
the module is simply absent from the kernel tree — it cannot be loaded even
|
|
37
|
+
as a privileged container.
|
|
38
|
+
|
|
39
|
+
**Why x86_64 hosted runners DO have these modules:**
|
|
40
|
+
The x86_64 ubuntu-24.04 hosted runners expose `binder` and `ashmem` because
|
|
41
|
+
they support the [GitHub Actions KVM Android hardware acceleration feature](https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/)
|
|
42
|
+
(released April 2024). The x86_64 kernel was explicitly built with Android
|
|
43
|
+
IPC support to enable this feature. The ARM64 kernel image is compiled
|
|
44
|
+
separately and was not built with these modules.
|
|
45
|
+
|
|
46
|
+
**Affected use cases:**
|
|
47
|
+
- Running [ReDroid](https://github.com/remote-android/redroid-doc) (GPU-enabled
|
|
48
|
+
Android-in-Docker) on native ARM64 CI for ARM-native app testing
|
|
49
|
+
- Running [Waydroid](https://waydro.id/) in ARM64 CI containers
|
|
50
|
+
- Any workflow that requires `/dev/binder` or `/dev/ashmem` devices
|
|
51
|
+
|
|
52
|
+
**Confirmed on:**
|
|
53
|
+
- ubuntu-24.04-arm64 image 20260531.15.1 (kernel aarch64, Azure westus2)
|
|
54
|
+
- Source: actions/runner-images#14184 (feature request, June 2026, open)
|
|
55
|
+
|
|
56
|
+
**No current workaround exists** — the module cannot be compiled from source
|
|
57
|
+
against the runner's kernel headers without the kernel source tree, and the
|
|
58
|
+
azure-linux kernel for ARM64 is not shipped with headers for out-of-tree
|
|
59
|
+
`binder_linux` builds. A request to add the modules to the ubuntu-24.04-arm64
|
|
60
|
+
image is tracked at runner-images#14184 and is currently open with no ETA.
|
|
61
|
+
fix: |
|
|
62
|
+
**No complete fix is currently available for native ARM64 hosted runners.**
|
|
63
|
+
|
|
64
|
+
**Option 1 (Recommended): Use ubuntu-24.04 x86_64 runners for Android tests**
|
|
65
|
+
|
|
66
|
+
The x86_64 ubuntu-24.04 runner has `binder_linux` and `ashmem_linux` and
|
|
67
|
+
supports Android container tests via KVM acceleration. ARM-native testing can
|
|
68
|
+
be approximated via the Android native bridge, at the cost of some overhead:
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
android-test:
|
|
72
|
+
runs-on: ubuntu-24.04 # x86_64 — has binder_linux/ashmem_linux
|
|
73
|
+
steps:
|
|
74
|
+
- uses: actions/checkout@v6
|
|
75
|
+
- run: |
|
|
76
|
+
sudo modprobe binder_linux # succeeds on x86_64
|
|
77
|
+
sudo modprobe ashmem_linux
|
|
78
|
+
# ... run ReDroid or Waydroid Android container tests
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Option 2: Use real ARM hardware (Firebase Test Lab, self-hosted)**
|
|
82
|
+
|
|
83
|
+
For true ARM64 profiling (power/wakelock, native execution) use Firebase
|
|
84
|
+
Test Lab with physical Pixel hardware, or a self-hosted ARM64 runner on
|
|
85
|
+
hardware/VMs that expose binder devices.
|
|
86
|
+
|
|
87
|
+
**Option 3: Compile binder_linux from source (complex, unreliable)**
|
|
88
|
+
|
|
89
|
+
Without kernel headers matching the runner kernel, this is not practical
|
|
90
|
+
on GitHub-hosted runners.
|
|
91
|
+
|
|
92
|
+
**Track for a platform fix:** Follow actions/runner-images#14184 for progress
|
|
93
|
+
on adding `binder_linux`/`ashmem_linux` to the ubuntu-24.04-arm64 runner image.
|
|
94
|
+
fix_code:
|
|
95
|
+
- language: yaml
|
|
96
|
+
label: 'Route Android container tests to x86_64 runner which has binder_linux/ashmem_linux'
|
|
97
|
+
code: |
|
|
98
|
+
jobs:
|
|
99
|
+
android-container-test:
|
|
100
|
+
# ubuntu-24.04-arm64 runner kernel is compiled without CONFIG_ANDROID_BINDER_IPC=m
|
|
101
|
+
# Use x86_64 runner which has binder_linux/ashmem_linux for KVM Android acceleration.
|
|
102
|
+
# Track runner-images#14184 for ARM64 kernel module support.
|
|
103
|
+
runs-on: ubuntu-24.04 # x86_64 — binder_linux available
|
|
104
|
+
container:
|
|
105
|
+
image: redroid/redroid:15.0.0-latest
|
|
106
|
+
options: --privileged
|
|
107
|
+
steps:
|
|
108
|
+
- uses: actions/checkout@v6
|
|
109
|
+
- name: Verify binder device
|
|
110
|
+
run: ls -la /dev/binder /dev/ashmem
|
|
111
|
+
- name: Run instrumented tests
|
|
112
|
+
run: ./gradlew connectedAndroidTest
|
|
113
|
+
- language: yaml
|
|
114
|
+
label: 'Guard ARM64 jobs against missing kernel modules'
|
|
115
|
+
code: |
|
|
116
|
+
jobs:
|
|
117
|
+
android-test:
|
|
118
|
+
runs-on: ${{ matrix.runner }}
|
|
119
|
+
strategy:
|
|
120
|
+
matrix:
|
|
121
|
+
runner: [ubuntu-24.04, ubuntu-24.04-arm64]
|
|
122
|
+
steps:
|
|
123
|
+
- uses: actions/checkout@v6
|
|
124
|
+
- name: Check binder_linux availability
|
|
125
|
+
id: binder-check
|
|
126
|
+
run: |
|
|
127
|
+
if modprobe binder_linux 2>/dev/null; then
|
|
128
|
+
echo "available=true" >> "$GITHUB_OUTPUT"
|
|
129
|
+
else
|
|
130
|
+
echo "available=false" >> "$GITHUB_OUTPUT"
|
|
131
|
+
echo "::warning::binder_linux not available on $(uname -m) runner. Skipping Android container tests."
|
|
132
|
+
fi
|
|
133
|
+
- name: Run Android container tests
|
|
134
|
+
if: steps.binder-check.outputs.available == 'true'
|
|
135
|
+
run: ./run-android-tests.sh
|
|
136
|
+
prevention:
|
|
137
|
+
- 'Do not assume binder_linux or ashmem_linux are available on ubuntu-24.04-arm64 hosted runners — the kernel was not built with CONFIG_ANDROID_BINDER_IPC=m.'
|
|
138
|
+
- 'Route Android container (ReDroid/Waydroid) CI tests to x86_64 ubuntu-24.04 runners until runner-images#14184 is resolved.'
|
|
139
|
+
- 'Always guard binder_linux/ashmem_linux modprobe calls with an availability check so ARM64 jobs fail gracefully rather than unexpectedly.'
|
|
140
|
+
- 'Track the ARM64 runner image feature request at actions/runner-images#14184 to know when the modules are added.'
|
|
141
|
+
docs:
|
|
142
|
+
- url: 'https://github.com/actions/runner-images/issues/14184'
|
|
143
|
+
label: 'runner-images #14184 — Add binder_linux and ashmem_linux kernel modules to ubuntu-24.04-arm image (open Jun 2026)'
|
|
144
|
+
- url: 'https://github.com/remote-android/redroid-doc/issues/928'
|
|
145
|
+
label: 'redroid-doc #928 — GitHub Actions ubuntu-24.04-arm runners lack binder/ashmem kernel modules'
|
|
146
|
+
- url: 'https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/'
|
|
147
|
+
label: 'GitHub Changelog — Hardware-accelerated Android virtualization on x86_64 Actions runners'
|
|
148
|
+
- url: 'https://github.com/actions/runner-images/releases/tag/ubuntu24-arm64%2F20260531.15'
|
|
149
|
+
label: 'ubuntu-24.04-arm64 image 20260531.15.1 release notes'
|