@htekdev/actions-debugger 1.0.124 → 1.0.126

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/errors/caching-artifacts/caching-artifacts-073.yml +100 -0
  2. package/errors/caching-artifacts/caching-artifacts-074.yml +117 -0
  3. package/errors/concurrency-timing/concurrency-timing-059.yml +146 -0
  4. package/errors/concurrency-timing/concurrency-timing-060.yml +144 -0
  5. package/errors/known-unsolved/known-unsolved-071.yml +122 -0
  6. package/errors/known-unsolved/known-unsolved-072.yml +143 -0
  7. package/errors/known-unsolved/known-unsolved-073.yml +172 -0
  8. package/errors/permissions-auth/permissions-auth-071.yml +144 -0
  9. package/errors/permissions-auth/permissions-auth-072.yml +112 -0
  10. package/errors/permissions-auth/permissions-auth-073.yml +127 -0
  11. package/errors/permissions-auth/permissions-auth-074.yml +106 -0
  12. package/errors/permissions-auth/permissions-auth-075.yml +137 -0
  13. package/errors/runner-environment/runner-environment-227.yml +106 -0
  14. package/errors/runner-environment/runner-environment-228.yml +117 -0
  15. package/errors/runner-environment/runner-environment-229.yml +119 -0
  16. package/errors/runner-environment/runner-environment-230.yml +129 -0
  17. package/errors/runner-environment/runner-environment-231.yml +90 -0
  18. package/errors/runner-environment/runner-environment-232.yml +131 -0
  19. package/errors/runner-environment/runner-environment-233.yml +90 -0
  20. package/errors/runner-environment/runner-environment-234.yml +114 -0
  21. package/errors/runner-environment/runner-environment-235.yml +151 -0
  22. package/errors/silent-failures/silent-failures-112.yml +97 -0
  23. package/errors/silent-failures/silent-failures-113.yml +110 -0
  24. package/errors/silent-failures/silent-failures-114.yml +116 -0
  25. package/errors/silent-failures/silent-failures-115.yml +130 -0
  26. package/errors/silent-failures/silent-failures-116.yml +117 -0
  27. package/errors/silent-failures/silent-failures-117.yml +137 -0
  28. package/errors/silent-failures/silent-failures-118.yml +156 -0
  29. package/errors/triggers/triggers-072.yml +150 -0
  30. package/errors/yaml-syntax/yaml-syntax-075.yml +128 -0
  31. package/errors/yaml-syntax/yaml-syntax-076.yml +107 -0
  32. package/package.json +1 -1
@@ -0,0 +1,143 @@
1
+ id: known-unsolved-072
2
+ title: 'No parallel steps within a single job — all steps execute sequentially'
3
+ category: known-unsolved
4
+ severity: limitation
5
+ tags:
6
+ - parallel-steps
7
+ - sequential
8
+ - performance
9
+ - job-structure
10
+ - limitation
11
+ - roadmap
12
+ patterns:
13
+ - regex: 'parallel.*steps.*not.*support|steps.*run.*sequentially'
14
+ flags: 'i'
15
+ error_messages:
16
+ - 'steps run sequentially — no native parallel step execution within a single job'
17
+ root_cause: |
18
+ In GitHub Actions, all steps within a single job execute sequentially in the order they
19
+ are defined. There is no native syntax to declare that two or more steps within the same
20
+ job should run concurrently.
21
+
22
+ This means:
23
+ - A job that runs `npm install`, `eslint`, and `jest` must run them one after another,
24
+ even if `eslint` and `jest` are completely independent and could run simultaneously.
25
+ - A job that runs two independent API calls, file downloads, or build targets must wait
26
+ for each to complete before starting the next.
27
+ - The only way to achieve true parallelism in GitHub Actions is to split work across
28
+ multiple jobs with `needs:` dependencies — but this requires each job to set up its
29
+ own runner, check out the repository, restore caches, and install dependencies,
30
+ adding significant overhead for short tasks.
31
+
32
+ This is a long-standing community request. GitHub added it to the public roadmap as
33
+ "Parallel Steps in GitHub Actions" (github/roadmap#1191, GA milestone, 2025).
34
+
35
+ Common workarounds add latency (multiple jobs) or complexity (background processes).
36
+ fix: |
37
+ There is no built-in fix. Workarounds:
38
+
39
+ 1. Split parallel work into separate jobs using `needs:` and a matrix strategy.
40
+ Each job adds runner setup overhead (~15-30s), so this is most effective for
41
+ tasks that take minutes, not seconds.
42
+
43
+ 2. Run steps as background shell processes and wait for them with `wait` (bash only).
44
+ This works for independent shell commands that don't need to write to GITHUB_OUTPUT,
45
+ GITHUB_ENV, or produce step outputs — those mechanisms are not safe for concurrent use.
46
+
47
+ 3. Use `make -j N` or `./gradlew --parallel` or similar build-tool parallelism within
48
+ a single shell step. This parallelizes work inside one run: step without needing
49
+ multiple GitHub Actions steps.
50
+
51
+ 4. Run a Docker Compose or docker run --detach to start background services, then
52
+ use a final step to check results.
53
+ fix_code:
54
+ - language: yaml
55
+ label: 'Run independent checks in parallel via separate jobs (preferred for long tasks)'
56
+ code: |
57
+ jobs:
58
+ lint:
59
+ runs-on: ubuntu-latest
60
+ steps:
61
+ - uses: actions/checkout@v4
62
+ - uses: actions/setup-node@v4
63
+ with:
64
+ node-version: 22
65
+ cache: npm
66
+ - run: npm ci
67
+ - run: npm run lint
68
+
69
+ test:
70
+ runs-on: ubuntu-latest
71
+ steps:
72
+ - uses: actions/checkout@v4
73
+ - uses: actions/setup-node@v4
74
+ with:
75
+ node-version: 22
76
+ cache: npm
77
+ - run: npm ci
78
+ - run: npm test
79
+
80
+ type-check:
81
+ runs-on: ubuntu-latest
82
+ steps:
83
+ - uses: actions/checkout@v4
84
+ - uses: actions/setup-node@v4
85
+ with:
86
+ node-version: 22
87
+ cache: npm
88
+ - run: npm ci
89
+ - run: npm run typecheck
90
+
91
+ # Final gate job waits for all parallel checks
92
+ ci-complete:
93
+ needs: [lint, test, type-check]
94
+ runs-on: ubuntu-latest
95
+ steps:
96
+ - run: echo "All checks passed"
97
+
98
+ - language: bash
99
+ label: 'Background shell processes for independent shell commands (same job)'
100
+ code: |
101
+ # In a single run: step, launch parallel shell processes and wait for all
102
+ # WARNING: This pattern does not work with GITHUB_OUTPUT/GITHUB_ENV/GITHUB_STEP_SUMMARY
103
+ # from the background processes — race conditions corrupt the append-mode files.
104
+ # Use only for commands that write to their own output files.
105
+
106
+ ./fetch-data-source-1.sh > /tmp/source1.json &
107
+ PID1=$!
108
+
109
+ ./fetch-data-source-2.sh > /tmp/source2.json &
110
+ PID2=$!
111
+
112
+ wait $PID1 || { echo "Source 1 fetch failed"; exit 1; }
113
+ wait $PID2 || { echo "Source 2 fetch failed"; exit 1; }
114
+
115
+ echo "Both sources fetched in parallel"
116
+ ./merge-sources.py /tmp/source1.json /tmp/source2.json
117
+
118
+ - language: yaml
119
+ label: 'Use build tool parallelism inside a single step'
120
+ code: |
121
+ jobs:
122
+ build:
123
+ runs-on: ubuntu-latest
124
+ steps:
125
+ - uses: actions/checkout@v4
126
+ - uses: actions/setup-java@v4
127
+ with:
128
+ java-version: 21
129
+ distribution: temurin
130
+ # Gradle parallel project execution — all subprojects build concurrently
131
+ - run: ./gradlew build --parallel --max-workers 4
132
+ prevention:
133
+ - 'Design CI pipelines with parallel jobs from the start — split lint, test, and build into independent jobs to maximize parallelism today.'
134
+ - 'Use a shared cache with `actions/cache` to minimize the overhead of repeated `npm ci` / `pip install` across parallel jobs.'
135
+ - 'Track github/roadmap#1191 for the native parallel steps feature — once released, sequential-step bottlenecks can be eliminated without the multi-job overhead.'
136
+ - 'For build-tool tasks, always prefer build-native parallelism (`make -j`, `--parallel`, `cargo build --jobs`) over workflow-level workarounds.'
137
+ docs:
138
+ - url: 'https://github.com/github/roadmap/issues/1191'
139
+ label: 'github/roadmap#1191 — Parallel Steps in GitHub Actions (GA milestone, open 2025)'
140
+ - url: 'https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idsteps'
141
+ label: 'GitHub Docs — jobs.<job_id>.steps (sequential execution model)'
142
+ - url: 'https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs'
143
+ label: 'GitHub Docs — Using a matrix for parallel jobs as a workaround'
@@ -0,0 +1,172 @@
1
+ id: known-unsolved-073
2
+ title: '`timeout-minutes:` does not accept expressions — must be a literal integer; variables, inputs, and secrets are unsupported'
3
+ category: known-unsolved
4
+ severity: limitation
5
+ tags:
6
+ - timeout-minutes
7
+ - expressions
8
+ - limitation
9
+ - no-dynamic-value
10
+ - job-timeout
11
+ - step-timeout
12
+ - vars-context
13
+ patterns:
14
+ - regex: 'timeout-minutes:\s*\$\{\{'
15
+ flags: 'i'
16
+ - regex: 'timeout-minutes.*vars\.|timeout-minutes.*inputs\.|timeout-minutes.*env\.'
17
+ flags: 'i'
18
+ - regex: 'Unexpected value.*timeout-minutes|timeout-minutes.*invalid'
19
+ flags: 'i'
20
+ error_messages:
21
+ - "The workflow is not valid. .github/workflows/ci.yml (Line: N, Col: M): Unexpected value 'true'"
22
+ - "timeout-minutes: unexpected value"
23
+ - "Expected Integer, String"
24
+ root_cause: |
25
+ The `timeout-minutes:` field at both the **job level** and the **step level** only
26
+ accepts a **literal integer** (e.g., `30`, `120`). GitHub Actions does not evaluate
27
+ expressions (`${{ }}`) in this field.
28
+
29
+ Attempting to use any of the following will either produce a YAML validation error
30
+ or silently fall back to the default timeout (6 hours for jobs, unlimited for steps):
31
+
32
+ - `timeout-minutes: ${{ vars.JOB_TIMEOUT }}` — variables context
33
+ - `timeout-minutes: ${{ inputs.timeout }}` — inputs context
34
+ - `timeout-minutes: ${{ env.TIMEOUT_MINUTES }}` — env context
35
+ - `timeout-minutes: ${{ 30 * 2 }}` — arithmetic expression
36
+ - `timeout-minutes: ${{ matrix.timeout }}` — matrix value
37
+
38
+ This is a long-standing feature request (actions/runner#1242, opened 2021, 500+
39
+ reactions) with no official resolution as of June 2026. GitHub's position is that
40
+ expression support in `timeout-minutes:` is not currently planned.
41
+
42
+ actionlint (>=1.6.x) correctly flags `timeout-minutes: ${{ ... }}` as a type error:
43
+ "type of expression at 'timeout-minutes' must be number but found string type."
44
+ However, some older actionlint versions or CI linting setups may not catch this,
45
+ allowing the invalid value to reach production where it silently uses the default.
46
+
47
+ Common motivation for wanting dynamic timeouts:
48
+ - Different environments (staging vs production) need different timeouts.
49
+ - A reusable workflow caller wants to pass a timeout as an input.
50
+ - Matrix jobs with different test suites need proportional timeouts.
51
+ - Organizational policies want to set timeouts via repository variables.
52
+ fix: |
53
+ There is no native fix — expressions in `timeout-minutes:` are not supported.
54
+
55
+ **Workaround 1 — Hardcode multiple job variants with `if:` conditions:**
56
+ Create separate job definitions for each timeout scenario, each with a hardcoded
57
+ `timeout-minutes:` and an `if:` condition that selects the appropriate one based
58
+ on the context. This is verbose but fully supported.
59
+
60
+ **Workaround 2 — Use a wrapper script with a timeout command:**
61
+ Instead of relying on job-level timeout, implement a timeout inside the step's run
62
+ script using the OS `timeout` command (Linux/macOS) or PowerShell's `Wait-Process`:
63
+ ```yaml
64
+ steps:
65
+ - name: Build with dynamic timeout
66
+ env:
67
+ BUILD_TIMEOUT: ${{ vars.BUILD_TIMEOUT_SECONDS || '1800' }}
68
+ run: timeout "$BUILD_TIMEOUT" ./build.sh
69
+ ```
70
+ This gives dynamic timeout behavior but does NOT release the runner immediately —
71
+ the job continues running (idle) after the script times out until the job-level
72
+ `timeout-minutes:` (hardcoded) fires.
73
+
74
+ **Workaround 3 — Hardcode a generous upper bound:**
75
+ Set `timeout-minutes:` to the maximum acceptable value for any scenario, and rely
76
+ on internal script logic to exit early when needed. Ensures the runner is eventually
77
+ released even in worst-case scenarios.
78
+
79
+ **Workaround 4 — For reusable workflows, hardcode per caller:**
80
+ If a reusable workflow needs caller-specified timeouts, duplicate the job definition
81
+ per timeout tier or create multiple reusable workflows with different timeouts.
82
+ fix_code:
83
+ - language: yaml
84
+ label: 'Does NOT work — expression in timeout-minutes is not supported'
85
+ code: |
86
+ jobs:
87
+ build:
88
+ runs-on: ubuntu-latest
89
+ timeout-minutes: ${{ vars.JOB_TIMEOUT_MINUTES }} # ❌ Expression not supported
90
+ steps:
91
+ - run: ./build.sh
92
+
93
+ # Also does NOT work:
94
+ jobs:
95
+ test:
96
+ runs-on: ubuntu-latest
97
+ timeout-minutes: ${{ inputs.timeout || 30 }} # ❌ inputs not supported here
98
+ steps:
99
+ - run: ./test.sh
100
+
101
+ - language: yaml
102
+ label: 'Workaround — use OS timeout command inside step for dynamic behavior'
103
+ code: |
104
+ jobs:
105
+ build:
106
+ runs-on: ubuntu-latest
107
+ timeout-minutes: 60 # ✅ Hardcoded upper bound (releases runner if script hangs)
108
+ steps:
109
+ - uses: actions/checkout@v4
110
+ - name: Build with dynamic timeout from variable
111
+ env:
112
+ # Variable in seconds: default 1800 (30 min), override via repo var
113
+ BUILD_TIMEOUT: ${{ vars.BUILD_TIMEOUT_SECONDS || '1800' }}
114
+ run: timeout "$BUILD_TIMEOUT" ./build.sh
115
+ # The job-level 60-minute timeout catches runaway cases
116
+
117
+ - language: yaml
118
+ label: 'Workaround — conditional job variants for different timeout requirements'
119
+ code: |
120
+ jobs:
121
+ build-short:
122
+ if: ${{ github.event_name == 'pull_request' }}
123
+ runs-on: ubuntu-latest
124
+ timeout-minutes: 15 # ✅ Short timeout for PR checks
125
+ steps:
126
+ - uses: actions/checkout@v4
127
+ - run: ./build.sh --quick
128
+
129
+ build-full:
130
+ if: ${{ github.ref == 'refs/heads/main' }}
131
+ runs-on: ubuntu-latest
132
+ timeout-minutes: 60 # ✅ Full timeout for main branch builds
133
+ steps:
134
+ - uses: actions/checkout@v4
135
+ - run: ./build.sh --full
136
+
137
+ - language: yaml
138
+ label: 'Reusable workflow workaround — hardcode tiers, expose as separate workflows'
139
+ code: |
140
+ # .github/workflows/ci-fast.yml — for PRs
141
+ on:
142
+ workflow_call:
143
+ jobs:
144
+ ci:
145
+ runs-on: ubuntu-latest
146
+ timeout-minutes: 15 # ✅ Fast tier
147
+ steps:
148
+ - run: ./ci.sh
149
+
150
+ # .github/workflows/ci-full.yml — for main branch
151
+ on:
152
+ workflow_call:
153
+ jobs:
154
+ ci:
155
+ runs-on: ubuntu-latest
156
+ timeout-minutes: 60 # ✅ Full tier
157
+ steps:
158
+ - run: ./ci.sh
159
+
160
+ prevention:
161
+ - 'Accept that `timeout-minutes:` requires a literal integer — design your timeouts with hardcoded values from the start.'
162
+ - 'Use actionlint in CI to catch `timeout-minutes: ${{ ... }}` during PR review before it reaches production.'
163
+ - 'Set `timeout-minutes:` to a safe upper bound to ensure runners are eventually released even when scripts hang.'
164
+ - 'Use step-level `run: timeout N command` for dynamic per-step timeouts without changing job-level `timeout-minutes:`.'
165
+ - 'Upvote actions/runner#1242 — expression support in timeout-minutes is a high-demand feature request.'
166
+ docs:
167
+ - url: 'https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes'
168
+ label: 'GitHub Docs: Workflow syntax — jobs.<id>.timeout-minutes (literal integer only)'
169
+ - url: 'https://github.com/actions/runner/issues/1242'
170
+ label: 'actions/runner#1242: Support expressions in timeout-minutes (500+ reactions, open since 2021)'
171
+ - url: 'https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepstimeout-minutes'
172
+ label: 'GitHub Docs: Workflow syntax — jobs.<id>.steps[*].timeout-minutes'
@@ -0,0 +1,144 @@
1
+ id: permissions-auth-071
2
+ title: 'OIDC token not available in pull_request events from forks — id-token: write cannot be granted'
3
+ category: permissions-auth
4
+ severity: error
5
+ tags:
6
+ - oidc
7
+ - fork
8
+ - pull-request
9
+ - id-token
10
+ - attestation
11
+ - aws
12
+ - azure
13
+ - workload-identity
14
+ patterns:
15
+ - regex: 'Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable'
16
+ flags: 'i'
17
+ - regex: 'Could not fetch an OIDC token.*id-token.*write'
18
+ flags: 'i'
19
+ - regex: 'Error: Action failed with error: Error: Error message: Unable to get ACTIONS_ID_TOKEN_REQUEST_URL'
20
+ flags: 'i'
21
+ error_messages:
22
+ - 'Error: Error message: Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable'
23
+ - 'Could not fetch an OIDC token. Did you remember to add `id-token: write` to your workflow permissions?'
24
+ - 'Error: Action failed with error: Error: Error message: Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable'
25
+ root_cause: |
26
+ GitHub Actions workflows triggered by `pull_request` events from forked repositories cannot
27
+ mint OIDC tokens, even when `id-token: write` is explicitly set in the workflow `permissions:` block.
28
+
29
+ The restriction is enforced by GitHub's security model for fork pull requests:
30
+ - Fork PRs run with the permissions of the fork, not the base repository.
31
+ - GitHub documentation states: "You can use the permissions key to add and remove read
32
+ permissions for forked repositories, but typically you can't grant write access."
33
+ - The `id-token: write` scope is a WRITE permission. The ACTIONS_ID_TOKEN_REQUEST_URL
34
+ environment variable is only set when the runtime has write-level token access.
35
+ - When the variable is absent, any action or toolkit call to `core.getIDToken()` fails with
36
+ "Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable".
37
+
38
+ This commonly impacts:
39
+ - Cloud provider OIDC authentication (AWS configure-aws-credentials, Azure login, GCP auth)
40
+ - actions/attest-build-provenance and actions/attest for build attestation on PRs
41
+ - Any action that relies on `@actions/core` `getIDToken()` for OIDC federation
42
+
43
+ The restriction exists to prevent malicious fork contributors from using OIDC tokens to
44
+ authenticate against production cloud accounts or push malicious artifacts.
45
+ fix: |
46
+ Option 1 — Use `pull_request_target` instead of `pull_request` (CAUTION required).
47
+ `pull_request_target` runs in the context of the base repository and CAN mint OIDC tokens.
48
+ However, it executes in the base repo's context with full access to base repo secrets —
49
+ this is a significant security risk if the workflow checks out or executes fork code without
50
+ proper isolation. Read all security guides before using this trigger.
51
+
52
+ Option 2 — Split the workflow into two parts.
53
+ Use `pull_request` for the build/test phase (no OIDC). Use a separate workflow triggered
54
+ by `workflow_run` or manual approval to perform OIDC-protected operations (attestation, deploy)
55
+ after verifying the PR code is safe.
56
+
57
+ Option 3 — Use a GitHub App token with explicit repository permissions for operations
58
+ that do not strictly require OIDC (e.g., package publishing). This avoids the OIDC
59
+ restriction entirely.
60
+
61
+ Option 4 — Only run OIDC-dependent steps on `push` events to protected branches (post-merge),
62
+ not on `pull_request` events from forks. Guard OIDC steps with:
63
+ if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false
64
+ fix_code:
65
+ - language: yaml
66
+ label: 'Guard OIDC steps — skip for fork PRs, run only for same-repo PRs or push'
67
+ code: |
68
+ jobs:
69
+ build-and-attest:
70
+ runs-on: ubuntu-latest
71
+ permissions:
72
+ id-token: write
73
+ contents: read
74
+ attestations: write
75
+ steps:
76
+ - uses: actions/checkout@v4
77
+
78
+ - name: Build artifact
79
+ run: ./build.sh
80
+
81
+ # OIDC-dependent steps: skip if fork PR (id-token write not available)
82
+ - name: Attest build provenance
83
+ if: >
84
+ github.event_name != 'pull_request' ||
85
+ github.event.pull_request.head.repo.full_name == github.repository
86
+ uses: actions/attest-build-provenance@v2
87
+ with:
88
+ subject-path: './dist/app'
89
+
90
+ - language: yaml
91
+ label: 'Split workflow: use workflow_run to run OIDC steps after fork PR merges'
92
+ code: |
93
+ # Workflow 1: runs on pull_request — builds and uploads artifact (no OIDC)
94
+ on:
95
+ pull_request:
96
+ jobs:
97
+ build:
98
+ runs-on: ubuntu-latest
99
+ steps:
100
+ - uses: actions/checkout@v4
101
+ - run: ./build.sh
102
+ - uses: actions/upload-artifact@v4
103
+ with:
104
+ name: build-output
105
+ path: ./dist/
106
+
107
+ ---
108
+
109
+ # Workflow 2: runs after workflow 1 completes — performs OIDC operations
110
+ on:
111
+ workflow_run:
112
+ workflows: ['Build']
113
+ types: [completed]
114
+ jobs:
115
+ attest:
116
+ # Only runs on base-repo push events completing after a merge
117
+ if: github.event.workflow_run.conclusion == 'success'
118
+ runs-on: ubuntu-latest
119
+ permissions:
120
+ id-token: write
121
+ attestations: write
122
+ steps:
123
+ - uses: actions/download-artifact@v4
124
+ with:
125
+ name: build-output
126
+ run-id: ${{ github.event.workflow_run.id }}
127
+ github-token: ${{ secrets.GITHUB_TOKEN }}
128
+ - uses: actions/attest-build-provenance@v2
129
+ with:
130
+ subject-path: './dist/app'
131
+ prevention:
132
+ - 'Never assume `id-token: write` is sufficient — fork PRs override write permissions to read-only regardless of the workflow `permissions:` block.'
133
+ - 'Add an explicit `if:` guard on every OIDC-dependent step to skip it for fork PRs: `if: github.event.pull_request.head.repo.fork == false`.'
134
+ - 'Use `pull_request_target` only after thoroughly reading the security hardening guide — it runs in base repo context and is vulnerable to pwn requests if fork code is checked out.'
135
+ - 'For attestation workflows, run attestation as a post-merge step on `push` to the default branch, not on PRs from forks.'
136
+ docs:
137
+ - url: 'https://github.com/actions/attest-build-provenance/issues/99'
138
+ label: 'actions/attest-build-provenance#99 — OIDC unavailable in fork PR workflows (open)'
139
+ - url: 'https://github.com/aws-actions/configure-aws-credentials/issues/373'
140
+ label: 'aws-actions/configure-aws-credentials#373 — OIDC fails for pull request from fork'
141
+ - url: 'https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#permissions-for-the-github_token'
142
+ label: 'GitHub Docs — GITHUB_TOKEN permissions for forked repos'
143
+ - url: 'https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#using-pull_request_target-safely'
144
+ label: 'GitHub Docs — Security hardening for pull_request_target'
@@ -0,0 +1,112 @@
1
+ id: permissions-auth-072
2
+ title: 'actions/labeler fails with "You do not have permission to create labels" — missing issues: write'
3
+ category: permissions-auth
4
+ severity: error
5
+ tags:
6
+ - actions/labeler
7
+ - issues
8
+ - labels
9
+ - permissions
10
+ - issues-write
11
+ - GITHUB_TOKEN
12
+ - HttpError
13
+ patterns:
14
+ - regex: 'You do not have permission to create labels on this repository'
15
+ flags: 'i'
16
+ - regex: 'HttpError.+do not have permission to create labels'
17
+ flags: 'i'
18
+ - regex: '"resource":"Repository","field":"label","code":"unauthorized"'
19
+ flags: 'i'
20
+ error_messages:
21
+ - 'HttpError: You do not have permission to create labels on this repository.: {"resource":"Repository","field":"label","code":"unauthorized"}'
22
+ - 'Error: You do not have permission to create labels on this repository.'
23
+ root_cause: |
24
+ `actions/labeler` requires the `issues: write` permission on the
25
+ `GITHUB_TOKEN` whenever it needs to **create** a label that does not yet
26
+ exist in the repository. The labeler's `create-labels: true` setting (or
27
+ its equivalent in older versions that auto-create missing labels) triggers a
28
+ `POST /repos/{owner}/{repo}/labels` API call.
29
+
30
+ In 2023+, GitHub tightened default token permissions. Repositories and
31
+ organizations that enable "Read repository contents and packages permissions"
32
+ as the default GITHUB_TOKEN permission, or workflows that explicitly
33
+ enumerate `permissions:` without including `issues: write`, will cause the
34
+ label-creation API call to return HTTP 403:
35
+
36
+ `HttpError: You do not have permission to create labels on this repository.`
37
+
38
+ Note: If all labels already exist in the repository, the action only calls
39
+ `GET /repos/{owner}/{repo}/labels` (read) and `POST .../issues/{number}/labels`
40
+ (adding a label to an issue/PR — also requires issues:write). In practice,
41
+ any labeling operation that modifies issues or creates labels needs this
42
+ permission. The error is especially confusing because it surfaces as an
43
+ `HttpError` that looks like a GitHub API error rather than a clear
44
+ "permission denied" message.
45
+ fix: |
46
+ Add `issues: write` to the workflow or job permissions block:
47
+
48
+ ```yaml
49
+ permissions:
50
+ issues: write
51
+ pull-requests: write # Also needed if labeling pull requests
52
+ contents: read
53
+ ```
54
+
55
+ If the repository uses the default broad permissions and the error occurs on
56
+ a fork PR (where fork PRs receive read-only tokens regardless of the
57
+ workflow's permissions block), add a guard:
58
+
59
+ ```yaml
60
+ if: github.event.pull_request.head.repo.full_name == github.repository
61
+ ```
62
+
63
+ to skip label creation on fork PRs where the token cannot be elevated.
64
+ fix_code:
65
+ - language: yaml
66
+ label: 'Add issues: write permission to the labeler job'
67
+ code: |
68
+ name: Label PRs
69
+
70
+ on:
71
+ pull_request_target:
72
+ types: [opened, synchronize, reopened]
73
+
74
+ jobs:
75
+ label:
76
+ runs-on: ubuntu-latest
77
+ permissions:
78
+ issues: write # Required to create new labels
79
+ pull-requests: write # Required to add labels to pull requests
80
+ contents: read
81
+ steps:
82
+ - uses: actions/labeler@v5
83
+ with:
84
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
85
+ - language: yaml
86
+ label: 'Skip labeler on fork PRs where token is always read-only'
87
+ code: |
88
+ jobs:
89
+ label:
90
+ runs-on: ubuntu-latest
91
+ # Skip on forks — their GITHUB_TOKEN is read-only regardless of permissions block
92
+ if: github.event.pull_request.head.repo.full_name == github.repository
93
+ permissions:
94
+ issues: write
95
+ pull-requests: write
96
+ contents: read
97
+ steps:
98
+ - uses: actions/labeler@v5
99
+ with:
100
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
101
+ prevention:
102
+ - 'Always include `issues: write` and `pull-requests: write` when using actions/labeler, even if the labeler config only applies existing labels — it still needs write to apply labels to PRs/issues.'
103
+ - 'Pre-create all labels defined in `.github/labeler.yml` in the repository settings so the action never needs to create them, reducing the permission surface needed (though issues:write is still needed for applying labels to issues/PRs).'
104
+ - 'When using `pull_request` trigger (not `pull_request_target`), fork PRs receive a read-only GITHUB_TOKEN by design; switch to `pull_request_target` or handle fork PRs with a separate read-only path.'
105
+ - 'Use the permissions checker in your CI review process: verify labeler workflows include explicit `permissions:` blocks before merging.'
106
+ docs:
107
+ - url: 'https://github.com/actions/labeler/issues/870'
108
+ label: 'actions/labeler#870 — HttpError: You do not have permission to create labels on this repository'
109
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token'
110
+ label: 'GitHub Docs — Controlling permissions for GITHUB_TOKEN'
111
+ - url: 'https://github.com/actions/labeler#token'
112
+ label: 'actions/labeler — Token and permissions requirements'