@htekdev/actions-debugger 1.0.55 → 1.0.57
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-038.yml +95 -0
- package/errors/caching-artifacts/caching-artifacts-039.yml +110 -0
- package/errors/concurrency-timing/concurrency-timing-033.yml +104 -0
- package/errors/concurrency-timing/concurrency-timing-034.yml +123 -0
- package/errors/known-unsolved/known-unsolved-037.yml +124 -0
- package/errors/known-unsolved/known-unsolved-038.yml +124 -0
- package/errors/known-unsolved/known-unsolved-039.yml +102 -0
- package/errors/permissions-auth/permissions-auth-040.yml +142 -0
- package/errors/permissions-auth/permissions-auth-041.yml +110 -0
- package/errors/runner-environment/runner-environment-112.yml +98 -0
- package/errors/runner-environment/runner-environment-113.yml +118 -0
- package/errors/runner-environment/runner-environment-114.yml +130 -0
- package/errors/runner-environment/runner-environment-115.yml +120 -0
- package/errors/runner-environment/runner-environment-116.yml +106 -0
- package/errors/runner-environment/runner-environment-117.yml +109 -0
- package/errors/silent-failures/silent-failures-056.yml +105 -0
- package/errors/silent-failures/silent-failures-057.yml +120 -0
- package/errors/silent-failures/silent-failures-058.yml +126 -0
- package/errors/triggers/triggers-040.yml +104 -0
- package/errors/triggers/triggers-041.yml +105 -0
- package/errors/triggers/triggers-042.yml +110 -0
- package/errors/triggers/triggers-043.yml +125 -0
- package/errors/yaml-syntax/yaml-syntax-040.yml +135 -0
- package/errors/yaml-syntax/yaml-syntax-041.yml +147 -0
- package/package.json +1 -1
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
id: known-unsolved-039
|
|
2
|
+
title: "on.schedule minimum interval is 5 minutes — sub-5-minute cron patterns silently run every 5 minutes"
|
|
3
|
+
category: known-unsolved
|
|
4
|
+
severity: limitation
|
|
5
|
+
tags:
|
|
6
|
+
- schedule
|
|
7
|
+
- cron
|
|
8
|
+
- on.schedule
|
|
9
|
+
- rate-limit
|
|
10
|
+
- interval
|
|
11
|
+
- minimum-frequency
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: '^\s*-\s*cron:\s*[''"]?\*\/[1-4]\s'
|
|
14
|
+
flags: 'm'
|
|
15
|
+
- regex: 'schedule.*cron.*every\s+(?:1|2|3|4)\s+minute'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
error_messages:
|
|
18
|
+
- "*/1 * * * *"
|
|
19
|
+
- "*/2 * * * *"
|
|
20
|
+
- "*/3 * * * *"
|
|
21
|
+
- "*/4 * * * *"
|
|
22
|
+
root_cause: |
|
|
23
|
+
GitHub Actions enforces a minimum cron schedule interval of 5 minutes. Cron
|
|
24
|
+
expressions that would trigger more frequently — such as */1, */2, */3, or */4
|
|
25
|
+
in the minutes field — are silently capped and run every 5 minutes instead of
|
|
26
|
+
the configured interval.
|
|
27
|
+
|
|
28
|
+
There is no validation error, no warning in workflow run logs, and no annotation
|
|
29
|
+
on the workflow YAML file. The workflow appears correctly configured in the GitHub
|
|
30
|
+
UI, but runs execute every 5 minutes regardless of the specified granularity.
|
|
31
|
+
|
|
32
|
+
This limitation is enforced server-side by GitHub's scheduler and cannot be
|
|
33
|
+
overridden via any workflow configuration. It applies to all hosted runners and
|
|
34
|
+
self-hosted runners triggered via GitHub's scheduler.
|
|
35
|
+
|
|
36
|
+
Additionally, even at the 5-minute minimum, scheduled workflows on busy
|
|
37
|
+
repositories may be delayed further during periods of high GitHub Actions load.
|
|
38
|
+
Under heavy load, schedules are queued and run as capacity allows — not
|
|
39
|
+
necessarily at the exact scheduled time. The schedule event documentation notes
|
|
40
|
+
that schedules may be delayed "up to hours" when load is high.
|
|
41
|
+
|
|
42
|
+
Common developer mental model mismatch: developers migrating from cron daemons
|
|
43
|
+
(systemd, cron, AWS EventBridge) where sub-minute schedules are routine expect
|
|
44
|
+
GitHub Actions to support the same granularity.
|
|
45
|
+
fix: |
|
|
46
|
+
Use a minimum interval of 5 minutes in your cron expression — replace */1,
|
|
47
|
+
*/2, */3, or */4 in the minutes field with */5.
|
|
48
|
+
|
|
49
|
+
If sub-5-minute polling or execution is required, use an external trigger
|
|
50
|
+
mechanism instead of on.schedule:
|
|
51
|
+
|
|
52
|
+
- External scheduler (AWS EventBridge, Azure Logic Apps, GCP Cloud Scheduler)
|
|
53
|
+
that calls the workflow_dispatch REST API
|
|
54
|
+
- A self-hosted runner with a local cron daemon (systemd timer, Linux cron)
|
|
55
|
+
that invokes the GitHub API to dispatch the workflow
|
|
56
|
+
- Move the time-sensitive logic out of GitHub Actions entirely and run it
|
|
57
|
+
in a dedicated service that can be triggered at any frequency
|
|
58
|
+
fix_code:
|
|
59
|
+
- language: yaml
|
|
60
|
+
label: "Minimum supported interval — every 5 minutes"
|
|
61
|
+
code: |
|
|
62
|
+
on:
|
|
63
|
+
schedule:
|
|
64
|
+
# Minimum supported interval is every 5 minutes
|
|
65
|
+
- cron: '*/5 * * * *'
|
|
66
|
+
# The following are silently capped to every 5 minutes:
|
|
67
|
+
# - cron: '*/1 * * * *'
|
|
68
|
+
# - cron: '*/2 * * * *'
|
|
69
|
+
# - cron: '*/3 * * * *'
|
|
70
|
+
# - cron: '*/4 * * * *'
|
|
71
|
+
- language: yaml
|
|
72
|
+
label: "workflow_dispatch trigger for external scheduler integration"
|
|
73
|
+
code: |
|
|
74
|
+
# Trigger via REST API from an external scheduler at any frequency:
|
|
75
|
+
# POST https://api.github.com/repos/OWNER/REPO/actions/workflows/WORKFLOW.yml/dispatches
|
|
76
|
+
# Body: {"ref": "main"}
|
|
77
|
+
on:
|
|
78
|
+
workflow_dispatch:
|
|
79
|
+
inputs:
|
|
80
|
+
triggered_by:
|
|
81
|
+
description: 'Trigger source identifier'
|
|
82
|
+
type: string
|
|
83
|
+
default: 'external-scheduler'
|
|
84
|
+
|
|
85
|
+
jobs:
|
|
86
|
+
scheduled-task:
|
|
87
|
+
runs-on: ubuntu-latest
|
|
88
|
+
steps:
|
|
89
|
+
- name: Run task
|
|
90
|
+
run: echo "Triggered by ${{ inputs.triggered_by }}"
|
|
91
|
+
prevention:
|
|
92
|
+
- "Always use */5 or higher in the cron minutes field for on.schedule expressions"
|
|
93
|
+
- "Add a comment next to every cron expression documenting the intended frequency and the 5-minute minimum"
|
|
94
|
+
- "Test schedule behavior by temporarily adding an on.push trigger during development rather than waiting for scheduled runs"
|
|
95
|
+
- "For sub-5-minute needs, design the solution with an external scheduler calling workflow_dispatch from the start — do not plan to reduce the interval later"
|
|
96
|
+
docs:
|
|
97
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#schedule"
|
|
98
|
+
label: "GitHub Docs — Schedule event (on.schedule)"
|
|
99
|
+
- url: "https://stackoverflow.com/questions/63612471/run-github-actions-every-x-minutes-cron-job"
|
|
100
|
+
label: "Stack Overflow — Run GitHub Actions every X minutes (highly voted)"
|
|
101
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#schedule"
|
|
102
|
+
label: "GitHub Docs — Note on schedule delays under high load"
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
id: permissions-auth-040
|
|
2
|
+
title: "GITHUB_TOKEN is read-only by default in new repositories — write operations fail with 403"
|
|
3
|
+
category: permissions-auth
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- GITHUB_TOKEN
|
|
7
|
+
- read-only
|
|
8
|
+
- permissions
|
|
9
|
+
- 403
|
|
10
|
+
- new-repo
|
|
11
|
+
- workflow-permissions
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'remote:\s*Permission to .* denied to github-actions\[bot\]'
|
|
14
|
+
flags: i
|
|
15
|
+
- regex: 'Error:\s*Resource not accessible by integration'
|
|
16
|
+
flags: i
|
|
17
|
+
- regex: 'HttpError:\s*Resource not accessible by integration'
|
|
18
|
+
flags: i
|
|
19
|
+
- regex: '403.*github-actions\[bot\]'
|
|
20
|
+
flags: i
|
|
21
|
+
error_messages:
|
|
22
|
+
- "remote: Permission to org/repo.git denied to github-actions[bot]"
|
|
23
|
+
- "Error: Resource not accessible by integration"
|
|
24
|
+
- "HttpError: Resource not accessible by integration"
|
|
25
|
+
- "fatal: unable to access 'https://github.com/org/repo/': The requested URL returned error: 403"
|
|
26
|
+
- "GitHub Actions is not permitted to create or approve pull requests"
|
|
27
|
+
root_cause: |
|
|
28
|
+
In February 2023 (GitHub Changelog), GitHub changed the default GITHUB_TOKEN
|
|
29
|
+
permissions for all new repositories and new organizations from read-write to
|
|
30
|
+
read-only. Repositories created before this change retain their original default
|
|
31
|
+
(read-write) unless an administrator explicitly changes the org-level setting.
|
|
32
|
+
|
|
33
|
+
This creates two failure scenarios:
|
|
34
|
+
|
|
35
|
+
1. COPIED WORKFLOWS: A developer copies a workflow from an older repo or a public
|
|
36
|
+
template that relies on the default read-write GITHUB_TOKEN (for example, to push
|
|
37
|
+
a build artifact, create a release, comment on a PR, or open a pull request). In a
|
|
38
|
+
new repo, that same workflow fails with 403 or "Resource not accessible by
|
|
39
|
+
integration" because the token only has read permissions.
|
|
40
|
+
|
|
41
|
+
2. ORG POLICY CHANGE: An organization administrator enables the read-only default
|
|
42
|
+
at the organization level (Settings > Actions > General > Workflow permissions).
|
|
43
|
+
All repos in the org immediately start failing any workflow that performs write
|
|
44
|
+
operations without an explicit permissions block.
|
|
45
|
+
|
|
46
|
+
The failure message is typically cryptic and does not mention that the root cause is
|
|
47
|
+
the workflow permissions default — it only says the token was denied.
|
|
48
|
+
fix: |
|
|
49
|
+
Add explicit permissions blocks to workflows or jobs that perform write operations.
|
|
50
|
+
GitHub recommends the principle of least privilege: grant only the specific write
|
|
51
|
+
permission needed, not blanket read-write access.
|
|
52
|
+
|
|
53
|
+
At the workflow level, a top-level permissions: block sets defaults for all jobs.
|
|
54
|
+
At the job level, a permissions: block overrides the workflow-level default for that
|
|
55
|
+
job only. Job-level is preferred — it minimises the blast radius if a job is
|
|
56
|
+
compromised.
|
|
57
|
+
|
|
58
|
+
Common permissions needed:
|
|
59
|
+
- contents: write — push commits, create releases, upload release assets
|
|
60
|
+
- pull-requests: write — create/comment on pull requests
|
|
61
|
+
- issues: write — create/comment on issues
|
|
62
|
+
- packages: write — publish to GitHub Packages
|
|
63
|
+
- pages: write — deploy to GitHub Pages (also needs id-token: write for OIDC)
|
|
64
|
+
|
|
65
|
+
Alternatively, change the default at repo level: Settings > Actions > General >
|
|
66
|
+
Workflow permissions > Read and write permissions. Not recommended for security-
|
|
67
|
+
conscious teams.
|
|
68
|
+
fix_code:
|
|
69
|
+
- language: yaml
|
|
70
|
+
label: "Problem: workflow relies on default write token, fails in new repos"
|
|
71
|
+
code: |
|
|
72
|
+
# No permissions block — relies on default, which is READ-ONLY in new repos
|
|
73
|
+
on: push
|
|
74
|
+
|
|
75
|
+
jobs:
|
|
76
|
+
release:
|
|
77
|
+
runs-on: ubuntu-latest
|
|
78
|
+
steps:
|
|
79
|
+
- uses: actions/checkout@v4
|
|
80
|
+
- name: Build
|
|
81
|
+
run: npm run build
|
|
82
|
+
- name: Create GitHub Release
|
|
83
|
+
uses: softprops/action-gh-release@v2
|
|
84
|
+
with:
|
|
85
|
+
files: dist/**
|
|
86
|
+
# Fails with 403 in new repos — needs contents:write
|
|
87
|
+
- language: yaml
|
|
88
|
+
label: "Fix: explicit job-level permissions (least privilege)"
|
|
89
|
+
code: |
|
|
90
|
+
on: push
|
|
91
|
+
|
|
92
|
+
jobs:
|
|
93
|
+
release:
|
|
94
|
+
runs-on: ubuntu-latest
|
|
95
|
+
permissions:
|
|
96
|
+
contents: write # Required to create releases and upload assets
|
|
97
|
+
steps:
|
|
98
|
+
- uses: actions/checkout@v4
|
|
99
|
+
- name: Build
|
|
100
|
+
run: npm run build
|
|
101
|
+
- name: Create GitHub Release
|
|
102
|
+
uses: softprops/action-gh-release@v2
|
|
103
|
+
with:
|
|
104
|
+
files: dist/**
|
|
105
|
+
- language: yaml
|
|
106
|
+
label: "Workflow-level permissions (when multiple jobs all need write access)"
|
|
107
|
+
code: |
|
|
108
|
+
on: push
|
|
109
|
+
|
|
110
|
+
# Set workflow-level default — overridden per job as needed
|
|
111
|
+
permissions:
|
|
112
|
+
contents: write
|
|
113
|
+
pull-requests: write
|
|
114
|
+
|
|
115
|
+
jobs:
|
|
116
|
+
build-and-release:
|
|
117
|
+
runs-on: ubuntu-latest
|
|
118
|
+
# Inherits workflow-level permissions
|
|
119
|
+
steps:
|
|
120
|
+
- uses: actions/checkout@v4
|
|
121
|
+
- run: npm run build
|
|
122
|
+
|
|
123
|
+
comment-on-pr:
|
|
124
|
+
runs-on: ubuntu-latest
|
|
125
|
+
permissions:
|
|
126
|
+
pull-requests: write # Job-level — more restrictive than workflow default
|
|
127
|
+
contents: read
|
|
128
|
+
steps:
|
|
129
|
+
- uses: actions/checkout@v4
|
|
130
|
+
prevention:
|
|
131
|
+
- "Always declare explicit permissions blocks in workflows that push, create releases, comment, or deploy — never rely on defaults"
|
|
132
|
+
- "Run 'actionlint' locally — it warns when a workflow uses write-requiring actions without corresponding permissions"
|
|
133
|
+
- "Use the minimum permissions required: grant 'contents: write' only on jobs that need it, not at workflow level"
|
|
134
|
+
- "When copying a workflow from another repo, check whether it has a permissions block — add one if missing"
|
|
135
|
+
- "Review the GitHub Actions audit log when a workflow fails with 403 to confirm the token permissions in use"
|
|
136
|
+
docs:
|
|
137
|
+
- url: "https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#permissions-for-the-github_token"
|
|
138
|
+
label: "GitHub Docs: GITHUB_TOKEN permissions"
|
|
139
|
+
- url: "https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#setting-the-permissions-of-the-github_token-for-your-repository"
|
|
140
|
+
label: "GitHub Docs: Setting default workflow permissions"
|
|
141
|
+
- url: "https://github.blog/changelog/2023-02-02-github-actions-updating-the-default-github_token-permissions-to-read-only/"
|
|
142
|
+
label: "GitHub Changelog: Default GITHUB_TOKEN permissions changed to read-only (Feb 2023)"
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
id: permissions-auth-041
|
|
2
|
+
title: "actions/checkout submodules fail with auth error when private submodule repos are outside the workflow repository"
|
|
3
|
+
category: permissions-auth
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- checkout
|
|
7
|
+
- submodules
|
|
8
|
+
- github-token
|
|
9
|
+
- private-repo
|
|
10
|
+
- authentication
|
|
11
|
+
- pat
|
|
12
|
+
- deploy-key
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: 'fatal: could not read Username for.*terminal prompts disabled'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'fatal: repository ''.*github\.com.*'' not found'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
- regex: 'remote: Repository not found\.'
|
|
19
|
+
flags: 'i'
|
|
20
|
+
- regex: 'Error: The process.*git.*failed with exit code 128'
|
|
21
|
+
flags: 'i'
|
|
22
|
+
error_messages:
|
|
23
|
+
- "fatal: could not read Username for 'https://github.com': terminal prompts disabled"
|
|
24
|
+
- "fatal: repository 'https://github.com/org/private-submodule/' not found"
|
|
25
|
+
- "remote: Repository not found."
|
|
26
|
+
- "Error: The process '/usr/bin/git' failed with exit code 128"
|
|
27
|
+
root_cause: |
|
|
28
|
+
`actions/checkout` uses the `GITHUB_TOKEN` (or the `token` input) to authenticate
|
|
29
|
+
git operations during checkout, including recursive submodule initialization.
|
|
30
|
+
`GITHUB_TOKEN` is automatically scoped to the repository that owns the running
|
|
31
|
+
workflow — it cannot access private repositories in other organizations, or other
|
|
32
|
+
private repositories within the same organization.
|
|
33
|
+
|
|
34
|
+
When a submodule `.gitmodules` entry points to a private repository that is different
|
|
35
|
+
from the workflow repository, git authentication fails during `submodule update`.
|
|
36
|
+
The resulting error (`fatal: could not read Username` or `repository not found`)
|
|
37
|
+
is confusing because the submodule URL is correct — the problem is authentication
|
|
38
|
+
scope, not the URL itself.
|
|
39
|
+
|
|
40
|
+
Developers upgrading from self-hosted runners (where global git credentials were
|
|
41
|
+
configured) or from `actions/checkout@v1-v2` (which had different authentication
|
|
42
|
+
behavior) frequently encounter this when moving to `actions/checkout@v4` on
|
|
43
|
+
GitHub-hosted runners.
|
|
44
|
+
|
|
45
|
+
This is a deliberate security boundary: `GITHUB_TOKEN` is intentionally limited to
|
|
46
|
+
the current repository to prevent workflows from silently reading other private repos.
|
|
47
|
+
fix: |
|
|
48
|
+
Use one of two approaches:
|
|
49
|
+
|
|
50
|
+
1. **PAT approach**: Create a Personal Access Token (classic PAT with `repo` scope,
|
|
51
|
+
or a fine-grained PAT with read access to all submodule repos). Store it as a
|
|
52
|
+
repository secret and pass it via the `token` input to `actions/checkout`.
|
|
53
|
+
|
|
54
|
+
2. **Deploy key approach**: Add a read-only deploy key to each private submodule
|
|
55
|
+
repository, then use `webfactory/ssh-agent` to load the key before checkout.
|
|
56
|
+
This avoids PATs entirely and follows least-privilege principles.
|
|
57
|
+
|
|
58
|
+
For organizations, a machine account (a GitHub account created for automation) with
|
|
59
|
+
`repo` read access to all submodule repos is often easier to manage than fine-grained
|
|
60
|
+
PATs.
|
|
61
|
+
fix_code:
|
|
62
|
+
- language: yaml
|
|
63
|
+
label: "PAT with repo scope passed via token input"
|
|
64
|
+
code: |
|
|
65
|
+
jobs:
|
|
66
|
+
build:
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@v4
|
|
70
|
+
with:
|
|
71
|
+
submodules: recursive
|
|
72
|
+
token: ${{ secrets.SUBMODULE_PAT }}
|
|
73
|
+
# SUBMODULE_PAT: classic PAT with repo scope, or fine-grained PAT
|
|
74
|
+
# with Contents: read on all private submodule repos
|
|
75
|
+
|
|
76
|
+
- language: yaml
|
|
77
|
+
label: "SSH deploy key approach using webfactory/ssh-agent"
|
|
78
|
+
code: |
|
|
79
|
+
jobs:
|
|
80
|
+
build:
|
|
81
|
+
runs-on: ubuntu-latest
|
|
82
|
+
steps:
|
|
83
|
+
- name: Configure SSH agent with submodule deploy key
|
|
84
|
+
uses: webfactory/ssh-agent@v0.9.0
|
|
85
|
+
with:
|
|
86
|
+
ssh-private-key: ${{ secrets.SUBMODULE_DEPLOY_KEY }}
|
|
87
|
+
# Add multiple keys for multiple private submodule repos:
|
|
88
|
+
# ssh-private-key: |
|
|
89
|
+
# ${{ secrets.SUBMODULE_REPO_A_KEY }}
|
|
90
|
+
# ${{ secrets.SUBMODULE_REPO_B_KEY }}
|
|
91
|
+
|
|
92
|
+
- uses: actions/checkout@v4
|
|
93
|
+
with:
|
|
94
|
+
submodules: recursive
|
|
95
|
+
# No token needed — SSH agent handles git authentication
|
|
96
|
+
prevention:
|
|
97
|
+
- "Prefer deploy keys over PATs for submodule access — deploy keys are repo-scoped and easier to rotate"
|
|
98
|
+
- "Use fine-grained PATs scoped to specific repositories rather than classic PATs with broad repo scope"
|
|
99
|
+
- "Document which submodule repos require special secrets so new contributors can configure their forks"
|
|
100
|
+
- "Consider converting private submodule dependencies to private packages in a registry to avoid cross-repo auth complexity"
|
|
101
|
+
- "Test submodule checkout in a fresh fork or on a runner without existing git credentials to catch auth issues early"
|
|
102
|
+
docs:
|
|
103
|
+
- url: "https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#permissions-for-the-github_token"
|
|
104
|
+
label: "GitHub Docs — GITHUB_TOKEN permissions and scope"
|
|
105
|
+
- url: "https://github.com/actions/checkout#usage"
|
|
106
|
+
label: "actions/checkout — token and submodules inputs"
|
|
107
|
+
- url: "https://docs.github.com/en/authentication/connecting-to-github-with-ssh/managing-deploy-keys"
|
|
108
|
+
label: "GitHub Docs — Managing deploy keys"
|
|
109
|
+
- url: "https://github.com/webfactory/ssh-agent"
|
|
110
|
+
label: "webfactory/ssh-agent — Load SSH keys for Actions"
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
id: runner-environment-112
|
|
2
|
+
title: "ubuntu-24.04 nftables replaces iptables — Docker bridge networking and kind/minikube cluster setup fails"
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- ubuntu-24.04
|
|
7
|
+
- docker
|
|
8
|
+
- networking
|
|
9
|
+
- iptables
|
|
10
|
+
- nftables
|
|
11
|
+
- kind
|
|
12
|
+
- minikube
|
|
13
|
+
- runner-image-update
|
|
14
|
+
patterns:
|
|
15
|
+
- regex: 'No chain/target/match by that name'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: 'iptables.*failed.*nat.*DOCKER'
|
|
18
|
+
flags: 'i'
|
|
19
|
+
- regex: 'Failed to set up iptables.*\(iptables-nft\)'
|
|
20
|
+
flags: 'i'
|
|
21
|
+
- regex: 'network.*setup.*failed.*iptables'
|
|
22
|
+
flags: 'i'
|
|
23
|
+
- regex: 'Error response from daemon.*iptables failed'
|
|
24
|
+
flags: 'i'
|
|
25
|
+
error_messages:
|
|
26
|
+
- "iptables: No chain/target/match by that name."
|
|
27
|
+
- "Error response from daemon: driver failed programming external connectivity on endpoint: iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 5432 -j DNAT --to-destination 172.17.0.2:5432 ! -i docker0: iptables: No chain/target/match by that name."
|
|
28
|
+
- "Failed to set up iptables rules: iptables-nft is not supported"
|
|
29
|
+
- "Error: failed to create cluster: failed to ensure docker network: failed to set up kind CNI"
|
|
30
|
+
root_cause: |
|
|
31
|
+
Ubuntu 24.04 ships with nftables as the primary packet-filtering framework. The `iptables`
|
|
32
|
+
command is now a thin wrapper around nftables (`iptables-nft`), replacing the legacy
|
|
33
|
+
`iptables-legacy` backend that was default on Ubuntu 20.04/22.04.
|
|
34
|
+
|
|
35
|
+
Docker's bridge networking writes iptables rules using legacy format assumptions. CNI plugins
|
|
36
|
+
used by Kubernetes tools (kind, minikube, k3s) also expect the legacy iptables backend to be
|
|
37
|
+
active. When these tools run on ubuntu-24.04, they encounter incompatible chain formats and
|
|
38
|
+
rule semantics that iptables-nft does not honour, causing network setup to fail with "No
|
|
39
|
+
chain/target/match by that name" errors.
|
|
40
|
+
|
|
41
|
+
The runner-images migration from ubuntu-22.04 to ubuntu-24.04 (and from ubuntu-latest pointing
|
|
42
|
+
to ubuntu-22.04 to ubuntu-24.04) silently exposes this issue for any workflow running
|
|
43
|
+
Docker-in-Docker, Kubernetes clusters, or service containers with custom networking.
|
|
44
|
+
fix: |
|
|
45
|
+
Switch the `iptables` alternative back to the legacy backend before starting Docker or
|
|
46
|
+
any CNI-based tooling. Add this step at the top of your job, before any Docker or cluster
|
|
47
|
+
setup steps:
|
|
48
|
+
|
|
49
|
+
- name: Switch to legacy iptables
|
|
50
|
+
run: |
|
|
51
|
+
sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
|
|
52
|
+
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
|
|
53
|
+
|
|
54
|
+
For kind clusters, the above fix is the most reliable approach.
|
|
55
|
+
|
|
56
|
+
If you cannot switch the iptables backend (e.g., you require nftables for other reasons),
|
|
57
|
+
use Docker with `--iptables=false` and manage forwarding rules manually, or use network
|
|
58
|
+
mode `host` where possible.
|
|
59
|
+
|
|
60
|
+
Long-term: upgrade to versions of kind (≥ v0.24), minikube (≥ v1.33), and Docker Engine
|
|
61
|
+
(≥ 27) that include nftables-native support.
|
|
62
|
+
fix_code:
|
|
63
|
+
- language: yaml
|
|
64
|
+
label: "Switch to iptables-legacy before Docker or cluster setup (ubuntu-24.04)"
|
|
65
|
+
code: |
|
|
66
|
+
jobs:
|
|
67
|
+
test:
|
|
68
|
+
runs-on: ubuntu-24.04
|
|
69
|
+
steps:
|
|
70
|
+
- name: Switch to legacy iptables
|
|
71
|
+
run: |
|
|
72
|
+
sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
|
|
73
|
+
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
|
|
74
|
+
|
|
75
|
+
- name: Start kind cluster
|
|
76
|
+
uses: helm/kind-action@v1
|
|
77
|
+
with:
|
|
78
|
+
cluster_name: ci
|
|
79
|
+
- language: yaml
|
|
80
|
+
label: "Pin runs-on to ubuntu-22.04 as a temporary workaround"
|
|
81
|
+
code: |
|
|
82
|
+
jobs:
|
|
83
|
+
test:
|
|
84
|
+
# Temporary: ubuntu-22.04 uses iptables-legacy by default
|
|
85
|
+
# TODO: migrate to ubuntu-24.04 after updating kind/Docker versions
|
|
86
|
+
runs-on: ubuntu-22.04
|
|
87
|
+
prevention:
|
|
88
|
+
- "Test workflows on ubuntu-24.04 explicitly before relying on ubuntu-latest switching to it"
|
|
89
|
+
- "Keep kind, minikube, and Docker Engine versions current — nftables-native support arrived in each"
|
|
90
|
+
- "Add an iptables-legacy switch step as a defensive measure in any job using Docker networking or CNI plugins"
|
|
91
|
+
- "Watch runner-images release notes (github.com/actions/runner-images) for ubuntu-latest label changes"
|
|
92
|
+
docs:
|
|
93
|
+
- url: "https://docs.docker.com/network/iptables/"
|
|
94
|
+
label: "Docker — iptables and nftables networking"
|
|
95
|
+
- url: "https://github.com/actions/runner-images/issues/10636"
|
|
96
|
+
label: "runner-images #10636 — ubuntu-24.04 iptables-nft Docker incompatibility"
|
|
97
|
+
- url: "https://kind.sigs.k8s.io/docs/user/known-issues/"
|
|
98
|
+
label: "kind — Known Issues including iptables compatibility"
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
id: runner-environment-113
|
|
2
|
+
title: "ubuntu-24.04 removed python3-distutils — ModuleNotFoundError: No module named 'distutils' on pip install"
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- ubuntu-24.04
|
|
7
|
+
- python
|
|
8
|
+
- distutils
|
|
9
|
+
- pip
|
|
10
|
+
- setup-py
|
|
11
|
+
- runner-image-update
|
|
12
|
+
- python-3-12
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: "ModuleNotFoundError: No module named 'distutils'"
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'No module named ''distutils\.core'''
|
|
17
|
+
flags: 'i'
|
|
18
|
+
- regex: 'error in setup command.*distutils'
|
|
19
|
+
flags: 'i'
|
|
20
|
+
- regex: 'distutils.*not found.*pip install'
|
|
21
|
+
flags: 'i'
|
|
22
|
+
error_messages:
|
|
23
|
+
- "ModuleNotFoundError: No module named 'distutils'"
|
|
24
|
+
- "ModuleNotFoundError: No module named 'distutils.core'"
|
|
25
|
+
- "error in setup command: Error parsing /path/to/setup.cfg: No module named 'distutils.core'"
|
|
26
|
+
- "note: This error originates from a subprocess, and is likely not a problem with pip."
|
|
27
|
+
- "error: legacy-install-failure"
|
|
28
|
+
root_cause: |
|
|
29
|
+
Ubuntu 24.04 ships Python 3.12 as the system Python. Python 3.12 fully removed the
|
|
30
|
+
`distutils` module from its standard library (it was deprecated in 3.10 and removed in 3.12
|
|
31
|
+
per PEP 632). Ubuntu Noble (24.04) also removed the `python3-distutils` apt backport package
|
|
32
|
+
that had been available on 20.04 and 22.04.
|
|
33
|
+
|
|
34
|
+
Many older Python packages still use `distutils` directly in their `setup.py` or `setup.cfg`
|
|
35
|
+
files. When `pip install` processes these packages, the build backend invokes `distutils` which
|
|
36
|
+
is no longer available. The error appears to be a build backend failure rather than a pip
|
|
37
|
+
failure, so the root cause is easy to miss.
|
|
38
|
+
|
|
39
|
+
This affects any workflow that:
|
|
40
|
+
- Uses the system Python (no `actions/setup-python` step)
|
|
41
|
+
- Installs packages with legacy `setup.py` that import `distutils`
|
|
42
|
+
- Creates virtualenvs from the system Python without pre-installing setuptools
|
|
43
|
+
|
|
44
|
+
Distinct from `setup-python-version-range-resolves-to-313-distutils-removed` which covers
|
|
45
|
+
setup-python action resolving to Python 3.12/3.13 and distutils in user packages. This entry
|
|
46
|
+
covers the apt-level removal affecting system Python on the ubuntu-24.04 runner image itself.
|
|
47
|
+
fix: |
|
|
48
|
+
Option 1 (recommended): Use actions/setup-python to manage the Python version explicitly.
|
|
49
|
+
setup-python bundles setuptools which provides a distutils compatibility shim.
|
|
50
|
+
|
|
51
|
+
Option 2: Install setuptools as the first pip action before installing other packages.
|
|
52
|
+
setuptools >= 58.0.0 ships a `distutils` compatibility shim that satisfies `import distutils`.
|
|
53
|
+
|
|
54
|
+
- name: Install setuptools (distutils shim)
|
|
55
|
+
run: pip install setuptools
|
|
56
|
+
|
|
57
|
+
Option 3: Install the apt package `python3-setuptools` which restores distutils compatibility
|
|
58
|
+
at the system level for Python 3.12.
|
|
59
|
+
|
|
60
|
+
Option 4 (long-term): Migrate the affected package to PEP 517/518 — replace setup.py with
|
|
61
|
+
pyproject.toml and a modern build backend (setuptools>=61, flit, hatch, etc.).
|
|
62
|
+
fix_code:
|
|
63
|
+
- language: yaml
|
|
64
|
+
label: "Use actions/setup-python so setuptools is available (recommended)"
|
|
65
|
+
code: |
|
|
66
|
+
jobs:
|
|
67
|
+
build:
|
|
68
|
+
runs-on: ubuntu-24.04
|
|
69
|
+
steps:
|
|
70
|
+
- uses: actions/checkout@v4
|
|
71
|
+
|
|
72
|
+
- uses: actions/setup-python@v5
|
|
73
|
+
with:
|
|
74
|
+
python-version: '3.12'
|
|
75
|
+
|
|
76
|
+
- name: Install dependencies
|
|
77
|
+
run: pip install -r requirements.txt
|
|
78
|
+
- language: yaml
|
|
79
|
+
label: "Pre-install setuptools to restore distutils shim (quick fix for system Python)"
|
|
80
|
+
code: |
|
|
81
|
+
jobs:
|
|
82
|
+
build:
|
|
83
|
+
runs-on: ubuntu-24.04
|
|
84
|
+
steps:
|
|
85
|
+
- uses: actions/checkout@v4
|
|
86
|
+
|
|
87
|
+
- name: Install setuptools (distutils compatibility shim for Python 3.12)
|
|
88
|
+
run: pip install --upgrade setuptools
|
|
89
|
+
|
|
90
|
+
- name: Install dependencies
|
|
91
|
+
run: pip install -r requirements.txt
|
|
92
|
+
- language: yaml
|
|
93
|
+
label: "Install python3-setuptools via apt (system-level fix)"
|
|
94
|
+
code: |
|
|
95
|
+
jobs:
|
|
96
|
+
build:
|
|
97
|
+
runs-on: ubuntu-24.04
|
|
98
|
+
steps:
|
|
99
|
+
- name: Install python3-setuptools
|
|
100
|
+
run: sudo apt-get install -y python3-setuptools
|
|
101
|
+
|
|
102
|
+
- name: Install dependencies
|
|
103
|
+
run: pip install -r requirements.txt
|
|
104
|
+
prevention:
|
|
105
|
+
- "Always use actions/setup-python rather than relying on system Python — it ships with setuptools"
|
|
106
|
+
- "Pin a Python version explicitly; avoid implicit system Python which changes per runner image"
|
|
107
|
+
- "Run pip install --dry-run in CI to detect distutils/setuptools issues before they block builds"
|
|
108
|
+
- "Audit third-party dependencies for setup.py usage with: pip install pipdeptree; pipdeptree | grep setup.py"
|
|
109
|
+
- "Migrate legacy setup.py packages to pyproject.toml for long-term Python 3.12+ compatibility"
|
|
110
|
+
docs:
|
|
111
|
+
- url: "https://docs.python.org/3/whatsnew/3.12.html#removed"
|
|
112
|
+
label: "Python 3.12 — Removed modules (distutils)"
|
|
113
|
+
- url: "https://peps.python.org/pep-0632/"
|
|
114
|
+
label: "PEP 632 — Deprecate distutils"
|
|
115
|
+
- url: "https://github.com/actions/runner-images/issues/9674"
|
|
116
|
+
label: "runner-images #9674 — python3-distutils unavailable on ubuntu-24.04"
|
|
117
|
+
- url: "https://github.com/actions/setup-python"
|
|
118
|
+
label: "actions/setup-python — bundles setuptools"
|