@htekdev/actions-debugger 1.0.13 → 1.0.15

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 (54) hide show
  1. package/dist/db/search.js +3 -1
  2. package/dist/db/search.js.map +1 -1
  3. package/dist/tools/suggest-fix.d.ts.map +1 -1
  4. package/dist/tools/suggest-fix.js +5 -1
  5. package/dist/tools/suggest-fix.js.map +1 -1
  6. package/errors/caching-artifacts/cache-key-too-long.yml +93 -0
  7. package/errors/caching-artifacts/cache-path-not-exist-skipped.yml +152 -0
  8. package/errors/caching-artifacts/docker-buildx-gha-cache-capacity.yml +107 -0
  9. package/errors/caching-artifacts/setup-ruby-bundler-ephemeral-workdir-cache-miss.yml +147 -0
  10. package/errors/caching-artifacts/upload-artifact-v3-retirement-blocked.yml +123 -0
  11. package/errors/concurrency-timing/always-cleanup-5min-forced-kill.yml +140 -0
  12. package/errors/concurrency-timing/concurrency-group-env-context-undefined.yml +99 -0
  13. package/errors/concurrency-timing/required-check-pending-path-filter-skip.yml +160 -0
  14. package/errors/concurrency-timing/wait-timer-cancel-in-progress-starvation.yml +125 -0
  15. package/errors/known-unsolved/composite-action-step-timeout-minutes-ignored.yml +146 -0
  16. package/errors/known-unsolved/reusable-workflow-no-composite-action-call.yml +116 -0
  17. package/errors/known-unsolved/schedule-trigger-default-branch-only.yml +113 -0
  18. package/errors/known-unsolved/secrets-not-allowed-in-if-conditions.yml +149 -0
  19. package/errors/permissions-auth/dependabot-pr-secrets-unavailable.yml +133 -0
  20. package/errors/permissions-auth/fine-grained-pat-deployment-write-required.yml +146 -0
  21. package/errors/permissions-auth/github-app-installation-token-new-format.yml +124 -0
  22. package/errors/permissions-auth/github-packages-read-requires-packages-permission.yml +128 -0
  23. package/errors/permissions-auth/oidc-id-token-write-permission-missing.yml +169 -0
  24. package/errors/permissions-auth/permissions-empty-block-removes-contents-read.yml +97 -0
  25. package/errors/permissions-auth/reusable-workflow-permissions-not-inherited.yml +114 -0
  26. package/errors/runner-environment/az-powershell-14-to-15-breaking.yml +108 -0
  27. package/errors/runner-environment/checkout-windows-ebusy-lock.yml +124 -0
  28. package/errors/runner-environment/deprecated-action-version-auto-rejected.yml +89 -0
  29. package/errors/runner-environment/github-hosted-runner-disk-space-full.yml +85 -0
  30. package/errors/runner-environment/github-path-same-step-not-found.yml +114 -0
  31. package/errors/runner-environment/github-script-v6-octokit-rest-actions-not-function.yml +87 -0
  32. package/errors/runner-environment/macos-15-mono-nuget-removed.yml +151 -0
  33. package/errors/runner-environment/macos-15-xcode-simulator-sdk-policy.yml +141 -0
  34. package/errors/runner-environment/runner-oom-exit-code-137.yml +117 -0
  35. package/errors/runner-environment/setup-go-go123-telemetry-cache-failure.yml +92 -0
  36. package/errors/runner-environment/setup-java-distribution-required.yml +108 -0
  37. package/errors/runner-environment/ubuntu-2204-precached-docker-removed.yml +110 -0
  38. package/errors/runner-environment/windows-latest-d-drive-removed.yml +104 -0
  39. package/errors/runner-environment/windows-msvc-ltcg-mixed-image-versions.yml +112 -0
  40. package/errors/runner-environment/windows-vs2026-cuda-host-compiler-unsupported.yml +145 -0
  41. package/errors/silent-failures/app-store-ios26-sdk-required.yml +113 -0
  42. package/errors/silent-failures/event-commits-empty-on-workflow-dispatch.yml +110 -0
  43. package/errors/silent-failures/fetch-tags-depth-one-silent-no-op.yml +77 -0
  44. package/errors/silent-failures/github-env-multiline-value-truncated.yml +127 -0
  45. package/errors/silent-failures/github-sha-pr-merge-commit-not-head.yml +150 -0
  46. package/errors/silent-failures/job-output-masked-as-secret-empty.yml +147 -0
  47. package/errors/silent-failures/upload-artifact-permissions-stripped.yml +98 -0
  48. package/errors/triggers/pull-request-branches-filter-matches-base-not-head.yml +140 -0
  49. package/errors/triggers/push-event-fires-on-branch-delete.yml +129 -0
  50. package/errors/triggers/push-first-commit-before-sha-zeros.yml +160 -0
  51. package/errors/yaml-syntax/fromjson-empty-string-crash.yml +99 -0
  52. package/errors/yaml-syntax/if-bang-negation-yaml-tag.yml +145 -0
  53. package/errors/yaml-syntax/local-action-path-always-top-level.yml +142 -0
  54. package/package.json +1 -1
@@ -0,0 +1,146 @@
1
+ id: known-unsolved-017
2
+ title: "timeout-minutes Is Silently Ignored on Steps Inside Composite Actions"
3
+ category: known-unsolved
4
+ severity: limitation
5
+ tags:
6
+ - timeout-minutes
7
+ - composite-action
8
+ - limitation
9
+ - step-timeout
10
+ - composite
11
+ - hung-step
12
+ - action-yml
13
+ patterns:
14
+ - regex: "timeout.?minutes.*composite|using.*composite.*timeout"
15
+ flags: "i"
16
+ - regex: "Unexpected value 'timeout-minutes'"
17
+ flags: "i"
18
+ error_messages:
19
+ - "Unexpected value 'timeout-minutes'"
20
+ root_cause: |
21
+ GitHub Actions supports `timeout-minutes` at the job level and at individual step level
22
+ inside regular workflow files. However, `timeout-minutes` is NOT enforced on steps
23
+ inside composite actions (action.yml files using `runs.using: composite`).
24
+
25
+ Adding `timeout-minutes` to a step within a composite action's `steps:` block is
26
+ accepted by the YAML parser without error, but the timeout is silently NOT applied
27
+ at runtime. A hung step inside a composite action will run until the parent job's
28
+ overall `timeout-minutes` is exhausted — up to 6 hours on GitHub-hosted runners by
29
+ default.
30
+
31
+ This creates a dangerous gap:
32
+ - Network-dependent steps (downloads, API calls, package installs) inside a composite
33
+ action can hang indefinitely if the network is slow or unresponsive
34
+ - `actions/cache` intermittently stalls; wrapping it in a composite action with a
35
+ step `timeout-minutes: 5` provides NO protection
36
+ - Composite action authors cannot provide defensive step timeouts — users of the
37
+ composite action must rely entirely on the calling job's `timeout-minutes`
38
+ - Since the step timeout appears to be set (the YAML is valid), developers believe
39
+ they have a guard when they actually have none
40
+
41
+ The limitation has been tracked and discussed in the community since 2021
42
+ (actions/runner#1979) and remains unresolved as of 2026.
43
+
44
+ Source: actions/runner#1979 — "We would like to see timeout-minutes supported on
45
+ steps in composite actions. Occasionally actions like actions/cache bug out and run
46
+ for the default timeout time (6 hours) which causes unnecessary costs."
47
+ fix: |
48
+ Since step-level timeouts cannot be enforced inside composite actions, use these
49
+ workarounds:
50
+
51
+ 1. **Shell-level timeout**: Wrap commands in `timeout <seconds>` (bash) or `Start-Sleep`
52
+ + `Start-Job` with timeout (PowerShell) to kill hung processes from within the script.
53
+ 2. **Job-level `timeout-minutes`**: Set a conservative timeout on the calling job as a
54
+ safety net — it limits the composite action's maximum runtime.
55
+ 3. **Step-level timeout in the calling workflow**: When calling a composite action as
56
+ a step in a workflow file, `timeout-minutes` IS supported at the step level in the
57
+ workflow (not inside the composite itself). This provides a per-call timeout.
58
+ 4. **Split into multiple reusable actions**: Replace a large composite action with
59
+ multiple smaller ones, each invoked as a separate workflow step — where step-level
60
+ `timeout-minutes` IS enforced.
61
+ fix_code:
62
+ - language: yaml
63
+ label: "WRONG — timeout-minutes inside composite action step is silently ignored"
64
+ code: |
65
+ # action.yml — composite action
66
+ name: "Setup with Timeout"
67
+ runs:
68
+ using: composite
69
+ steps:
70
+ - name: Download dependencies
71
+ timeout-minutes: 5 # ← SILENTLY IGNORED — not enforced at runtime
72
+ shell: bash
73
+ run: curl -o deps.tar.gz "${{ inputs.deps-url }}"
74
+
75
+ - language: yaml
76
+ label: "Workaround: shell-level timeout inside composite action"
77
+ code: |
78
+ # action.yml — composite action
79
+ name: "Setup with Shell Timeout"
80
+ runs:
81
+ using: composite
82
+ steps:
83
+ - name: Download dependencies with shell timeout
84
+ shell: bash
85
+ run: |
86
+ # timeout-minutes on this step would be ignored — use shell timeout instead
87
+ timeout 300 curl -o deps.tar.gz "${{ inputs.deps-url }}" || {
88
+ echo "::error::Download timed out after 5 minutes"
89
+ exit 1
90
+ }
91
+
92
+ - name: Cache restore with timeout guard
93
+ shell: bash
94
+ run: |
95
+ timeout 120 ./restore-cache.sh || {
96
+ echo "::warning::Cache restore timed out — continuing without cache"
97
+ }
98
+
99
+ - language: yaml
100
+ label: "Workaround: step-level timeout in the calling WORKFLOW (not inside composite)"
101
+ code: |
102
+ # workflow.yml — timeout-minutes at step level in workflow DOES work
103
+ jobs:
104
+ build:
105
+ runs-on: ubuntu-latest
106
+ timeout-minutes: 30 # Job-level safety net
107
+ steps:
108
+ - uses: actions/checkout@v4
109
+
110
+ # timeout-minutes here is at the WORKFLOW step level — this IS enforced
111
+ - name: Run composite action
112
+ uses: ./.github/actions/my-composite-action
113
+ timeout-minutes: 10 # Works: this is a workflow step, not inside the composite
114
+
115
+ - run: npm run build
116
+
117
+ - language: yaml
118
+ label: "Workaround: split composite into multiple actions — each gets timeout"
119
+ code: |
120
+ # workflow.yml — multiple smaller actions instead of one large composite
121
+ jobs:
122
+ build:
123
+ runs-on: ubuntu-latest
124
+ steps:
125
+ # Each step in the workflow gets enforceable timeout-minutes
126
+ - uses: ./.github/actions/setup-node
127
+ timeout-minutes: 5 # Enforced — workflow step level
128
+
129
+ - uses: ./.github/actions/restore-cache
130
+ timeout-minutes: 3 # Enforced
131
+
132
+ - uses: ./.github/actions/install-deps
133
+ timeout-minutes: 10 # Enforced
134
+ prevention:
135
+ - "Never rely on `timeout-minutes` inside composite action `steps:` — the field is accepted but silently ignored."
136
+ - "Use `timeout <seconds>` (bash) or PowerShell job timeouts as shell-level guards for long-running composite steps."
137
+ - "Apply `timeout-minutes` at the step level in the CALLING WORKFLOW (not inside the composite) for per-invocation limits."
138
+ - "Always set a job-level `timeout-minutes` on any job that calls composite actions, as a safety net against runaway steps."
139
+ - "Composite action authors should document the expected maximum runtime so callers can set appropriate job-level timeouts."
140
+ docs:
141
+ - url: "https://github.com/actions/runner/issues/1979"
142
+ label: "actions/runner#1979 — timeout-minutes not enforced in composite action steps (open since 2021)"
143
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepstimeout-minutes"
144
+ label: "GitHub Docs: steps[*].timeout-minutes (workflow-level steps — works)"
145
+ - url: "https://docs.github.com/en/actions/sharing-automations/creating-actions/metadata-syntax-for-github-actions#runs-for-composite-actions"
146
+ label: "GitHub Docs: Metadata syntax for composite actions"
@@ -0,0 +1,116 @@
1
+ id: known-unsolved-014
2
+ title: "Reusable Workflows Cannot Be Called from Composite Actions"
3
+ category: known-unsolved
4
+ severity: limitation
5
+ tags:
6
+ - composite-action
7
+ - reusable-workflow
8
+ - workflow-call
9
+ - limitation
10
+ - uses-key
11
+ - no-fix
12
+ patterns:
13
+ - regex: "Reusable workflows cannot be referenced from composite actions"
14
+ flags: "i"
15
+ - regex: "uses:.*\\.github/workflows/.*\\.yml.*composite"
16
+ flags: "i"
17
+ - regex: "A reusable workflow cannot be used as a step in a composite action"
18
+ flags: "i"
19
+ error_messages:
20
+ - "Error: Reusable workflows cannot be referenced from composite actions."
21
+ - "A reusable workflow cannot be used as a step in a composite action."
22
+ root_cause: |
23
+ GitHub Actions enforces a strict separation between two different abstraction levels:
24
+ - **Actions** (composite, JavaScript, Docker) — called from workflow steps via `uses:`
25
+ - **Reusable workflows** (called via `workflow_call` trigger) — called from workflow jobs
26
+ via `uses:` at the JOB level, not the step level
27
+
28
+ A composite action runs within a step inside a job. A reusable workflow, however, IS a
29
+ job (or set of jobs). You cannot embed a job inside a step — this is a fundamental
30
+ architectural constraint, not a configuration error.
31
+
32
+ This fails at validation time with a clear error message. The error is triggered when:
33
+ - A composite action's `runs.steps` contains a `uses:` entry that points to a
34
+ `.github/workflows/*.yml` file (a reusable workflow)
35
+ - An organization tried to nest workflow-level orchestration inside a step-level action
36
+
37
+ There is no workaround that preserves both the composite action wrapping and the reusable
38
+ workflow invocation. GitHub has confirmed this is by design and has no plans to change it.
39
+ The GitHub Actions team's rationale: reusable workflows operate at the job/runner level
40
+ and require job-level context (needs:, outputs:, secrets: inheritance) that cannot exist
41
+ inside a step.
42
+ fix: |
43
+ There is no fix — this is a platform limitation.
44
+
45
+ The recommended alternatives are:
46
+ 1. **Restructure to call the reusable workflow at the job level** (not from inside a
47
+ composite action). Move the reusable workflow call to a dedicated job in your workflow
48
+ file using `jobs.my-job.uses:`.
49
+ 2. **Convert the reusable workflow into a composite action** if the logic does not require
50
+ job-level features (matrix, needs: dependencies, explicit runner selection, secrets
51
+ inheritance via `secrets: inherit`).
52
+ 3. **Inline the reusable workflow steps** into the composite action directly. While this
53
+ loses the DRY benefit of the reusable workflow, it resolves the structural constraint.
54
+ fix_code:
55
+ - language: yaml
56
+ label: "Call reusable workflow at job level (not from composite action)"
57
+ code: |
58
+ # ❌ This FAILS — cannot call reusable workflow from composite action step
59
+ # In: .github/actions/my-composite/action.yml
60
+ # runs:
61
+ # using: "composite"
62
+ # steps:
63
+ # - uses: ./.github/workflows/shared-build.yml # ERROR: not allowed
64
+ # with:
65
+ # environment: staging
66
+
67
+ # ✅ Call reusable workflow at job level in workflow file instead
68
+ jobs:
69
+ setup:
70
+ runs-on: ubuntu-latest
71
+ steps:
72
+ # Composite action can still do pre/post steps
73
+ - uses: ./.github/actions/my-composite
74
+ with:
75
+ param: value
76
+
77
+ shared-build:
78
+ needs: setup
79
+ uses: ./.github/workflows/shared-build.yml
80
+ with:
81
+ environment: staging
82
+ secrets: inherit
83
+ - language: yaml
84
+ label: "Convert reusable workflow to composite action (when job-level features not needed)"
85
+ code: |
86
+ # .github/actions/shared-build/action.yml
87
+ name: "Shared Build"
88
+ description: "Composite action equivalent of the shared-build reusable workflow"
89
+ inputs:
90
+ environment:
91
+ required: true
92
+ description: "Target environment"
93
+ runs:
94
+ using: "composite"
95
+ steps:
96
+ - name: Setup Node
97
+ uses: actions/setup-node@v4
98
+ with:
99
+ node-version: '20'
100
+ - name: Build
101
+ shell: bash
102
+ run: npm run build:${{ inputs.environment }}
103
+ prevention:
104
+ - "Understand the GitHub Actions hierarchy: Docker/JS/composite actions run WITHIN steps; reusable workflows run AS jobs."
105
+ - "Use composite actions when you want to share steps across workflows within a single job."
106
+ - "Use reusable workflows (workflow_call) when you want to share an entire job or multi-job sequence."
107
+ - "If you need both abstraction levels, combine them: a job calls a reusable workflow, and within that workflow's jobs, steps call composite actions."
108
+ docs:
109
+ - url: "https://docs.github.com/en/actions/sharing-automations/reusing-workflows#limitations"
110
+ label: "GitHub docs — Reusing workflows: limitations (composite action restriction)"
111
+ - url: "https://docs.github.com/en/actions/sharing-automations/creating-actions/creating-a-composite-action"
112
+ label: "GitHub docs — Creating a composite action"
113
+ - url: "https://github.com/orgs/community/discussions/11834"
114
+ label: "Community discussion #11834 — reusable workflow called from composite action error"
115
+ - url: "https://stackoverflow.com/questions/70421268/how-to-reference-a-reusable-workflow-from-a-composite-action"
116
+ label: "Stack Overflow — reference reusable workflow from composite action"
@@ -0,0 +1,113 @@
1
+ id: known-unsolved-015
2
+ title: "Scheduled Workflows Only Run on the Default Branch — Cannot Target Arbitrary Branches"
3
+ category: known-unsolved
4
+ severity: limitation
5
+ tags:
6
+ - schedule
7
+ - cron
8
+ - default-branch
9
+ - trigger
10
+ - branches-filter
11
+ - platform-limitation
12
+ patterns:
13
+ - regex: "schedule.*branches|branches.*schedule"
14
+ flags: "i"
15
+ - regex: "cron.*not.*branch|branch.*cron.*ignored"
16
+ flags: "i"
17
+ - regex: "Unexpected value 'branches'"
18
+ flags: "i"
19
+ error_messages:
20
+ - "You have an error in your yaml syntax on line X"
21
+ - "Unexpected value 'branches'"
22
+ - "The 'branches' filter is not supported under 'schedule'"
23
+ root_cause: |
24
+ GitHub Actions schedule (cron) triggers **always run the workflow file from the
25
+ repository's default branch** (typically `main`). This is an intentional platform
26
+ security constraint.
27
+
28
+ There is no supported way to target a non-default branch with a `schedule:` trigger:
29
+ - Adding `branches:` under `schedule:` causes a YAML syntax error ("Unexpected value
30
+ 'branches'") — it is not a valid key in that position.
31
+ - Placing the schedule workflow on a non-default branch does not cause it to run.
32
+ - The `github.ref` and `github.head_ref` values will always reflect the default branch
33
+ when triggered by a schedule event.
34
+
35
+ **Why GitHub enforces this:**
36
+ If scheduled workflows could target arbitrary branches, an attacker who pushes
37
+ malicious code to a feature branch could have it execute on a cron schedule with the
38
+ repository's full secrets — a significant supply-chain risk. By restricting cron runs
39
+ to the default branch, GitHub ensures only reviewed/merged code runs on schedule.
40
+
41
+ **Platform impact:**
42
+ - Cannot create separate nightly build schedules for multiple branches from one repo.
43
+ - Cannot run a scheduled integration test on a long-lived release branch without
44
+ special workarounds.
45
+ - Community has requested this capability since 2021 (community discussion #16107).
46
+
47
+ Sources: Stack Overflow Q/A, GitHub Community #16107, GitHub Docs
48
+ fix: |
49
+ There is no direct fix — this is a platform constraint. Use these workarounds:
50
+
51
+ **Workaround 1 (Recommended): Check out the target branch in the scheduled workflow**
52
+ Keep the scheduled workflow on the default branch but have the job check out the
53
+ desired branch in its `actions/checkout` step:
54
+
55
+ **Workaround 2: Trigger via `workflow_dispatch` from an external scheduler**
56
+ Use the GitHub REST API or `gh workflow run` from a controlled external system
57
+ (another scheduled job, GitHub App, etc.) to trigger a `workflow_dispatch` event
58
+ targeting a specific `ref` (branch or tag).
59
+
60
+ **Workaround 3: `workflow_run` chaining**
61
+ Not a direct substitute, but a workflow triggered by `workflow_run` on a push to
62
+ the target branch can perform scheduled-like follow-up logic.
63
+
64
+ **For release branches:** Merge a scheduled workflow file into each release branch
65
+ as part of the branch maintenance process — each branch can independently schedule
66
+ its own cron.
67
+ fix_code:
68
+ - language: yaml
69
+ label: "Broken — branches filter not valid under schedule, causes YAML error"
70
+ code: |
71
+ # ❌ BROKEN: 'branches' is not a valid key under schedule — YAML syntax error
72
+ on:
73
+ schedule:
74
+ - cron: '0 1 * * *'
75
+ branches: # ← invalid key, causes: Unexpected value 'branches'
76
+ - release/v2
77
+ - language: yaml
78
+ label: "Workaround — check out target branch in the scheduled workflow step"
79
+ code: |
80
+ # ✅ WORKAROUND: workflow lives on default branch, checks out the desired ref
81
+ on:
82
+ schedule:
83
+ - cron: '0 1 * * *' # runs from default branch (main)
84
+
85
+ jobs:
86
+ nightly-test:
87
+ runs-on: ubuntu-latest
88
+ steps:
89
+ - uses: actions/checkout@v4
90
+ with:
91
+ ref: 'release/v2' # explicitly check out the target branch
92
+ # All subsequent steps operate on release/v2 code
93
+ - run: ./run-tests.sh
94
+ - language: yaml
95
+ label: "Workaround — trigger workflow_dispatch against a specific branch via gh CLI"
96
+ code: |
97
+ # ✅ WORKAROUND: External script that fires workflow_dispatch targeting a branch
98
+ # Run this from another scheduled job (e.g., a GitHub App or a cron runner)
99
+ gh workflow run nightly.yml \
100
+ --repo owner/repo \
101
+ --ref release/v2 # workflow_dispatch supports specifying a branch ref
102
+ prevention:
103
+ - "Do not add `branches:` under `schedule:` — it is not a valid key and will cause YAML syntax errors."
104
+ - "Design scheduled workflows to check out the target branch explicitly via `actions/checkout` with the `ref:` input."
105
+ - "For complex multi-branch scheduling needs, consider using a GitHub App or external scheduler that fires `workflow_dispatch` events targeting specific refs."
106
+ - "Document this platform limitation in team wikis to prevent repeated attempts at adding `branches:` to schedule triggers."
107
+ docs:
108
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#schedule"
109
+ label: "GitHub Docs: Events that trigger workflows — schedule"
110
+ - url: "https://github.com/orgs/community/discussions/16107"
111
+ label: "GitHub Community #16107 — Schedule trigger target branch request"
112
+ - url: "https://stackoverflow.com/questions/63612155/how-do-i-trigger-a-scheduled-action-on-a-specific-branch"
113
+ label: "Stack Overflow: How to trigger a scheduled action on a specific branch"
@@ -0,0 +1,149 @@
1
+ id: known-unsolved-016
2
+ title: "secrets Context Cannot Be Directly Referenced in if: Conditions"
3
+ category: known-unsolved
4
+ severity: limitation
5
+ tags:
6
+ - secrets
7
+ - if-condition
8
+ - conditional
9
+ - env
10
+ - limitation
11
+ - expressions
12
+ - step-condition
13
+ patterns:
14
+ - regex: "if:.*\\$\\{\\{.*secrets\\..*\\}\\}"
15
+ flags: "i"
16
+ - regex: "secrets\\.[A-Z_a-z]+\\s*!=\\s*''"
17
+ flags: "i"
18
+ error_messages:
19
+ - "This job was skipped."
20
+ root_cause: |
21
+ GitHub Actions explicitly prohibits direct use of the `secrets` context in `if:`
22
+ conditional expressions at the job or step level. The platform blocks this as a
23
+ security measure to prevent secret values from being leaked through expression
24
+ evaluation in workflow logs.
25
+
26
+ Attempting `if: ${{ secrets.MY_SECRET != '' }}` or `if: secrets.MY_SECRET` silently
27
+ fails — the condition evaluates to an empty string (falsy), causing the step or job
28
+ to be skipped with no error message, warning, or explanation.
29
+
30
+ The same restriction applies at the job level:
31
+ ```yaml
32
+ jobs:
33
+ deploy:
34
+ if: ${{ secrets.DEPLOY_KEY != '' }} # silently evaluates wrong
35
+ ```
36
+
37
+ This catches developers off guard because:
38
+ - The workflow is syntactically valid and passes YAML linting — no parse error
39
+ - The failure mode is silent: the job/step is skipped with "This job was skipped"
40
+ rather than an explicit error about the secrets restriction
41
+ - The pattern looks correct by analogy with other contexts (`github.*`, `env.*`,
42
+ `vars.*`) that DO work in `if:` conditions
43
+ - Secrets used in `run:` scripts and `with:` inputs work fine — only `if:` is blocked
44
+
45
+ GitHub's documentation explicitly states: "Secrets cannot be directly referenced
46
+ in `if:` conditionals. Instead, consider setting secrets as job-level environment
47
+ variables, then referencing the environment variables to conditionally run steps."
48
+
49
+ As of 2026 this is a by-design limitation with no planned native fix.
50
+ `actionlint` now flags direct secret references in `if:` expressions as an error.
51
+
52
+ Sources:
53
+ - GitHub Docs — Using secrets in GitHub Actions (use-secrets.md)
54
+ - github/docs#12722 — PR documenting the `if:` condition restriction
55
+ fix: |
56
+ Promote the secret to a job-level `env:` variable that evaluates the boolean (not the
57
+ secret value itself), then reference `env.VARIABLE_NAME` in the `if:` condition.
58
+
59
+ For job-level `if:` (not step-level), use a preceding detection job that outputs
60
+ whether the secret is present, and condition the downstream job on that output.
61
+ fix_code:
62
+ - language: yaml
63
+ label: "WRONG — direct secrets reference in step if: condition"
64
+ code: |
65
+ jobs:
66
+ deploy:
67
+ runs-on: ubuntu-latest
68
+ steps:
69
+ - name: Deploy to production
70
+ if: ${{ secrets.DEPLOY_KEY != '' }} # silently wrong — step is skipped
71
+ run: ./deploy.sh
72
+ env:
73
+ DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
74
+
75
+ - language: yaml
76
+ label: "CORRECT — promote secret presence to job-level env, reference in step if:"
77
+ code: |
78
+ jobs:
79
+ deploy:
80
+ runs-on: ubuntu-latest
81
+ env:
82
+ # Safe: evaluates to "true"/"false" string — not the secret value itself
83
+ HAS_DEPLOY_KEY: ${{ secrets.DEPLOY_KEY != '' }}
84
+ steps:
85
+ - name: Deploy to production
86
+ if: env.HAS_DEPLOY_KEY == 'true'
87
+ run: ./deploy.sh
88
+ env:
89
+ DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
90
+
91
+ - language: yaml
92
+ label: "CORRECT — job-level conditional via detection job + output"
93
+ code: |
94
+ jobs:
95
+ check-secrets:
96
+ runs-on: ubuntu-latest
97
+ outputs:
98
+ has_key: ${{ steps.check.outputs.has_key }}
99
+ steps:
100
+ - id: check
101
+ env:
102
+ DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
103
+ run: |
104
+ if [ -n "$DEPLOY_KEY" ]; then
105
+ echo "has_key=true" >> "$GITHUB_OUTPUT"
106
+ else
107
+ echo "has_key=false" >> "$GITHUB_OUTPUT"
108
+ fi
109
+
110
+ deploy:
111
+ needs: check-secrets
112
+ # Job-level if: can reference job outputs — not secrets directly
113
+ if: needs.check-secrets.outputs.has_key == 'true'
114
+ runs-on: ubuntu-latest
115
+ steps:
116
+ - run: ./deploy.sh
117
+ env:
118
+ DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
119
+
120
+ - language: yaml
121
+ label: "CORRECT — inline env check using bash within step"
122
+ code: |
123
+ jobs:
124
+ deploy:
125
+ runs-on: ubuntu-latest
126
+ steps:
127
+ - name: Deploy (skip gracefully if secret absent)
128
+ env:
129
+ DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
130
+ run: |
131
+ if [ -z "$DEPLOY_KEY" ]; then
132
+ echo "No DEPLOY_KEY configured — skipping deployment"
133
+ exit 0
134
+ fi
135
+ ./deploy.sh
136
+ prevention:
137
+ - "Never reference `secrets.*` directly in `if:` conditions — always promote to `env:` first."
138
+ - "Use `env.HAS_SECRET: ${{ secrets.MY_SECRET != '' }}` at the job level to create a safe boolean env var."
139
+ - "Install and run `actionlint` in CI — it now flags direct secret references in `if:` as an error."
140
+ - "For job-level conditionals based on secret presence, use a dedicated detection job with outputs."
141
+ docs:
142
+ - url: "https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions#using-secrets-in-a-workflow"
143
+ label: "GitHub Docs: Using secrets in a workflow (secrets cannot be in if: conditionals)"
144
+ - url: "https://github.com/github/docs/pull/12722"
145
+ label: "github/docs#12722 — Document secrets in if: conditionals limitation"
146
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsif"
147
+ label: "Workflow syntax: steps[*].if"
148
+ - url: "https://github.com/rhysd/actionlint"
149
+ label: "actionlint — flags direct secrets in if: conditions as an error"
@@ -0,0 +1,133 @@
1
+ id: permissions-auth-013
2
+ title: "Dependabot Pull Requests Cannot Access Repository Secrets — Read-Only Token"
3
+ category: permissions-auth
4
+ severity: silent-failure
5
+ tags:
6
+ - dependabot
7
+ - secrets
8
+ - github-token
9
+ - pull-request
10
+ - read-only
11
+ patterns:
12
+ - regex: "Context access might be invalid: secrets\\."
13
+ flags: "i"
14
+ - regex: "denied|forbidden|403"
15
+ flags: "i"
16
+ - regex: "Resource not accessible by integration"
17
+ flags: "i"
18
+ error_messages:
19
+ - "Context access might be invalid: secrets.NPM_TOKEN"
20
+ - "Error: Process completed with exit code 1."
21
+ - "HttpError: Resource not accessible by integration"
22
+ root_cause: |
23
+ For security reasons, GitHub Actions workflows triggered by Dependabot pull requests
24
+ are granted a **read-only GITHUB_TOKEN** and **cannot access repository secrets**.
25
+
26
+ When a Dependabot PR triggers an `on: pull_request` workflow:
27
+ - `secrets.*` expressions evaluate to empty string (not an error — silently empty)
28
+ - `GITHUB_TOKEN` has read-only permissions (cannot write to the repository, push
29
+ tags, create releases, comment on PRs, etc.)
30
+ - Steps that need secrets (publishing to npm, Docker Hub, PyPI, etc.) fail with
31
+ authentication errors or silently produce wrong results
32
+
33
+ This is intentional: Dependabot opens PRs that update dependencies from external
34
+ sources. If Dependabot-triggered workflows had full secret access, a malicious
35
+ package update could exfiltrate your credentials via a modified build step.
36
+
37
+ The failure is often silent because:
38
+ - The secret evaluates to empty string — tools may fail with "missing credentials"
39
+ rather than a clear "secret unavailable" error
40
+ - `GITHUB_TOKEN` write failures show as 403 "Resource not accessible by integration"
41
+
42
+ Sources: dependabot/dependabot-core#3253, #5464
43
+ fix: |
44
+ Choose one of these approaches depending on your security requirements:
45
+
46
+ **Option 1 (Recommended): Use Dependabot secrets**
47
+ Add the required secrets to the Dependabot secrets store (Settings > Secrets and
48
+ variables > Dependabot). Dependabot-triggered workflows can access these separately
49
+ from repository secrets.
50
+
51
+ **Option 2: Auto-approve and merge without secrets**
52
+ For dependency updates, use `pull_request_review` + `pull_request` auto-merge
53
+ pattern — approve Dependabot PRs that pass CI without needing secrets.
54
+
55
+ **Option 3: Use `pull_request_target` with caution**
56
+ `pull_request_target` runs in the base repo context and has full secret access.
57
+ Only use this for trusted, controlled steps (like leaving a comment) — never
58
+ checkout and run untrusted fork code in a `pull_request_target` step with secrets.
59
+
60
+ **Option 4: Filter out Dependabot runs**
61
+ Add `if: github.actor != 'dependabot[bot]'` to skip secret-requiring steps for
62
+ Dependabot PRs, letting CI pass without the publishing step.
63
+ fix_code:
64
+ - language: yaml
65
+ label: "Add secrets to Dependabot secrets store (Settings → Secrets → Dependabot)"
66
+ code: |
67
+ # Add NPM_TOKEN (and any other required secrets) to:
68
+ # Settings > Secrets and variables > Dependabot
69
+ # These are separate from repository secrets and accessible to Dependabot runs.
70
+
71
+ # No workflow change needed — ${{ secrets.NPM_TOKEN }} will resolve correctly
72
+ # once the secret is added to the Dependabot secrets store.
73
+ - language: yaml
74
+ label: "Skip secret-requiring steps for Dependabot PRs"
75
+ code: |
76
+ jobs:
77
+ build:
78
+ runs-on: ubuntu-latest
79
+ steps:
80
+ - uses: actions/checkout@v4
81
+
82
+ - name: Run tests
83
+ run: npm test
84
+ # Tests run for all PRs including Dependabot
85
+
86
+ - name: Publish to npm (skip for Dependabot)
87
+ if: github.actor != 'dependabot[bot]'
88
+ run: npm publish
89
+ env:
90
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
91
+ # NPM_TOKEN is empty for Dependabot — skip the step entirely
92
+ - language: yaml
93
+ label: "Auto-approve Dependabot PRs using Dependabot secrets + gh CLI"
94
+ code: |
95
+ name: Auto-approve Dependabot
96
+ on: pull_request
97
+
98
+ permissions:
99
+ pull-requests: write
100
+ contents: write
101
+
102
+ jobs:
103
+ auto-approve:
104
+ runs-on: ubuntu-latest
105
+ if: github.actor == 'dependabot[bot]'
106
+ steps:
107
+ - name: Fetch Dependabot metadata
108
+ id: meta
109
+ uses: dependabot/fetch-metadata@v2
110
+
111
+ - name: Auto-approve minor and patch updates
112
+ if: steps.meta.outputs.update-type != 'version-update:semver-major'
113
+ run: gh pr review --approve "$PR_URL"
114
+ env:
115
+ PR_URL: ${{ github.event.pull_request.html_url }}
116
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
117
+ # GITHUB_TOKEN in dependabot context is read-only for repo content
118
+ # but CAN approve PRs when permissions: pull-requests: write is set
119
+ prevention:
120
+ - "Never assume repository secrets are available in Dependabot-triggered workflows — they aren't."
121
+ - "Use `github.actor == 'dependabot[bot]'` conditions to branch logic for Dependabot vs human PRs."
122
+ - "Add required secrets to the Dependabot secrets store separately from repository secrets."
123
+ - "Audit CI workflows for `${{ secrets.* }}` usage and test with a Dependabot PR to confirm behavior."
124
+ - "Do not use `pull_request_target` with `actions/checkout` on the PR head ref — this is a security vulnerability."
125
+ docs:
126
+ - url: "https://docs.github.com/en/code-security/dependabot/working-with-dependabot/automating-dependabot-with-github-actions"
127
+ label: "Automating Dependabot with GitHub Actions"
128
+ - url: "https://docs.github.com/en/code-security/dependabot/working-with-dependabot/configuring-access-to-private-registries-for-dependabot"
129
+ label: "Configuring Dependabot secrets"
130
+ - url: "https://github.com/dependabot/dependabot-core/issues/3253"
131
+ label: "dependabot-core#3253 — secrets unavailable in Dependabot-triggered workflows"
132
+ - url: "https://github.com/dependabot/dependabot-core/issues/5464"
133
+ label: "dependabot-core#5464 — Dependabot read-only token behavior"