@htekdev/actions-debugger 1.0.81 → 1.0.83

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.
@@ -0,0 +1,74 @@
1
+ id: runner-environment-146
2
+ title: "ubuntu-24.04 runner — Ruby and gem not pre-installed"
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - ubuntu-24
7
+ - ruby
8
+ - gem
9
+ - tools-missing
10
+ - migration
11
+
12
+ patterns:
13
+ - regex: 'ruby\s*:\s*command not found'
14
+ flags: i
15
+ - regex: 'gem\s*:\s*command not found'
16
+ flags: i
17
+ - regex: 'No such file or directory.*ruby'
18
+ flags: i
19
+
20
+ error_messages:
21
+ - "/usr/bin/bash: ruby: command not found"
22
+ - "/usr/bin/bash: gem: command not found"
23
+ - "Error: ruby not found"
24
+
25
+ root_cause: |
26
+ GitHub's ubuntu-24.04 runner image does not include Ruby in its pre-installed
27
+ software list. Unlike ubuntu-22.04 (which ships Ruby 3.0.x from the Ubuntu 22
28
+ package repository), ubuntu-24.04 dropped Ruby as a default pre-installed tool.
29
+
30
+ Workflows that rely on `ruby`, `gem`, `bundle`, or `rake` being available without
31
+ an explicit setup step will fail with "command not found" when the runner image is
32
+ ubuntu-24.04 or when ubuntu-latest resolves to ubuntu-24.04.
33
+
34
+ This commonly affects:
35
+ - Workflows that run `gem install` or `bundle install` directly
36
+ - Custom scripts that call `ruby my-script.rb`
37
+ - Jekyll static site workflows without the setup-ruby action
38
+ - Workflows that inherited ubuntu-22.04 behavior when pinned to ubuntu-latest
39
+
40
+ fix: |
41
+ Use the ruby/setup-ruby action to install Ruby on any runner. This is the
42
+ recommended approach for cross-platform consistency and version pinning.
43
+
44
+ Alternatively, install Ruby via apt-get if a specific package-managed version
45
+ is acceptable, but ruby/setup-ruby is strongly preferred for version control.
46
+
47
+ fix_code:
48
+ - language: yaml
49
+ label: "Use ruby/setup-ruby action (recommended)"
50
+ code: |
51
+ - uses: ruby/setup-ruby@v1
52
+ with:
53
+ ruby-version: '3.3'
54
+ bundler-cache: true # runs bundle install and caches gems
55
+
56
+ - run: ruby my-script.rb
57
+
58
+ - language: yaml
59
+ label: "Install via apt-get (version uncontrolled)"
60
+ code: |
61
+ - run: sudo apt-get install -y ruby ruby-dev
62
+
63
+ prevention:
64
+ - Always use ruby/setup-ruby instead of relying on pre-installed Ruby.
65
+ - Test workflows against ubuntu-24.04 explicitly before switching ubuntu-latest.
66
+ - Check the ubuntu-24.04 pre-installed software list when migrating from ubuntu-22.04.
67
+
68
+ docs:
69
+ - url: https://github.com/ruby/setup-ruby
70
+ label: "ruby/setup-ruby — GitHub Actions"
71
+ - url: https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md
72
+ label: "ubuntu-24.04 runner image — pre-installed software"
73
+ - url: https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2204-Readme.md
74
+ label: "ubuntu-22.04 runner image — Ruby pre-installed"
@@ -0,0 +1,85 @@
1
+ id: runner-environment-147
2
+ title: "Windows runner 'shell: powershell' invokes PowerShell 5 not PowerShell 7"
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - windows
7
+ - powershell
8
+ - pwsh
9
+ - shell
10
+ - powershell-version
11
+
12
+ patterns:
13
+ - regex: 'The term .{0,20} is not recognized as the name of a cmdlet'
14
+ flags: i
15
+ - regex: 'Unexpected token.*\?\.'
16
+ flags: i
17
+ - regex: 'parameter cannot be found.*Parallel'
18
+ flags: i
19
+
20
+ error_messages:
21
+ - "The term '??' is not recognized as the name of a cmdlet, function, script file, or operable program."
22
+ - "Unexpected token '?.' in expression or statement."
23
+ - "ForEach-Object: A parameter cannot be found that matches parameter name 'Parallel'."
24
+
25
+ root_cause: |
26
+ On Windows GitHub-hosted runners, explicitly setting `shell: powershell` in a
27
+ workflow step invokes `powershell.exe` — Windows PowerShell 5.1 — NOT the modern
28
+ PowerShell 7.x (pwsh).
29
+
30
+ Windows PowerShell 5.1 is a separate executable that lacks numerous features
31
+ introduced in PowerShell 6.0 (Core) and later:
32
+ - Null-coalescing operator: `$a ?? $b` (requires PS 7.0+)
33
+ - Null-coalescing assignment: `$a ??= 'default'` (requires PS 7.0+)
34
+ - Null-conditional member access: `$obj?.Property` (requires PS 7.0+)
35
+ - Ternary operator: `$x ? $y : $z` (requires PS 7.0+)
36
+ - ForEach-Object -Parallel (requires PS 7.0+)
37
+ - Pipeline chain operators: `&&`, `||` (requires PS 7.0+)
38
+
39
+ The default shell on Windows runners (when no `shell:` key is specified) is `pwsh`
40
+ (PowerShell 7). This means workflows that omit `shell:` work fine, but any step that
41
+ explicitly adds `shell: powershell` regresses to PowerShell 5.1.
42
+
43
+ Developers often set `shell: powershell` when they mean "use PowerShell" without
44
+ knowing the distinction between Windows PowerShell and PowerShell 7.
45
+
46
+ fix: |
47
+ Replace `shell: powershell` with `shell: pwsh` to use PowerShell 7.
48
+
49
+ If the workflow requires PowerShell 5.1 compatibility (rare), audit the script
50
+ and remove PS7-only syntax. However, in almost all cases the intent is PowerShell 7.
51
+
52
+ fix_code:
53
+ - language: yaml
54
+ label: "Use pwsh for PowerShell 7 (fix)"
55
+ code: |
56
+ # Before (broken on modern PS syntax):
57
+ # - run: $value = $null ?? "default"
58
+ # shell: powershell
59
+
60
+ # After (correct):
61
+ - run: $value = $null ?? "default"
62
+ shell: pwsh
63
+ - language: yaml
64
+ label: "Set pwsh as default shell for all Windows steps"
65
+ code: |
66
+ defaults:
67
+ run:
68
+ shell: pwsh
69
+
70
+ jobs:
71
+ build:
72
+ runs-on: windows-latest
73
+ steps:
74
+ - run: $value = $null ?? "default" # uses pwsh by default
75
+
76
+ prevention:
77
+ - 'Use `shell: pwsh` (not `shell: powershell`) in any step using PowerShell 6+ syntax.'
78
+ - 'Set `defaults.run.shell: pwsh` at workflow level to apply PowerShell 7 globally on Windows.'
79
+ - 'Use actionlint — it does not currently distinguish PS5 vs PS7 but code review should catch explicit `shell: powershell`.'
80
+
81
+ docs:
82
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-syntax-for-github-actions#jobsjob_idstepsshell'
83
+ label: 'Workflow syntax: shell — GitHub Docs'
84
+ - url: 'https://learn.microsoft.com/en-us/powershell/scripting/whats-new/differences-from-windows-powershell'
85
+ label: 'Differences between Windows PowerShell 5.1 and PowerShell 7 — Microsoft Docs'
@@ -0,0 +1,102 @@
1
+ id: silent-failures-077
2
+ title: '`github.event.inputs` is undefined (null) when workflow triggered via `workflow_call`'
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - workflow-call
7
+ - workflow-dispatch
8
+ - inputs
9
+ - github-event-inputs
10
+ - reusable-workflow
11
+ patterns:
12
+ - regex: 'github\.event\.inputs\.'
13
+ flags: 'g'
14
+ - regex: 'on:\s*\n\s+workflow_call:'
15
+ flags: 'im'
16
+ error_messages:
17
+ - "Expression github.event.inputs.environment evaluated to ''"
18
+ - 'github.event.inputs is null'
19
+ - 'unexpected value '''''
20
+ root_cause: |
21
+ When a workflow supports both `workflow_dispatch` and `workflow_call` triggers,
22
+ developers often use `github.event.inputs.param` to read input values.
23
+ This works for `workflow_dispatch` but silently fails for `workflow_call`:
24
+
25
+ - `workflow_dispatch`: inputs are surfaced at `github.event.inputs.*`
26
+ (always strings regardless of declared type)
27
+ - `workflow_call`: inputs are NOT placed in `github.event.inputs`; they are
28
+ only available via the `inputs` context (`inputs.param`)
29
+
30
+ When a reusable workflow is invoked via `workflow_call`, `github.event.inputs`
31
+ is an empty object — referencing `github.event.inputs.param` evaluates to an
32
+ empty string `''`, not an error. The workflow continues running with silently
33
+ missing parameter values, producing incorrect behavior rather than a visible
34
+ failure.
35
+
36
+ The `inputs` context (without `github.event.`) is the correct way to read
37
+ inputs in both scenarios, as it is populated for both `workflow_dispatch` and
38
+ `workflow_call`.
39
+ fix: |
40
+ Replace all `github.event.inputs.*` references with `inputs.*` — the `inputs`
41
+ context works correctly for both `workflow_dispatch` and `workflow_call` events.
42
+ fix_code:
43
+ - language: yaml
44
+ label: 'Use inputs context instead of github.event.inputs'
45
+ code: |
46
+ on:
47
+ workflow_dispatch:
48
+ inputs:
49
+ environment:
50
+ type: string
51
+ required: true
52
+ workflow_call:
53
+ inputs:
54
+ environment:
55
+ type: string
56
+ required: true
57
+
58
+ jobs:
59
+ deploy:
60
+ runs-on: ubuntu-latest
61
+ steps:
62
+ # BAD: github.event.inputs is empty/null in workflow_call context
63
+ - run: echo "Deploying to ${{ github.event.inputs.environment }}"
64
+
65
+ # GOOD: inputs context works for both workflow_dispatch and workflow_call
66
+ - run: echo "Deploying to ${{ inputs.environment }}"
67
+
68
+ - language: yaml
69
+ label: 'Dual-trigger workflow using inputs context correctly'
70
+ code: |
71
+ on:
72
+ workflow_dispatch:
73
+ inputs:
74
+ dry_run:
75
+ type: boolean
76
+ default: false
77
+ workflow_call:
78
+ inputs:
79
+ dry_run:
80
+ type: boolean
81
+ default: false
82
+
83
+ jobs:
84
+ release:
85
+ runs-on: ubuntu-latest
86
+ steps:
87
+ - uses: actions/checkout@v4
88
+ # inputs.dry_run works for both dispatch and call
89
+ - if: '!inputs.dry_run'
90
+ run: ./publish.sh
91
+ prevention:
92
+ - 'Always use the `inputs` context (not `github.event.inputs`) when reading inputs in workflows that support both `workflow_dispatch` and `workflow_call`'
93
+ - 'Grep your workflow files for `github.event.inputs` and replace with `inputs` before adding a `workflow_call` trigger'
94
+ - '`github.event.inputs` values are always strings; `inputs` respects the declared type (boolean, number, string, choice)'
95
+ - 'Test reusable workflows by calling them from another workflow, not just via the UI dispatch button'
96
+ docs:
97
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_call'
98
+ label: 'workflow_call event — GitHub Docs'
99
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_dispatch'
100
+ label: 'workflow_dispatch event — GitHub Docs'
101
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#inputs-context'
102
+ label: 'inputs context — GitHub Docs'
@@ -0,0 +1,85 @@
1
+ id: silent-failures-076
2
+ title: "Job outputs: block missing — needs.job.outputs.key is always empty string in downstream jobs"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - job-outputs
7
+ - needs-context
8
+ - GITHUB_OUTPUT
9
+ - outputs-block
10
+ - empty-string
11
+ - downstream-jobs
12
+ patterns:
13
+ - regex: 'needs\.[a-z_][a-z0-9_-]*\.outputs\.[a-z_][a-z0-9_-]*'
14
+ flags: 'i'
15
+ error_messages:
16
+ - "needs.deploy.outputs.artifact_url is always empty string"
17
+ - "needs.build.outputs.sha: empty output in downstream job"
18
+ root_cause: |
19
+ Writing to $GITHUB_OUTPUT inside a step only makes the value available within that job
20
+ via steps.<step_id>.outputs.<key>. To expose an output to downstream jobs via
21
+ needs.<job>.outputs.<key>, the job must explicitly declare an outputs: block that maps
22
+ key names to step output expressions using ${{ steps.<id>.outputs.<key> }}.
23
+
24
+ Without the job-level outputs: mapping, $GITHUB_OUTPUT writes are silently ignored by
25
+ downstream consumers — needs.<job>.outputs.<key> evaluates to an empty string with no
26
+ warning, error, or annotation. The step that wrote to $GITHUB_OUTPUT exits with code 0
27
+ and no indication of the problem.
28
+
29
+ This two-step mechanism is required: the step writes to $GITHUB_OUTPUT (job-internal),
30
+ and the job's outputs: block re-exports selected values to the workflow's needs graph.
31
+ fix: |
32
+ Add an outputs: block at the job level (as a sibling of runs-on:, steps:, etc.)
33
+ that maps the desired key names to the corresponding step output expressions.
34
+ Every key you want accessible via needs.<job>.outputs.<key> must appear in this block.
35
+ fix_code:
36
+ - language: yaml
37
+ label: "Correct: job outputs: block declares which step outputs to expose"
38
+ code: |
39
+ jobs:
40
+ build:
41
+ runs-on: ubuntu-latest
42
+ outputs:
43
+ artifact-version: ${{ steps.version.outputs.value }}
44
+ build-sha: ${{ steps.hash.outputs.sha }}
45
+ steps:
46
+ - name: Compute version
47
+ id: version
48
+ run: echo "value=1.2.3" >> $GITHUB_OUTPUT
49
+ - name: Compute hash
50
+ id: hash
51
+ run: echo "sha=$(sha256sum dist/app | cut -d' ' -f1)" >> $GITHUB_OUTPUT
52
+
53
+ deploy:
54
+ needs: build
55
+ runs-on: ubuntu-latest
56
+ steps:
57
+ - run: echo "Deploying ${{ needs.build.outputs.artifact-version }}"
58
+ - language: yaml
59
+ label: "Wrong: outputs: block absent — needs.build.outputs.* is always empty"
60
+ code: |
61
+ jobs:
62
+ build:
63
+ runs-on: ubuntu-latest
64
+ # No outputs: block — step writes are invisible to downstream jobs
65
+ steps:
66
+ - name: Compute version
67
+ id: version
68
+ run: echo "value=1.2.3" >> $GITHUB_OUTPUT
69
+
70
+ deploy:
71
+ needs: build
72
+ runs-on: ubuntu-latest
73
+ steps:
74
+ - run: echo "${{ needs.build.outputs.artifact-version }}" # Always ''
75
+ prevention:
76
+ - "Any job that produces values for downstream jobs MUST have a matching outputs: block"
77
+ - "Use actionlint — it warns when needs.<job>.outputs.<key> references an undeclared key"
78
+ - "Debug by printing ${{ toJSON(needs) }} in a downstream step to see all available outputs"
79
+ - "Note: steps.<id>.outputs.<key> within the same job does NOT require an outputs: block"
80
+ - "Composite action outputs and reusable workflow outputs have separate but analogous declaration requirements"
81
+ docs:
82
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/passing-information-between-jobs"
83
+ label: "GitHub Docs: Passing information between jobs"
84
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idoutputs"
85
+ label: "GitHub Docs: jobs.<job_id>.outputs syntax"
@@ -0,0 +1,79 @@
1
+ id: triggers-057
2
+ title: '`on.pull_request types: [closed]` fires for both merged AND unmerged PR closures — use `if: merged == true` guard'
3
+ category: triggers
4
+ severity: silent-failure
5
+ tags:
6
+ - pull_request
7
+ - closed
8
+ - merged
9
+ - event-types
10
+ - deploy-on-merge
11
+
12
+ patterns:
13
+ - regex: 'types:\s*\[.*closed.*\]'
14
+ flags: 'i'
15
+ - regex: 'on:\s*\n\s+pull_request:\s*\n\s+types:\s*\[.*closed'
16
+ flags: 'im'
17
+
18
+ error_messages:
19
+ - "github.event.action: closed"
20
+ - "github.event.pull_request.merged: false"
21
+
22
+ root_cause: |
23
+ The `pull_request` event `closed` type fires whenever a PR is closed — regardless
24
+ of whether it was merged or simply closed without merging. GitHub does not provide
25
+ a `merged` type for the `pull_request` event.
26
+
27
+ Developers commonly use `types: [closed]` to trigger deployment or post-merge
28
+ workflows, assuming `closed` is equivalent to "merged into the base branch". In
29
+ reality, a PR can be closed (abandoned, rejected) without being merged, and the
30
+ `closed` event fires in both cases.
31
+
32
+ The distinction is only available via `github.event.pull_request.merged` (a
33
+ boolean) or `github.event.pull_request.merge_commit_sha` (non-null if merged).
34
+ Without an explicit check, workflows using `types: [closed]` will run on
35
+ abandoned PRs, causing spurious deployments, incorrect release triggers, or
36
+ unnecessary job runs.
37
+
38
+ fix: |
39
+ Add an `if:` condition to the job or workflow that checks
40
+ `github.event.pull_request.merged == true` to ensure the workflow only
41
+ proceeds when the PR was actually merged.
42
+
43
+ fix_code:
44
+ - language: yaml
45
+ label: 'Guard job with merged == true check'
46
+ code: |
47
+ on:
48
+ pull_request:
49
+ types: [closed]
50
+
51
+ jobs:
52
+ deploy:
53
+ # Only run when PR was merged, not when simply closed
54
+ if: github.event.pull_request.merged == true
55
+ runs-on: ubuntu-latest
56
+ steps:
57
+ - uses: actions/checkout@v4
58
+ - run: ./deploy.sh
59
+ - language: yaml
60
+ label: 'Equivalent guard using merge_commit_sha'
61
+ code: |
62
+ jobs:
63
+ notify:
64
+ if: github.event.pull_request.merge_commit_sha != ''
65
+ runs-on: ubuntu-latest
66
+ steps:
67
+ - name: Notify on merge
68
+ run: echo "PR merged at ${{ github.event.pull_request.merge_commit_sha }}"
69
+
70
+ prevention:
71
+ - 'Never use `types: [closed]` without an `if: github.event.pull_request.merged == true` guard for merge-triggered workflows.'
72
+ - 'Remember: there is no `merged` event type for `pull_request` — `closed` is the closest type, but it requires the merged guard.'
73
+ - 'Test your workflow by manually closing a PR without merging and verifying the workflow does not run (or is skipped).'
74
+
75
+ docs:
76
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request'
77
+ label: 'pull_request event — GitHub Docs'
78
+ - url: 'https://docs.github.com/en/webhooks/webhook-events-and-payloads#pull_request'
79
+ label: 'pull_request webhook payload — GitHub Docs'
@@ -0,0 +1,83 @@
1
+ id: triggers-055
2
+ title: "branches: filter does not apply to tag pushes — tag push always triggers unless tags-ignore is set"
3
+ category: triggers
4
+ severity: silent-failure
5
+ tags:
6
+ - push
7
+ - branches-filter
8
+ - tags
9
+ - tag-push
10
+ - tags-ignore
11
+ - ref-type
12
+ patterns:
13
+ - regex: 'on:\s*\n\s+push:\s*\n\s+branches:'
14
+ flags: 'm'
15
+ - regex: 'Triggered by refs/tags/'
16
+ flags: 'i'
17
+ error_messages:
18
+ - "Run triggered by push to refs/tags/v1.0.0 (unexpected — only branches: [main] was set)"
19
+ root_cause: |
20
+ The branches: filter under on.push: only evaluates branch refs (refs/heads/*). A push
21
+ to a tag ref (refs/tags/*) is an entirely separate ref type that the branches: filter
22
+ has no authority to gate. If no tags: or tags-ignore: filter is specified under
23
+ on.push:, ALL tag pushes pass through unconditionally.
24
+
25
+ This causes workflows intended to run "only on pushes to main" to also run on every
26
+ release tag, annotated tag, and automated tag created by CI pipelines.
27
+
28
+ Branch and tag filters are independent dimensions of the push event:
29
+ branches: / branches-ignore: — applies ONLY to branch refs (refs/heads/*)
30
+ tags: / tags-ignore: — applies ONLY to tag refs (refs/tags/*)
31
+
32
+ If a filter type is absent, all refs of that type pass through.
33
+ Setting branches: [main] does NOT automatically exclude tags.
34
+
35
+ The same mechanism applies in reverse: a tags: filter does not affect branch pushes.
36
+ And the paths: filter is also bypassed by tag pushes (see push-paths-filter-bypassed-by-tag).
37
+ fix: |
38
+ To restrict the workflow to branch pushes only, add a tags-ignore: ['**'] pattern
39
+ to exclude all tag pushes. Alternatively, add an if: condition to check github.ref_type.
40
+ fix_code:
41
+ - language: yaml
42
+ label: "Option 1: add tags-ignore to explicitly exclude all tag pushes"
43
+ code: |
44
+ on:
45
+ push:
46
+ branches:
47
+ - main
48
+ - 'release/**'
49
+ tags-ignore:
50
+ - '**' # Exclude all tag pushes from triggering this workflow
51
+ - language: yaml
52
+ label: "Option 2: use if condition on the job to check ref_type"
53
+ code: |
54
+ on:
55
+ push:
56
+ branches:
57
+ - main
58
+
59
+ jobs:
60
+ build:
61
+ if: github.ref_type == 'branch' # Skip if triggered by a tag push
62
+ runs-on: ubuntu-latest
63
+ steps:
64
+ - run: echo "Only runs on branch pushes"
65
+ - language: yaml
66
+ label: "Option 3: explicitly allow specific tags alongside branches"
67
+ code: |
68
+ on:
69
+ push:
70
+ branches:
71
+ - main
72
+ tags:
73
+ - 'v[0-9]+.[0-9]+.[0-9]+' # Only semver release tags; other tags excluded
74
+ prevention:
75
+ - "Whenever you set branches:, also consider whether you need tags-ignore: ['**'] to exclude tag pushes"
76
+ - "Check if automated tooling (release-please, semantic-release, etc.) creates tags in your repo — they will trigger this workflow"
77
+ - "The same principle applies to paths: filter — it also does not block tag pushes"
78
+ - "Remember the rule: absent filter = all refs of that type pass through"
79
+ docs:
80
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#onpushbranchestagsbranches-ignoretags-ignore"
81
+ label: "GitHub Docs: push event branches/tags filter syntax"
82
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#push"
83
+ label: "GitHub Docs: Push event triggers"
@@ -0,0 +1,75 @@
1
+ id: triggers-056
2
+ title: '`on.release: types: [created]` fires when a draft release is first saved'
3
+ category: triggers
4
+ severity: silent-failure
5
+ tags:
6
+ - release
7
+ - triggers
8
+ - draft
9
+ - created
10
+ - published
11
+ patterns:
12
+ - regex: 'types:\s*\[?created\]?'
13
+ flags: 'i'
14
+ - regex: 'on:\s*\n\s+release:'
15
+ flags: 'im'
16
+ error_messages:
17
+ - 'Triggered by: release'
18
+ - 'github.event.action: created'
19
+ - 'github.event.release.draft: true'
20
+ root_cause: |
21
+ The `release` event with `types: [created]` fires when ANY release record is
22
+ first created in GitHub — including draft releases. When a developer clicks
23
+ "Save draft" to prepare release notes before publishing, GitHub fires the
24
+ `created` event immediately. This causes deployment or publish workflows to
25
+ run against an incomplete, unpublished draft.
26
+
27
+ The `created` type maps to the moment the release row is inserted in GitHub's
28
+ database, regardless of draft or published state. Many developers assume
29
+ `created` means "publicly released" because that mirrors the UI action of
30
+ clicking "Publish release", but the event fires earlier.
31
+
32
+ The correct type for "a release is now publicly visible" is `published`, which
33
+ fires only when the release transitions from draft (or pre-release) to a
34
+ published, non-draft release.
35
+ fix: |
36
+ Use `types: [published]` for workflows that should only run when a release
37
+ becomes publicly available. Add an `if:` guard as a defensive layer when
38
+ using `created`.
39
+ fix_code:
40
+ - language: yaml
41
+ label: 'Use published instead of created for deploy workflows'
42
+ code: |
43
+ # BAD: fires on draft creation too
44
+ on:
45
+ release:
46
+ types: [created]
47
+
48
+ # GOOD: fires only when release becomes publicly published
49
+ on:
50
+ release:
51
+ types: [published]
52
+ - language: yaml
53
+ label: 'Defensive if: guard when created type is required'
54
+ code: |
55
+ on:
56
+ release:
57
+ types: [created]
58
+ jobs:
59
+ deploy:
60
+ # Skip execution when triggered by a draft save
61
+ if: '!github.event.release.draft'
62
+ runs-on: ubuntu-latest
63
+ steps:
64
+ - uses: actions/checkout@v4
65
+ - run: ./deploy.sh
66
+ prevention:
67
+ - 'Prefer `types: [published]` for deployment workflows to avoid triggering on draft saves'
68
+ - 'Note: `published` also fires when a pre-release is promoted to a full release — guard with `!github.event.release.prerelease` if needed'
69
+ - 'Add `if: ''!github.event.release.draft''` as an explicit guard when using the `created` type'
70
+ - 'Test your release workflow by creating a draft release and verifying it does or does not trigger as expected'
71
+ docs:
72
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#release'
73
+ label: 'release event — GitHub Docs'
74
+ - url: 'https://docs.github.com/en/rest/releases/releases#create-a-release'
75
+ label: 'Create a release REST API — GitHub Docs'
@@ -0,0 +1,98 @@
1
+ id: yaml-syntax-052
2
+ title: '`secrets` context not available in `with:` inputs for reusable workflow calls — use `secrets:` block instead'
3
+ category: yaml-syntax
4
+ severity: error
5
+ tags:
6
+ - reusable-workflows
7
+ - secrets
8
+ - with
9
+ - workflow-call
10
+ - secrets-context
11
+
12
+ patterns:
13
+ - regex: 'Context access might be invalid: secrets'
14
+ flags: 'i'
15
+ - regex: 'secrets\.[A-Z_][A-Z0-9_]*'
16
+ flags: 'i'
17
+
18
+ error_messages:
19
+ - "Context access might be invalid: secrets"
20
+ - "The workflow is not valid. .github/workflows/caller.yml: Unrecognized named-value: 'secrets'"
21
+ - "Unrecognized named-value: 'secrets'. Located at position 1 within expression: secrets.MY_TOKEN"
22
+
23
+ root_cause: |
24
+ When calling a reusable workflow, the `with:` key (which passes inputs) does NOT
25
+ have access to the `secrets` context. The `secrets` context is intentionally
26
+ restricted to the `secrets:` block of the reusable workflow call to prevent
27
+ secrets from being accidentally exposed as plain-text input values.
28
+
29
+ This restriction applies ONLY to reusable workflow calls (`jobs.<id>.uses:`).
30
+ Regular action steps (`steps.<id>.uses:`) DO allow `${{ secrets.MY_SECRET }}`
31
+ in their `with:` blocks.
32
+
33
+ Attempting to pass a secret via `with:` in a reusable workflow call results in
34
+ an actionlint error or a runtime error: "Context access might be invalid: secrets".
35
+ Even if it were allowed, passing secrets as `with:` inputs would expose the
36
+ secret value in the workflow logs as a plain-text input.
37
+
38
+ The correct mechanism is the `secrets:` mapping on the calling job, which
39
+ explicitly maps caller secrets to the callee's declared `on.workflow_call.secrets`
40
+ parameters. This preserves masking and audit trail.
41
+
42
+ fix: |
43
+ Move secret values from `with:` to the `secrets:` block of the reusable
44
+ workflow call. Ensure the callee workflow declares the secret under
45
+ `on.workflow_call.secrets` with a matching name.
46
+
47
+ fix_code:
48
+ - language: yaml
49
+ label: 'Caller workflow — pass secrets via secrets: not with:'
50
+ code: |
51
+ # BAD: secrets context not available in with:
52
+ # jobs:
53
+ # call:
54
+ # uses: ./.github/workflows/deploy.yml
55
+ # with:
56
+ # token: ${{ secrets.DEPLOY_TOKEN }} # Error: secrets context invalid here
57
+
58
+ # GOOD: pass secrets via secrets: block
59
+ jobs:
60
+ call:
61
+ uses: ./.github/workflows/deploy.yml
62
+ with:
63
+ environment: production # non-secret inputs go here
64
+ secrets:
65
+ deploy-token: ${{ secrets.DEPLOY_TOKEN }} # secrets go here
66
+ - language: yaml
67
+ label: 'Callee workflow — declare secrets under on.workflow_call.secrets'
68
+ code: |
69
+ # .github/workflows/deploy.yml
70
+ on:
71
+ workflow_call:
72
+ inputs:
73
+ environment:
74
+ type: string
75
+ required: true
76
+ secrets:
77
+ deploy-token:
78
+ required: true
79
+
80
+ jobs:
81
+ deploy:
82
+ runs-on: ubuntu-latest
83
+ steps:
84
+ - name: Use the secret
85
+ env:
86
+ TOKEN: ${{ secrets.deploy-token }}
87
+ run: echo "Deploying to ${{ inputs.environment }}"
88
+
89
+ prevention:
90
+ - 'Never use `${{ secrets.* }}` inside `with:` of a reusable workflow call — the `secrets` context is blocked there.'
91
+ - 'Declare all required secrets in the callee under `on.workflow_call.secrets:` and pass them via `secrets:` in the caller.'
92
+ - 'Run actionlint in CI to catch `secrets` context misuse before it reaches runtime.'
93
+
94
+ docs:
95
+ - url: 'https://docs.github.com/en/actions/sharing-automations/reusing-workflows#using-inputs-and-secrets-in-a-reusable-workflow'
96
+ label: 'Using inputs and secrets in a reusable workflow — GitHub Docs'
97
+ - url: 'https://docs.github.com/en/actions/sharing-automations/reusing-workflows#passing-secrets-to-called-workflows'
98
+ label: 'Passing secrets to called workflows — GitHub Docs'