@htekdev/actions-debugger 1.0.54 → 1.0.56

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,124 @@
1
+ id: known-unsolved-037
2
+ title: "Skipped jobs show as 'skipped' — branch protection required status checks block PR merge"
3
+ category: known-unsolved
4
+ severity: limitation
5
+ tags:
6
+ - required-status-checks
7
+ - branch-protection
8
+ - skipped
9
+ - conditional-job
10
+ - merge-blocked
11
+ - known-limitation
12
+ patterns:
13
+ - regex: 'if:\s+github\.event_name\s+!=\s+'
14
+ flags: i
15
+ - regex: 'if:\s+\$\{\{\s*github\.event_name\s*!=\s*'
16
+ flags: i
17
+ error_messages:
18
+ - "Required status check 'ci/test' was not successful — status: skipped"
19
+ - "Branch protection rule requires passing status checks before merging"
20
+ root_cause: |
21
+ When a job's if: condition evaluates to false, GitHub Actions marks that job as
22
+ "Skipped" in the Checks API. Branch protection rules that require a specific check
23
+ to pass only accept a conclusion of "success" — not "skipped", "cancelled", or
24
+ "neutral".
25
+
26
+ This creates a practical trap: a team sets up a required check for a job like
27
+ ci/test, then later adds an if: condition to skip that job on certain events
28
+ (for example, to avoid running tests on tag pushes or documentation-only changes).
29
+ The conditional logic is correct for workflow execution, but the skipped conclusion
30
+ permanently blocks all PRs where that condition evaluates to false.
31
+
32
+ GitHub has documented this as intentional: a skipped job is not a successful job.
33
+ There is no configuration option to treat "skipped" as equivalent to "success" for
34
+ branch protection purposes as of 2026. The workaround requires a structural change
35
+ to the workflow.
36
+ fix: |
37
+ This is a known limitation with no direct fix. The recommended workarounds are:
38
+
39
+ 1. ALWAYS-PASS WRAPPER JOB: Create a wrapper job that always runs and reports
40
+ the real outcome. The wrapper job becomes the required status check instead of
41
+ the real CI job. If CI was skipped (e.g., docs-only change), the wrapper passes.
42
+ If CI ran and failed, the wrapper fails.
43
+
44
+ 2. MOVE THE CONDITION INSIDE THE JOB: Instead of using if: at the job level, keep
45
+ the job always running and use if: at the step level. An empty job always
46
+ succeeds, so the required status check passes.
47
+
48
+ 3. PATHS FILTER PATTERN (dorny/paths-filter): Use a separate filtering job and
49
+ pass its output as a condition parameter to downstream jobs while keeping a
50
+ pass-through job for status check reporting.
51
+
52
+ 4. RE-EVALUATE THE REQUIRED CHECK: If the check is truly optional for some events,
53
+ consider removing it from required status checks and instead enforce it only at
54
+ the merge queue level.
55
+ fix_code:
56
+ - language: yaml
57
+ label: "Problem: conditional job is skipped, blocking required status check"
58
+ code: |
59
+ on: [push, pull_request]
60
+
61
+ jobs:
62
+ test:
63
+ runs-on: ubuntu-latest
64
+ # This job is required in branch protection, but gets skipped on push to main
65
+ if: github.event_name == 'pull_request'
66
+ steps:
67
+ - run: npm test
68
+ # On push events, this job is SKIPPED, blocking required status check
69
+ - language: yaml
70
+ label: "Fix: always-pass wrapper job becomes the required status check"
71
+ code: |
72
+ on: [push, pull_request]
73
+
74
+ jobs:
75
+ test:
76
+ runs-on: ubuntu-latest
77
+ if: github.event_name == 'pull_request'
78
+ steps:
79
+ - uses: actions/checkout@v4
80
+ - run: npm test
81
+
82
+ # Set THIS job as the required status check in branch protection
83
+ ci-status:
84
+ runs-on: ubuntu-latest
85
+ needs: [test]
86
+ if: always()
87
+ steps:
88
+ - name: Report CI result
89
+ run: |
90
+ result="${{ needs.test.result }}"
91
+ if [[ "$result" == "success" || "$result" == "skipped" ]]; then
92
+ echo "CI passed or was intentionally skipped — OK to merge"
93
+ else
94
+ echo "CI failed (result: $result)"
95
+ exit 1
96
+ fi
97
+ - language: yaml
98
+ label: "Alternative: move condition inside job so job always runs and passes when empty"
99
+ code: |
100
+ on: [push, pull_request]
101
+
102
+ jobs:
103
+ test:
104
+ runs-on: ubuntu-latest
105
+ # No if: at job level — job always runs and always produces a conclusion
106
+ steps:
107
+ - uses: actions/checkout@v4
108
+
109
+ - name: Run tests (pull_request only)
110
+ if: github.event_name == 'pull_request'
111
+ run: npm test
112
+ # If step is skipped, job still succeeds — required check passes
113
+ prevention:
114
+ - "Never add an if: condition to a job that is a required status check — use a wrapper job instead"
115
+ - "Use the always-pass wrapper pattern from the start when adding new required status checks"
116
+ - "Test required check behavior by creating a draft PR that intentionally triggers the skip condition"
117
+ - "Document which jobs are required status checks in a comment at the top of the workflow file"
118
+ docs:
119
+ - url: "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/troubleshooting-required-status-checks"
120
+ label: "GitHub Docs: Troubleshooting required status checks"
121
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idif"
122
+ label: "GitHub Docs: Job-level if conditions"
123
+ - url: "https://github.com/dorny/paths-filter"
124
+ label: "dorny/paths-filter: Conditional execution with status reporting"
@@ -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,99 @@
1
+ id: silent-failures-055
2
+ title: "'github.event_name' is 'workflow_call' inside reusable workflows — not the caller's event"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - reusable-workflow
7
+ - workflow_call
8
+ - event_name
9
+ - github-context
10
+ - conditional
11
+ - silent
12
+ patterns:
13
+ - regex: 'github\.event_name\s*==\s*[''"]push[''"]'
14
+ flags: i
15
+ - regex: 'github\.event_name\s*==\s*[''"]pull_request[''"]'
16
+ flags: i
17
+ - regex: 'github\.event_name\s*==\s*[''"]workflow_dispatch[''"]'
18
+ flags: i
19
+ error_messages:
20
+ - "Evaluating: github.event_name == 'push' => false"
21
+ - "Step skipped: if condition 'github.event_name == \"push\"' was false"
22
+ root_cause: |
23
+ When a workflow is called as a reusable workflow via on: workflow_call, GitHub Actions
24
+ sets github.event_name to "workflow_call" inside that workflow — NOT to the triggering
25
+ event from the caller workflow.
26
+
27
+ A common mistake is to write conditional logic in a reusable workflow that checks
28
+ github.event_name expecting the caller's event (push, pull_request, workflow_dispatch,
29
+ etc.). These conditions always evaluate to false when the workflow is invoked via
30
+ workflow_call, silently skipping the affected steps or entire jobs.
31
+
32
+ The behaviour is especially confusing because developers often test the reusable workflow
33
+ in isolation via workflow_dispatch — in which case github.event_name IS correct. The
34
+ silent skip only appears when the workflow is called from another workflow, and the skipped
35
+ step or job disappears from the run summary with no error message.
36
+ fix: |
37
+ Pass the caller's event name as an explicit input to the reusable workflow. The caller
38
+ reads github.event_name from its own context (where it is correct) and passes it as a
39
+ string input. Inside the reusable workflow, check inputs.caller_event (or whatever name
40
+ you choose) instead of github.event_name.
41
+
42
+ Alternatively, restructure so that event-specific logic stays in the caller workflow and
43
+ the reusable workflow only receives final parameters — not the raw event name.
44
+ fix_code:
45
+ - language: yaml
46
+ label: "Problem: event_name check always false in reusable workflow"
47
+ code: |
48
+ # reusable.yml — WRONG: event_name is always "workflow_call" here
49
+ on:
50
+ workflow_call:
51
+
52
+ jobs:
53
+ build:
54
+ runs-on: ubuntu-latest
55
+ steps:
56
+ - name: Deploy only on push
57
+ if: github.event_name == 'push' # Always false — event_name is "workflow_call"
58
+ run: echo "Deploying..."
59
+ - language: yaml
60
+ label: "Fix: accept caller_event as an explicit input"
61
+ code: |
62
+ # reusable.yml — CORRECT: accept the caller's event as an input
63
+ on:
64
+ workflow_call:
65
+ inputs:
66
+ caller_event:
67
+ type: string
68
+ required: true
69
+
70
+ jobs:
71
+ build:
72
+ runs-on: ubuntu-latest
73
+ steps:
74
+ - name: Deploy only on push
75
+ if: inputs.caller_event == 'push' # Correct — uses the passed-in value
76
+ run: echo "Deploying..."
77
+ - language: yaml
78
+ label: "Caller workflow: pass github.event_name as input"
79
+ code: |
80
+ # caller.yml — pass the caller's event name to the reusable workflow
81
+ on: [push, pull_request]
82
+
83
+ jobs:
84
+ call-reusable:
85
+ uses: ./.github/workflows/reusable.yml
86
+ with:
87
+ caller_event: ${{ github.event_name }} # "push" or "pull_request"
88
+ prevention:
89
+ - "Never use 'github.event_name' in a reusable workflow to detect the caller's event — it will always be 'workflow_call'"
90
+ - "Pass event-specific data as explicit inputs; document expected values in the input description field"
91
+ - "When testing a reusable workflow via workflow_dispatch, simulate the production caller_event value via inputs to catch conditional errors early"
92
+ - "The same rule applies to github.event.* properties — many will be empty or refer to the workflow_call event, not the caller's event"
93
+ docs:
94
+ - url: "https://docs.github.com/en/actions/sharing-automations/reusing-workflows"
95
+ label: "GitHub Docs: Reusing workflows"
96
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#github-context"
97
+ label: "GitHub Docs: github context reference"
98
+ - url: "https://docs.github.com/en/actions/sharing-automations/reusing-workflows#limitations"
99
+ label: "GitHub Docs: Reusable workflow limitations"
@@ -0,0 +1,105 @@
1
+ id: silent-failures-056
2
+ title: "'continue-on-error: true' makes a failed job report success in required status checks"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - continue-on-error
7
+ - required-status-checks
8
+ - branch-protection
9
+ - checks-api
10
+ - silent
11
+ - branch-protection-bypass
12
+ patterns:
13
+ - regex: 'continue-on-error:\s*true'
14
+ flags: i
15
+ error_messages:
16
+ - "Job succeeded (continue-on-error)"
17
+ - "Required status check passed (job actually failed but continue-on-error: true)"
18
+ root_cause: |
19
+ When a job has continue-on-error: true set, GitHub Actions converts the job's conclusion
20
+ from failure to success before writing the result to the Checks API. The branch
21
+ protection system only sees the API-level conclusion — which is "success" — and allows
22
+ the pull request to merge.
23
+
24
+ The job timeline in the GitHub UI shows a yellow icon with "(Cancelled)" or similar
25
+ wording, but the Checks API and branch protection treat it as passed. Developers
26
+ relying on required status checks to enforce quality gates unknowingly lose that
27
+ protection for any job marked continue-on-error: true.
28
+
29
+ This is particularly dangerous on jobs that run security scans, license checks, or
30
+ integration tests where the team deliberately added them as required checks to block
31
+ broken or risky changes from merging.
32
+ fix: |
33
+ Avoid using continue-on-error: true on jobs that are configured as required status
34
+ checks in branch protection rules. Instead, handle acceptable failure conditions
35
+ explicitly inside the job using if: steps.*.outcome == 'failure' logic.
36
+
37
+ If you need to always continue a workflow past a flaky or optional step but still
38
+ surface failures in status checks, use a separate sentinel job that:
39
+ 1. Depends on the real job with needs:
40
+ 2. Runs with if: always()
41
+ 3. Fails explicitly if the upstream job failed
42
+
43
+ This pattern separates "keep the workflow running" from "record the real outcome".
44
+ fix_code:
45
+ - language: yaml
46
+ label: "Problem: continue-on-error silently hides failures from status checks"
47
+ code: |
48
+ jobs:
49
+ security-scan:
50
+ runs-on: ubuntu-latest
51
+ continue-on-error: true # DANGER: required status check will PASS even if scan fails
52
+ steps:
53
+ - name: Run security scan
54
+ run: ./run-scan.sh
55
+ - language: yaml
56
+ label: "Fix: use a sentinel job to preserve the real outcome"
57
+ code: |
58
+ jobs:
59
+ security-scan:
60
+ runs-on: ubuntu-latest
61
+ # No continue-on-error here
62
+ steps:
63
+ - name: Run security scan
64
+ run: ./run-scan.sh
65
+
66
+ # This is the job to set as the required status check
67
+ security-gate:
68
+ runs-on: ubuntu-latest
69
+ needs: [security-scan]
70
+ if: always()
71
+ steps:
72
+ - name: Check security scan result
73
+ if: needs.security-scan.result != 'success'
74
+ run: |
75
+ echo "Security scan did not pass (result: ${{ needs.security-scan.result }})"
76
+ exit 1
77
+ - language: yaml
78
+ label: "Alternative: handle acceptable failures inside the step, not the job"
79
+ code: |
80
+ jobs:
81
+ test:
82
+ runs-on: ubuntu-latest
83
+ steps:
84
+ - name: Run optional extended tests
85
+ id: extended
86
+ run: ./run-extended-tests.sh
87
+ continue-on-error: true # Step-level is safer than job-level
88
+
89
+ - name: Fail job if extended tests failed unexpectedly
90
+ if: steps.extended.outcome == 'failure'
91
+ run: |
92
+ echo "Extended tests failed — blocking merge"
93
+ exit 1
94
+ prevention:
95
+ - "Never set continue-on-error: true at the job level for jobs that are required status checks"
96
+ - "Use continue-on-error: true at the step level instead — it does not affect the Checks API job conclusion"
97
+ - "Audit your branch protection required checks against all jobs that have continue-on-error: true"
98
+ - "Use the sentinel job pattern to separate workflow continuation from status reporting"
99
+ docs:
100
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idcontinue-on-error"
101
+ label: "GitHub Docs: continue-on-error syntax"
102
+ - url: "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#require-status-checks-before-merging"
103
+ label: "GitHub Docs: Required status checks before merging"
104
+ - url: "https://docs.github.com/en/rest/checks/runs"
105
+ label: "GitHub REST API: Checks runs"
@@ -0,0 +1,115 @@
1
+ id: triggers-039
2
+ title: "'github.sha' in pull_request_target points to base branch HEAD, not the PR's head commit"
3
+ category: triggers
4
+ severity: silent-failure
5
+ tags:
6
+ - pull_request_target
7
+ - github-sha
8
+ - base-branch
9
+ - pr-head
10
+ - checkout
11
+ - security
12
+ - silent
13
+ patterns:
14
+ - regex: 'pull_request_target'
15
+ flags: i
16
+ - regex: 'github\.event\.pull_request\.head\.sha'
17
+ flags: i
18
+ - regex: 'github\.sha.*pull_request_target'
19
+ flags: i
20
+ error_messages:
21
+ - "Tests passed but PR code was never executed (checked out base branch at github.sha)"
22
+ root_cause: |
23
+ The pull_request_target event fires in the context of the BASE branch of a pull request,
24
+ not the PR's head branch. Consequently, github.sha inside a pull_request_target workflow
25
+ is the HEAD commit SHA of the BASE branch — typically main or master — not the PR
26
+ contributor's changes.
27
+
28
+ This design is intentional: pull_request_target runs with repository secrets and write
29
+ permissions available, so GitHub restricts it to trusted base-branch code to prevent
30
+ malicious PR code from exfiltrating secrets. However, it causes a silent logic error when
31
+ developers expect github.sha (or the default actions/checkout behaviour, which checks out
32
+ github.sha) to build and test the PR's changes.
33
+
34
+ The result is a CI run that appears to succeed — but it compiled and tested the base
35
+ branch code, not the pull request's changes. The PR author sees green CI even though
36
+ their changes were never executed.
37
+ fix: |
38
+ To work with PR head code in a pull_request_target workflow, explicitly specify the PR
39
+ head SHA using github.event.pull_request.head.sha in the checkout step's ref: input.
40
+
41
+ SECURITY WARNING: checking out untrusted PR code in a workflow that has access to secrets
42
+ creates a pwn-request vulnerability. Only check out PR head code in jobs with minimal
43
+ permissions and no secret exposure.
44
+
45
+ For most CI use cases — building, linting, testing — use the standard pull_request event
46
+ instead of pull_request_target. The pull_request event correctly checks out PR changes
47
+ but runs without repository secrets, which is the safe and intended design.
48
+ fix_code:
49
+ - language: yaml
50
+ label: "Problem: default checkout in pull_request_target checks out base branch"
51
+ code: |
52
+ on: pull_request_target
53
+
54
+ jobs:
55
+ test:
56
+ runs-on: ubuntu-latest
57
+ steps:
58
+ - uses: actions/checkout@v4
59
+ # No ref specified — uses github.sha which is BASE branch HEAD, not PR code
60
+ - run: npm test # Tests base branch, not the PR changes
61
+ - language: yaml
62
+ label: "Explicit PR head checkout (only when no secrets are exposed)"
63
+ code: |
64
+ on: pull_request_target
65
+
66
+ jobs:
67
+ label-and-check:
68
+ runs-on: ubuntu-latest
69
+ permissions:
70
+ pull-requests: write # Minimal permissions — no secrets
71
+ steps:
72
+ - uses: actions/checkout@v4
73
+ with:
74
+ ref: ${{ github.event.pull_request.head.sha }}
75
+ # Only safe because this job has no secret access
76
+ # Do NOT add secrets: or environment: to jobs that do this
77
+ - language: yaml
78
+ label: "Recommended: use pull_request for testing, pull_request_target only for privileged operations"
79
+ code: |
80
+ # Standard PR testing — pull_request has no secrets but correctly checks out PR changes
81
+ on: pull_request
82
+
83
+ jobs:
84
+ test:
85
+ runs-on: ubuntu-latest
86
+ steps:
87
+ - uses: actions/checkout@v4
88
+ # github.sha is the PR merge commit — correct for testing PR changes
89
+ - run: npm test
90
+
91
+ ---
92
+ # Separate privileged workflow for labeling/commenting — uses pull_request_target
93
+ # This one works with base-branch context (github.sha = base HEAD) — which is correct
94
+ # for privileged operations that should only run trusted code
95
+ on: pull_request_target
96
+
97
+ jobs:
98
+ label:
99
+ runs-on: ubuntu-latest
100
+ permissions:
101
+ pull-requests: write
102
+ steps:
103
+ - uses: actions/labeler@v5
104
+ prevention:
105
+ - "Default to 'pull_request' event for building and testing PR code — it correctly checks out PR changes and has no secrets"
106
+ - "Use 'pull_request_target' only for privileged operations that genuinely need secrets or write permissions (labeling, commenting, deployment approval)"
107
+ - "Never expose repository secrets in the same job that checks out untrusted PR head code via github.event.pull_request.head.sha"
108
+ - "Add a comment next to any pull_request_target checkout step documenting which ref is used and why it is safe"
109
+ docs:
110
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request_target"
111
+ label: "GitHub Docs: pull_request_target event"
112
+ - url: "https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/"
113
+ label: "GitHub Security Lab: Preventing pwn requests"
114
+ - url: "https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions"
115
+ label: "GitHub Docs: Security hardening for GitHub Actions"
@@ -0,0 +1,104 @@
1
+ id: triggers-040
2
+ title: "Missing 'on: merge_group' trigger — required status checks fail in merge queue"
3
+ category: triggers
4
+ severity: error
5
+ tags:
6
+ - merge-queue
7
+ - merge_group
8
+ - required-status-checks
9
+ - branch-protection
10
+ - ci-failure
11
+ - triggers
12
+ patterns:
13
+ - regex: 'merge_group'
14
+ flags: i
15
+ - regex: 'Required status checks were not passing.*merge.queue'
16
+ flags: i
17
+ error_messages:
18
+ - "Required status check 'ci/test' was not reported — PR ejected from merge queue"
19
+ - "This branch requires linear history. The merge queue could not merge this pull request."
20
+ root_cause: |
21
+ GitHub's merge queue (available since May 2023 GA) uses a dedicated event called
22
+ merge_group to trigger workflows. This is distinct from the pull_request event.
23
+
24
+ When a pull request enters the merge queue, GitHub creates a temporary merge branch
25
+ and fires the merge_group event. Workflows that only declare on: pull_request (or
26
+ other events) do not trigger on merge_group and therefore never create any status
27
+ check runs for the queued PR.
28
+
29
+ Branch protection rules that require specific status checks see no check result for
30
+ the merge group run and treat the absence as failure, ejecting the PR from the queue
31
+ with a message that the required checks were not passing.
32
+
33
+ The merge queue was added to GitHub Actions in May 2023 (GitHub Changelog). Existing
34
+ workflows created before that date have no merge_group trigger and must be updated
35
+ manually. Projects that enable merge queue on an existing repo will silently find
36
+ that all PRs are blocked from being merged via the queue.
37
+ fix: |
38
+ Add merge_group: to the on: trigger block alongside pull_request (and push, if used).
39
+ The merge_group event accepts no filter options — it fires whenever any PR enters
40
+ the merge queue for a protected branch.
41
+
42
+ If your workflow uses branch filters under on.pull_request.branches, those filters
43
+ do NOT apply to merge_group — the event always fires regardless of branch name.
44
+ This is intentional: the merge queue uses temporary synthetic branches.
45
+ fix_code:
46
+ - language: yaml
47
+ label: "Problem: workflow only triggers on pull_request, not in merge queue"
48
+ code: |
49
+ # BEFORE: only runs on pull_request — never fires in merge queue
50
+ on:
51
+ pull_request:
52
+ branches: [main]
53
+
54
+ jobs:
55
+ test:
56
+ runs-on: ubuntu-latest
57
+ steps:
58
+ - uses: actions/checkout@v4
59
+ - run: npm test
60
+ - language: yaml
61
+ label: "Fix: add merge_group trigger so CI runs in the merge queue"
62
+ code: |
63
+ # AFTER: runs on both pull_request and when entering the merge queue
64
+ on:
65
+ pull_request:
66
+ branches: [main]
67
+ merge_group: # Required for merge queue — no filter options available
68
+
69
+ jobs:
70
+ test:
71
+ runs-on: ubuntu-latest
72
+ steps:
73
+ - uses: actions/checkout@v4
74
+ - run: npm test
75
+ - language: yaml
76
+ label: "With push trigger (common three-trigger pattern)"
77
+ code: |
78
+ on:
79
+ push:
80
+ branches: [main]
81
+ pull_request:
82
+ branches: [main]
83
+ merge_group: # Always needed if merge queue is enabled on the repo
84
+
85
+ jobs:
86
+ ci:
87
+ runs-on: ubuntu-latest
88
+ steps:
89
+ - uses: actions/checkout@v4
90
+ - run: npm ci
91
+ - run: npm test
92
+ - run: npm run lint
93
+ prevention:
94
+ - "Any time you enable merge queue on a branch, audit all required-check workflows and add 'merge_group:' to each"
95
+ - "The merge_group event accepts no filter keys — do not try to add 'branches:' or 'types:' under it"
96
+ - "Test merge queue behavior by adding a PR to the queue and checking the Actions tab for the merge group run"
97
+ - "Add a comment near the merge_group trigger explaining its purpose for teammates unfamiliar with merge queues"
98
+ docs:
99
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#merge_group"
100
+ label: "GitHub Docs: merge_group event"
101
+ - url: "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue"
102
+ label: "GitHub Docs: Managing a merge queue"
103
+ - url: "https://github.blog/changelog/2023-05-12-github-actions-merge-queue-is-generally-available/"
104
+ label: "GitHub Changelog: Merge queue GA (May 2023)"
@@ -0,0 +1,91 @@
1
+ id: yaml-syntax-038
2
+ title: "'::save-state::' and '::get-state::' workflow commands deprecated — upgrade to GITHUB_STATE"
3
+ category: yaml-syntax
4
+ severity: warning
5
+ tags:
6
+ - save-state
7
+ - get-state
8
+ - deprecated
9
+ - workflow-commands
10
+ - environment-files
11
+ - GITHUB_STATE
12
+ patterns:
13
+ - regex: 'The `save-state` command is deprecated'
14
+ flags: i
15
+ - regex: 'The `get-state` command is deprecated'
16
+ flags: i
17
+ - regex: '::save-state name='
18
+ flags: ''
19
+ - regex: '::get-state name='
20
+ flags: ''
21
+ error_messages:
22
+ - "Warning: The `save-state` command is deprecated and will be disabled soon. Please upgrade to using Environment Files."
23
+ - "Warning: The `get-state` command is deprecated and will be disabled soon. Please upgrade to using Environment Files."
24
+ root_cause: |
25
+ GitHub Actions originally provided workflow commands ::save-state name=FOO::value and
26
+ ::get-state name=FOO:: as a way to persist data between the main body of a step and its
27
+ pre: or post: hooks in JavaScript actions.
28
+
29
+ GitHub deprecated these commands when it introduced environment files (GITHUB_STATE,
30
+ GITHUB_ENV, GITHUB_OUTPUT) as a more robust alternative. Workflows and actions that use
31
+ the old echo "::save-state name=...::value" or echo "::get-state name=...:" syntax now
32
+ produce deprecation warnings in workflow logs.
33
+
34
+ When these commands are eventually disabled, steps using them will silently fail to persist
35
+ state — the post: hook will read an empty string from the state variable, causing subtle
36
+ logic errors. Actions published to the Marketplace are particularly affected because older
37
+ versions used these commands before the deprecation was announced.
38
+ fix: |
39
+ Replace the deprecated workflow commands with the GITHUB_STATE environment file approach:
40
+ - To write state: append "KEY=value" to $GITHUB_STATE (shell) or write to
41
+ process.env['GITHUB_STATE'] (Node.js)
42
+ - To read state in pre:/post: hooks: read the environment variable STATE_<KEY>
43
+
44
+ In shell-based steps the pattern is identical to GITHUB_ENV and GITHUB_OUTPUT.
45
+ In JavaScript actions, upgrade to @actions/core v1.10.0+ and use the saveState() and
46
+ getState() helpers, which internally write to GITHUB_STATE.
47
+ fix_code:
48
+ - language: yaml
49
+ label: "Deprecated: ::save-state:: and ::get-state:: commands (produces warnings)"
50
+ code: |
51
+ # DEPRECATED — produces warning in logs, will eventually break
52
+ - name: Save state (deprecated)
53
+ run: echo "::save-state name=SERVER_PID::12345"
54
+
55
+ - name: Read state in post step (deprecated)
56
+ run: echo "Saved PID was $(echo "::get-state name=SERVER_PID::")"
57
+ - language: yaml
58
+ label: "Correct: GITHUB_STATE environment file"
59
+ code: |
60
+ # Write state to GITHUB_STATE file
61
+ - name: Save state
62
+ run: echo "SERVER_PID=12345" >> $GITHUB_STATE
63
+
64
+ # State is automatically available as STATE_<KEY> in later phases
65
+ - name: Read state (available in main, pre, and post phases)
66
+ run: echo "Server PID was $STATE_SERVER_PID"
67
+ - language: yaml
68
+ label: "PowerShell equivalent"
69
+ code: |
70
+ - name: Save state (PowerShell)
71
+ shell: pwsh
72
+ run: |
73
+ "SERVER_PID=12345" | Out-File -FilePath $env:GITHUB_STATE -Append
74
+
75
+ - name: Read state (PowerShell)
76
+ shell: pwsh
77
+ run: |
78
+ Write-Host "Server PID was $env:STATE_SERVER_PID"
79
+ prevention:
80
+ - "Audit actions with pre: or post: hooks — these are the primary consumers of save-state/get-state"
81
+ - "Upgrade to @actions/core v1.10.0+ which uses GITHUB_STATE internally via saveState()/getState()"
82
+ - "Search existing workflows and composite actions for '::save-state' and '::get-state' patterns before they are disabled"
83
+ - "Pin to action versions that have migrated to GITHUB_STATE; check CHANGELOG for migration notes"
84
+ - "The same deprecation cycle affected ::set-output:: (now GITHUB_OUTPUT) and ::set-env:: (now GITHUB_ENV)"
85
+ docs:
86
+ - url: "https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#environment-files"
87
+ label: "GitHub Docs: Workflow commands — environment files"
88
+ - url: "https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/"
89
+ label: "GitHub Changelog: Deprecating save-state and set-output commands (Oct 2022)"
90
+ - url: "https://github.com/actions/toolkit/releases/tag/%40actions%2Fcore%401.10.0"
91
+ label: "actions/toolkit: @actions/core v1.10.0 release notes"
@@ -0,0 +1,115 @@
1
+ id: yaml-syntax-039
2
+ title: "'type: choice' not supported for workflow_call inputs — validation error when combining with workflow_dispatch"
3
+ category: yaml-syntax
4
+ severity: error
5
+ tags:
6
+ - workflow_call
7
+ - workflow_dispatch
8
+ - inputs
9
+ - type-choice
10
+ - validation
11
+ - combined-triggers
12
+ patterns:
13
+ - regex: 'Input type .choice. is not supported'
14
+ flags: i
15
+ - regex: 'Unexpected value .choice.'
16
+ flags: i
17
+ - regex: 'Invalid workflow file.*type.*choice'
18
+ flags: i
19
+ error_messages:
20
+ - "Invalid workflow file: Input type 'choice' is not supported for workflow_call triggers. Allowed types: boolean, number, string"
21
+ - "Unexpected value 'choice', expected one of: boolean, number, string"
22
+ - "Invalid value for inputs.*.type: 'choice'"
23
+ root_cause: |
24
+ GitHub Actions supports different input types depending on the trigger:
25
+ - workflow_dispatch supports: boolean, choice, environment, number, string
26
+ - workflow_call supports only: boolean, number, string
27
+
28
+ When developers combine both triggers in the same workflow file (a common pattern for
29
+ workflows that can be called by other workflows AND dispatched manually), they define a
30
+ shared inputs: block. If those shared inputs use type: choice — valid for workflow_dispatch
31
+ but not workflow_call — the workflow fails schema validation with a cryptic error.
32
+
33
+ The error message does not always clearly indicate which trigger is rejecting the type,
34
+ causing developers to search for choice support across GitHub Actions documentation rather
35
+ than recognising it as a trigger-specific limitation. The same restriction applies to
36
+ type: environment.
37
+ fix: |
38
+ For inputs shared between workflow_dispatch and workflow_call, use type: string and
39
+ document the allowed values in the description field. The GitHub UI renders a free-text
40
+ field for manual dispatch instead of a dropdown, but callers still pass controlled values.
41
+
42
+ For strict input validation, add a shell step at the start of the job that fails if the
43
+ input value is not in the allowed set.
44
+
45
+ If the dropdown UI is essential for manual dispatch, create a thin dispatcher workflow
46
+ (workflow_dispatch only with type: choice) that calls the main reusable workflow passing
47
+ the validated value as a string.
48
+ fix_code:
49
+ - language: yaml
50
+ label: "Problem: type: choice breaks workflow_call validation"
51
+ code: |
52
+ on:
53
+ workflow_dispatch:
54
+ inputs:
55
+ environment:
56
+ type: choice # Valid for workflow_dispatch only
57
+ options: [dev, staging, prod]
58
+ workflow_call:
59
+ inputs:
60
+ environment:
61
+ type: choice # INVALID for workflow_call — causes validation error
62
+ - language: yaml
63
+ label: "Fix: use type: string with documented allowed values"
64
+ code: |
65
+ on:
66
+ workflow_dispatch:
67
+ inputs:
68
+ environment:
69
+ type: string
70
+ description: "Target environment. Allowed values: dev, staging, prod"
71
+ default: dev
72
+ workflow_call:
73
+ inputs:
74
+ environment:
75
+ type: string
76
+ description: "Target environment. Allowed values: dev, staging, prod"
77
+
78
+ jobs:
79
+ deploy:
80
+ runs-on: ubuntu-latest
81
+ steps:
82
+ - name: Validate environment input
83
+ run: |
84
+ case "${{ inputs.environment }}" in
85
+ dev|staging|prod) echo "Environment: ${{ inputs.environment }}" ;;
86
+ *) echo "Invalid environment: ${{ inputs.environment }}"; exit 1 ;;
87
+ esac
88
+ - language: yaml
89
+ label: "Alternative: dispatcher wrapper preserves dropdown UI for manual runs"
90
+ code: |
91
+ # dispatcher.yml — manual dispatch wrapper with choice dropdown
92
+ on:
93
+ workflow_dispatch:
94
+ inputs:
95
+ environment:
96
+ type: choice
97
+ options: [dev, staging, prod]
98
+
99
+ jobs:
100
+ dispatch:
101
+ uses: ./.github/workflows/deploy.yml # calls the reusable workflow
102
+ with:
103
+ environment: ${{ inputs.environment }} # passes as string
104
+ prevention:
105
+ - "workflow_call inputs support only: boolean, number, string — not choice or environment"
106
+ - "Use type: string with a description listing allowed values when an input is shared across both triggers"
107
+ - "Add input validation as the first job step to fail fast when an unexpected value is passed via workflow_call"
108
+ - "Run actionlint locally before pushing — it catches unsupported input types at development time"
109
+ docs:
110
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#onworkflow_callinputs"
111
+ label: "GitHub Docs: on.workflow_call.inputs syntax"
112
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#onworkflow_dispatchinputs"
113
+ label: "GitHub Docs: on.workflow_dispatch.inputs syntax"
114
+ - url: "https://rhysd.github.io/actionlint/"
115
+ label: "actionlint: static checker for GitHub Actions workflow files"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htekdev/actions-debugger",
3
- "version": "1.0.54",
3
+ "version": "1.0.56",
4
4
  "description": "65+ real GitHub Actions errors, queryable by agents. CLI + MCP server + Copilot skills + error database.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",