@htekdev/actions-debugger 1.0.11 → 1.0.12

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,137 @@
1
+ id: known-unsolved-011
2
+ title: "Matrix Job Outputs Are Non-Deterministic — Only Last Completed Job's Value Is Used"
3
+ category: known-unsolved
4
+ severity: silent-failure
5
+ tags:
6
+ - matrix
7
+ - outputs
8
+ - non-deterministic
9
+ - race-condition
10
+ - jobs-outputs
11
+ - strategy
12
+ patterns:
13
+ - regex: "jobs\\.\\w+\\.outputs\\.\\w+"
14
+ flags: "i"
15
+ - regex: "matrix.*output.*overwrite"
16
+ flags: "i"
17
+ - regex: "only.*last.*matrix.*job.*output"
18
+ flags: "i"
19
+ error_messages:
20
+ - "outputs from matrix returns only the last value"
21
+ - "matrix job output overwritten by later-completing job"
22
+ root_cause: |
23
+ GitHub Actions does not support aggregating outputs across matrix jobs. When a job uses
24
+ `strategy: matrix:` and defines `outputs:`, all matrix instances write to the SAME
25
+ output key. The value that survives is whichever matrix job completes LAST — and
26
+ completion order is non-deterministic.
27
+
28
+ Example: a 3-element matrix writing `result` as an output. Job [A, B, C] may complete
29
+ in any order — the downstream job receives only the output from whichever finished last.
30
+ This can silently produce wrong results that vary between runs.
31
+
32
+ The underlying limitation: `jobs.<job_id>.outputs` maps to a single scalar value
33
+ per key, with no way to collect values from all matrix instances into a structured
34
+ result. The runner simply last-writes-wins with no conflict detection.
35
+
36
+ This is a long-standing limitation tracked in actions/runner#1835 (opened April 2022)
37
+ and actions/runner#2477. A partial improvement in runner v2.303.0 added `$matrix`
38
+ context to outputs expressions, but it is still not generally available and has known
39
+ bugs (runner#2499: workflow won't start with the new syntax on older runners).
40
+
41
+ Source: actions/runner#1835 (Outputs from matrix returns only the last value)
42
+ Source: Stack Overflow #70287603 (Dynamic outputs for job with strategy.matrix)
43
+ fix: |
44
+ There is no native GitHub Actions solution for collecting all matrix job outputs into
45
+ a structured result. Use one of these workarounds:
46
+
47
+ Workaround 1 — Write to artifacts, aggregate downstream:
48
+ Each matrix job writes its result to a uniquely-named artifact file. A downstream
49
+ aggregator job downloads all artifacts and processes them.
50
+
51
+ Workaround 2 — Encode outputs in artifact JSON, then use as dynamic matrix:
52
+ Popularized by the `matrix-output` marketplace action. Each job appends a JSON row
53
+ to an artifact, and a reporting job downloads and merges them.
54
+
55
+ Workaround 3 — Use reusable workflows with known job indices:
56
+ Reusable workflows allow accessing specific job outputs via the caller's
57
+ `jobs.<reusable_workflow_job>.outputs` context.
58
+
59
+ Workaround 4 — Consolidate into a single non-matrix job:
60
+ If the matrix outputs must be consumed, consider restructuring to run the work
61
+ sequentially in one job or use a scripted loop.
62
+ fix_code:
63
+ - language: yaml
64
+ label: "Workaround: write output to artifact file, aggregate in downstream job"
65
+ code: |
66
+ jobs:
67
+ build:
68
+ strategy:
69
+ matrix:
70
+ component: [api, web, worker]
71
+ runs-on: ubuntu-latest
72
+ steps:
73
+ - name: Build component
74
+ run: |
75
+ # ... build logic ...
76
+ echo "build_status=success" >> result-${{ matrix.component }}.txt
77
+
78
+ - name: Upload result artifact
79
+ uses: actions/upload-artifact@v4
80
+ with:
81
+ name: result-${{ matrix.component }}
82
+ path: result-${{ matrix.component }}.txt
83
+
84
+ aggregate:
85
+ needs: build
86
+ runs-on: ubuntu-latest
87
+ steps:
88
+ - name: Download all results
89
+ uses: actions/download-artifact@v4
90
+ with:
91
+ pattern: result-*
92
+ merge-multiple: true
93
+
94
+ - name: Aggregate results
95
+ run: |
96
+ for f in result-*.txt; do
97
+ echo "=== $f ==="
98
+ cat "$f"
99
+ done
100
+
101
+ - language: yaml
102
+ label: "Anti-pattern: matrix outputs — only one value survives (last writer wins)"
103
+ code: |
104
+ # ❌ WRONG — only last-completing job's output is used by downstream-job
105
+ jobs:
106
+ build:
107
+ strategy:
108
+ matrix:
109
+ component: [api, web, worker]
110
+ runs-on: ubuntu-latest
111
+ outputs:
112
+ status: ${{ steps.build.outputs.status }} # ← non-deterministic!
113
+ steps:
114
+ - id: build
115
+ run: echo "status=done-${{ matrix.component }}" >> $GITHUB_OUTPUT
116
+
117
+ downstream-job:
118
+ needs: build
119
+ runs-on: ubuntu-latest
120
+ steps:
121
+ - run: echo "${{ needs.build.outputs.status }}"
122
+ # Prints ONE value (whichever matrix job finished last) — unpredictable
123
+
124
+ prevention:
125
+ - "Never rely on matrix job outputs for per-job values — outputs are not aggregated."
126
+ - "Use upload-artifact/download-artifact with unique names per matrix dimension to collect per-job results."
127
+ - "If a downstream job needs all matrix results, prefer artifact-based aggregation over job outputs."
128
+ - "Document in your workflow comments that matrix outputs are single-valued and non-deterministic."
129
+ docs:
130
+ - url: "https://github.com/actions/runner/issues/1835"
131
+ label: "actions/runner#1835: Outputs from matrix returns only the last value"
132
+ - url: "https://stackoverflow.com/questions/70287603/dynamic-outputs-for-job-with-strategy-matrix"
133
+ label: "Stack Overflow: Dynamic outputs for job with strategy.matrix"
134
+ - url: "https://github.com/marketplace/actions/matrix-output"
135
+ label: "Marketplace: matrix-output action (artifact-based aggregation workaround)"
136
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/passing-information-between-jobs"
137
+ label: "GitHub Docs: Passing information between jobs"
@@ -0,0 +1,134 @@
1
+ id: known-unsolved-012
2
+ title: "uses: Key Does Not Support Expressions or Context Variables — Must Be a Static String"
3
+ category: known-unsolved
4
+ severity: error
5
+ tags:
6
+ - uses
7
+ - expression
8
+ - context
9
+ - dynamic-action
10
+ - composite
11
+ - local-action
12
+ patterns:
13
+ - regex: "uses:\\s*\\.?/\\$\\{\\{"
14
+ flags: "i"
15
+ - regex: "uses:\\s*['\"]?\\$\\{\\{"
16
+ flags: "i"
17
+ - regex: "Unrecognized named-value.*uses"
18
+ flags: "i"
19
+ - regex: "Invalid workflow file.*uses.*expression"
20
+ flags: "i"
21
+ error_messages:
22
+ - "Invalid workflow file: .github/workflows/ci.yml — uses: does not support expression syntax"
23
+ - "The 'uses' field must be a literal string and cannot contain expressions"
24
+ - "Unrecognized named-value: 'env' at position 1 within expression in uses:"
25
+ root_cause: |
26
+ GitHub Actions resolves all `uses:` references (actions and reusable workflows) BEFORE
27
+ the job starts executing — at workflow evaluation / job queue time. At that point,
28
+ no runtime contexts (env, inputs, github, matrix, steps, needs) are available.
29
+
30
+ As a result, you cannot use `${{ }}` expression syntax in a `uses:` key at any level:
31
+ - Step-level: `uses: ${{ env.MY_ACTION }}@${{ env.VERSION }}` ❌
32
+ - Local path with variable: `uses: ./${{ env.DIR }}/my-action` ❌
33
+ - Dynamic version pin: `uses: actions/setup-node@${{ inputs.node-version }}` ❌
34
+ - Reusable workflow: `uses: ${{ github.repository }}/.github/workflows/ci.yml@main` ❌
35
+
36
+ This is an architectural constraint: the runner must download and validate actions
37
+ (and reusable workflows) before any step code can run. Allowing runtime expressions
38
+ would break policy enforcement (org-level allowed-actions lists) and make workflow
39
+ graphs non-deterministic at parse time.
40
+
41
+ Note: `env:` and `with:` inputs to an action DO support expressions — only the `uses:`
42
+ key itself is restricted.
43
+
44
+ Source: actions/runner#1479 (Support context/matrix variables in steps of type 'uses')
45
+ Source: actions/runner#895 (Allow expressions in uses:)
46
+ Source: Stack Overflow #75373413 (Reference a variable in uses when pointing to a path)
47
+ fix: |
48
+ There is no native GitHub Actions solution for dynamic `uses:` values.
49
+
50
+ Option 1 — Hard-code the version or path (recommended for most cases):
51
+ Pin versions explicitly in the workflow file. Use Dependabot or Renovate to keep
52
+ action versions updated automatically.
53
+
54
+ Option 2 — Use a composite action or script as a dispatcher:
55
+ Create a wrapper composite action that accepts an input and uses `if:` conditions
56
+ to call different static actions based on the input value.
57
+
58
+ Option 3 — Use step-security/dynamic-uses (third-party workaround):
59
+ The `dynamic-uses` action by step-security resolves and invokes actions dynamically
60
+ at runtime. This works around the limitation but adds a third-party dependency.
61
+
62
+ Option 4 — Restructure to not need dynamic action references:
63
+ If you're trying to select between local action paths, check out the repo first and
64
+ use a scripted approach instead of composite action dispatch.
65
+ fix_code:
66
+ - language: yaml
67
+ label: "Anti-pattern — expressions in uses: cause parse error"
68
+ code: |
69
+ # ❌ WRONG — none of these are supported
70
+ steps:
71
+ - uses: ./${{ env.ACTION_DIR }}/my-action # ← parse error
72
+ - uses: actions/setup-node@${{ inputs.version }} # ← parse error
73
+ - uses: ${{ github.repository }}/.github/workflows/deploy.yml@main # ← error
74
+
75
+ - language: yaml
76
+ label: "Fix: hard-code the version, use Dependabot to keep it updated"
77
+ code: |
78
+ # ✅ CORRECT — static string in uses:
79
+ steps:
80
+ - uses: actions/setup-node@v4 # pin to major version
81
+ - uses: actions/setup-node@11.0.0 # or exact version
82
+ - uses: ./.github/actions/my-action # local action: always relative to repo root
83
+
84
+ # Keep versions current with Dependabot (.github/dependabot.yml):
85
+ # version: 2
86
+ # updates:
87
+ # - package-ecosystem: "github-actions"
88
+ # directory: "/"
89
+ # schedule:
90
+ # interval: "weekly"
91
+
92
+ - language: yaml
93
+ label: "Workaround: if-based dispatch when choosing between known static actions"
94
+ code: |
95
+ # ✅ Conditional dispatch using if: conditions on static uses:
96
+ steps:
97
+ - name: Setup Node (version from input)
98
+ uses: actions/setup-node@v4
99
+ with:
100
+ node-version: ${{ inputs.node-version }} # ← with: supports expressions
101
+
102
+ # If you truly need different actions based on input:
103
+ - name: Use action for staging
104
+ if: inputs.environment == 'staging'
105
+ uses: ./actions/deploy-staging # static path
106
+
107
+ - name: Use action for production
108
+ if: inputs.environment == 'production'
109
+ uses: ./actions/deploy-production # static path
110
+
111
+ - language: yaml
112
+ label: "Workaround: step-security/dynamic-uses third-party action"
113
+ code: |
114
+ # Third-party workaround — resolves expressions in uses: at runtime
115
+ steps:
116
+ - uses: step-security/dynamic-uses@v1
117
+ with:
118
+ uses: actions/setup-node@${{ inputs.node-version }}
119
+ with: '{ "node-version": 18 }'
120
+
121
+ prevention:
122
+ - "Always use static literal strings in `uses:` keys — no `${{ }}` expressions."
123
+ - "Use `with:` inputs (which DO support expressions) to pass dynamic values to actions."
124
+ - "Use Dependabot or Renovate to automate action version bumps so manual pinning stays current."
125
+ - "For environment-specific action selection, use `if:` conditions on separate steps with static `uses:` values."
126
+ docs:
127
+ - url: "https://github.com/actions/runner/issues/1479"
128
+ label: "actions/runner#1479: Support context/matrix variables in steps of type 'uses'"
129
+ - url: "https://github.com/actions/runner/issues/895"
130
+ label: "actions/runner#895: Allow expressions in uses: key"
131
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/using-pre-written-building-blocks-in-your-workflow"
132
+ label: "GitHub Docs: Using pre-written building blocks (actions)"
133
+ - url: "https://github.com/step-security/dynamic-uses"
134
+ label: "step-security/dynamic-uses: third-party workaround for dynamic uses:"
@@ -0,0 +1,137 @@
1
+ id: runner-environment-033
2
+ title: "Windows Runner Default Shell Is PowerShell — Bash Scripts Silently Fail Without shell: bash"
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - windows
7
+ - shell
8
+ - bash
9
+ - powershell
10
+ - default-shell
11
+ - run-step
12
+ - cross-platform
13
+ patterns:
14
+ - regex: "shell:\\s*C:\\\\Windows\\\\system32\\\\bash\\.EXE"
15
+ flags: "i"
16
+ - regex: "The term '.*' is not recognized.*cmdlet.*function.*script"
17
+ flags: "i"
18
+ - regex: "pwsh.*noprofile.*noninteractive.*command"
19
+ flags: "i"
20
+ - regex: "bash.*error.*not.*recognized.*windows"
21
+ flags: "i"
22
+ error_messages:
23
+ - "The term 'set' is not recognized as the name of a cmdlet, function, script file"
24
+ - "Unrecognized token '||' in pipeline"
25
+ - "shell: C:\\Windows\\system32\\bash.EXE --noprofile --norc -e -o pipefail {0}: No such file or directory"
26
+ - "export: The term 'export' is not recognized as the name of a cmdlet"
27
+ root_cause: |
28
+ GitHub Actions uses a different default shell depending on the runner OS:
29
+ - Linux (ubuntu-*): bash
30
+ - macOS (macos-*): bash
31
+ - Windows (windows-*): PowerShell (pwsh)
32
+
33
+ When you write `run:` steps using bash syntax (e.g., `export VAR=value`, `set -e`,
34
+ `||`, `&&`, heredocs, `$(...)` subshells) without explicitly specifying `shell: bash`,
35
+ those steps will execute under PowerShell on Windows runners and fail with confusing
36
+ errors.
37
+
38
+ This is especially problematic in:
39
+ - Matrix workflows that include both Linux and Windows OS variants
40
+ - Composite actions where the shell is not explicitly set per step
41
+ - Reusable workflows called from both Linux and Windows jobs
42
+ - Migration from Linux-only workflows to cross-platform
43
+
44
+ A secondary issue: on Windows runners, if `C:\Windows\System32\bash.exe` exists
45
+ (WSL stub), specifying `shell: bash` may invoke the WSL stub instead of Git Bash
46
+ (`C:\Program Files\Git\bin\bash.EXE`). This causes "No such file or directory"
47
+ errors because the WSL stub requires a Linux distribution to be installed.
48
+ Since runner-images#12646, this is a known issue with no GitHub-side fix.
49
+
50
+ Source: actions/runner#1328 (Unable to run bash scripts on Windows runner)
51
+ Source: runner-images#12646 (Windows WSL bash.exe stub causes shell: bash failures)
52
+ fix: |
53
+ Always explicitly set `shell: bash` on any `run:` step that uses bash syntax.
54
+
55
+ For cross-platform matrix workflows, there are three approaches:
56
+
57
+ 1. Explicit shell per step — add `shell: bash` to every bash step.
58
+
59
+ 2. Workflow-level default — set `defaults.run.shell: bash` to apply bash to ALL
60
+ run steps in the workflow (be consistent — all steps must then use bash syntax).
61
+
62
+ 3. Job-level default — set `defaults.run.shell: bash` at the job level to scope it.
63
+
64
+ If you need PowerShell on Windows AND bash on Linux in the same matrix, use a
65
+ matrix-aware condition to selectively set the shell, or split into separate jobs.
66
+ fix_code:
67
+ - language: yaml
68
+ label: "Fix: explicit shell: bash on individual steps"
69
+ code: |
70
+ jobs:
71
+ test:
72
+ strategy:
73
+ matrix:
74
+ os: [ubuntu-latest, windows-latest, macos-latest]
75
+ runs-on: ${{ matrix.os }}
76
+ steps:
77
+ - uses: actions/checkout@v4
78
+
79
+ # ✅ Always specify shell: bash for bash scripts
80
+ - name: Run build script
81
+ shell: bash # required on Windows — default is PowerShell
82
+ run: |
83
+ export BUILD_ENV=production
84
+ set -euo pipefail
85
+ ./scripts/build.sh
86
+
87
+ - language: yaml
88
+ label: "Fix: workflow-level default shell (applies to all run steps)"
89
+ code: |
90
+ name: Cross-Platform CI
91
+
92
+ defaults:
93
+ run:
94
+ shell: bash # override default — all run steps use bash on all OS
95
+
96
+ jobs:
97
+ test:
98
+ strategy:
99
+ matrix:
100
+ os: [ubuntu-latest, windows-latest, macos-latest]
101
+ runs-on: ${{ matrix.os }}
102
+ steps:
103
+ - uses: actions/checkout@v4
104
+ - name: Run tests
105
+ run: |
106
+ # This runs in bash on all platforms
107
+ ./scripts/run-tests.sh
108
+
109
+ - language: yaml
110
+ label: "Anti-pattern: bash syntax without shell: bash on Windows fails"
111
+ code: |
112
+ # ❌ WRONG on Windows — default shell is PowerShell, bash syntax breaks
113
+ jobs:
114
+ build:
115
+ runs-on: windows-latest
116
+ steps:
117
+ - name: Set env
118
+ run: |
119
+ export DEPLOY_ENV=production # ← ERROR: 'export' not recognized
120
+ echo "env: $DEPLOY_ENV" # ← ERROR: bash variable expansion
121
+ ls -la # ← ERROR: ls -la not valid in pwsh
122
+
123
+ prevention:
124
+ - "Always specify `shell: bash` (or `shell: pwsh`) explicitly on every `run:` step in cross-platform workflows."
125
+ - "Use `defaults.run.shell: bash` at the workflow or job level to reduce repetition."
126
+ - "Test all matrix OS variants in CI — don't assume Linux behavior translates to Windows."
127
+ - "For PowerShell-specific steps on Windows, use `shell: pwsh` explicitly rather than relying on the default."
128
+ - "Avoid relying on the runner's WSL bash stub on Windows — it requires a WSL distribution installed."
129
+ docs:
130
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/setting-a-default-shell-and-working-directory"
131
+ label: "GitHub Docs: Setting a default shell and working directory"
132
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell"
133
+ label: "GitHub Docs: jobs.<job_id>.steps[*].shell"
134
+ - url: "https://github.com/actions/runner/issues/1328"
135
+ label: "actions/runner#1328: Unable to run bash scripts on Windows runner"
136
+ - url: "https://github.com/actions/runner-images/issues/12646"
137
+ label: "runner-images#12646: Windows WSL bash.exe stub causes shell: bash failures"
@@ -0,0 +1,134 @@
1
+ id: silent-failures-014
2
+ title: "pull_request github.ref Is refs/pull/N/merge — Branch-Name Conditions Silently Evaluate to False"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - pull_request
7
+ - github-ref
8
+ - merge-ref
9
+ - branch-name
10
+ - if-condition
11
+ - head-ref
12
+ - base-ref
13
+ patterns:
14
+ - regex: "github\\.ref\\s*==\\s*['\"]refs/heads/"
15
+ flags: "i"
16
+ - regex: "GITHUB_REF.*refs/pull/\\d+/merge"
17
+ flags: "i"
18
+ - regex: "github\\.ref.*startsWith.*refs/heads"
19
+ flags: "i"
20
+ error_messages:
21
+ - "refs/pull/123/merge"
22
+ - "Conditional check 'github.ref == refs/heads/main' evaluated to false on pull_request event"
23
+ - "GITHUB_REF=refs/pull/47/merge"
24
+ root_cause: |
25
+ When a workflow is triggered by the `pull_request` (or `pull_request_target`) event,
26
+ `github.ref` is set to `refs/pull/<number>/merge` — NOT the source branch name.
27
+
28
+ This `refs/pull/<N>/merge` is a synthetic Git reference created by GitHub representing
29
+ the prospective merge commit (the merge of the PR's head branch into the base branch).
30
+ It does not correspond to any named branch.
31
+
32
+ Developers commonly write conditions expecting `github.ref` to contain the branch name:
33
+ - `if: github.ref == 'refs/heads/feature-branch'` → always false on PR events
34
+ - `if: startsWith(github.ref, 'refs/heads/')` → always false on PR events
35
+ - `if: github.ref != 'refs/heads/main'` → always true on PR events
36
+
37
+ These conditions silently pass or silently skip — no error is reported. The job
38
+ simply runs (or doesn't run) with no indication that the ref check was wrong.
39
+
40
+ The correct context variables for PR events are:
41
+ - `github.head_ref` — the source branch name (e.g., "feature/my-branch")
42
+ - `github.base_ref` — the target branch name (e.g., "main")
43
+ - `github.event.pull_request.head.ref` — same as head_ref
44
+ - `github.event.pull_request.base.ref` — same as base_ref
45
+
46
+ Note: `github.head_ref` and `github.base_ref` are ONLY set for pull_request events.
47
+ For push events, use `github.ref_name` instead.
48
+
49
+ Source: Stack Overflow #68708792 (what is github.ref when merging PR to master)
50
+ Source: Stack Overflow #78162051 (obtain branch name in github action on pull_request)
51
+ Docs: https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#github-context
52
+ fix: |
53
+ Use the correct context variable depending on what information you need:
54
+
55
+ For the PR source branch:
56
+ Use `github.head_ref` (not `github.ref`)
57
+
58
+ For the PR target branch:
59
+ Use `github.base_ref` (not `github.ref`)
60
+
61
+ For branch-scoped conditions that need to work across BOTH push and pull_request:
62
+ Use `github.ref_name` (gives branch/tag name without refs/heads/ prefix)
63
+ Or use `github.event_name` to gate the condition by event type
64
+
65
+ To check if a push or PR targets the main branch:
66
+ - Push: `github.ref == 'refs/heads/main'`
67
+ - PR: `github.base_ref == 'main'`
68
+ - Both: use separate conditions gated by `github.event_name`
69
+ fix_code:
70
+ - language: yaml
71
+ label: "Fix: use github.head_ref for PR source branch, base_ref for target"
72
+ code: |
73
+ jobs:
74
+ deploy:
75
+ runs-on: ubuntu-latest
76
+ steps:
77
+ # ❌ WRONG: github.ref on pull_request is refs/pull/N/merge — never matches heads/*
78
+ - name: Wrong branch check
79
+ if: github.ref == 'refs/heads/feature-branch' # always false on PR!
80
+ run: echo "this never runs on PR events"
81
+
82
+ # ✅ CORRECT: use head_ref for the source branch name
83
+ - name: Correct branch check
84
+ if: github.head_ref == 'feature-branch'
85
+ run: echo "this runs when PR source branch is feature-branch"
86
+
87
+ # ✅ CORRECT: use base_ref for the target branch name
88
+ - name: Check if targeting main
89
+ if: github.base_ref == 'main'
90
+ run: echo "this PR is targeting main"
91
+
92
+ - language: yaml
93
+ label: "Cross-event condition: works for both push and pull_request"
94
+ code: |
95
+ jobs:
96
+ conditional:
97
+ runs-on: ubuntu-latest
98
+ steps:
99
+ # Works for both push (github.ref_name) and PR (github.base_ref)
100
+ - name: Is this targeting/on main?
101
+ if: |
102
+ (github.event_name == 'push' && github.ref == 'refs/heads/main') ||
103
+ (github.event_name == 'pull_request' && github.base_ref == 'main')
104
+ run: echo "targeting or on main branch"
105
+
106
+ # Simpler: github.ref_name works for push; for PR it returns the merge ref number
107
+ # Best to keep push and pull_request logic separate with event_name guards
108
+
109
+ - language: yaml
110
+ label: "Debug step: print all relevant refs for troubleshooting"
111
+ code: |
112
+ - name: Debug refs
113
+ run: |
114
+ echo "event_name: ${{ github.event_name }}"
115
+ echo "ref: ${{ github.ref }}"
116
+ echo "ref_name: ${{ github.ref_name }}"
117
+ echo "head_ref: ${{ github.head_ref }}"
118
+ echo "base_ref: ${{ github.base_ref }}"
119
+ # On push/branch: ref=refs/heads/main, head_ref='', base_ref=''
120
+ # On pull_request: ref=refs/pull/47/merge, head_ref=feature-x, base_ref=main
121
+
122
+ prevention:
123
+ - "Never use `github.ref` to get the branch name in `pull_request` triggered workflows — it is not a branch ref."
124
+ - "Use `github.head_ref` for the PR source branch and `github.base_ref` for the target branch."
125
+ - "For conditions that span both push and pull_request events, gate on `github.event_name` first."
126
+ - "Add a debug step printing `github.ref`, `github.head_ref`, and `github.base_ref` when debugging trigger conditions."
127
+ - "Use `github.ref_name` (branch/tag name without prefix) for push events instead of stripping `refs/heads/` manually."
128
+ docs:
129
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#github-context"
130
+ label: "GitHub Docs: github context (ref, head_ref, base_ref, ref_name)"
131
+ - url: "https://stackoverflow.com/questions/68708792/what-is-github-ref-when-merging-pr-to-master"
132
+ label: "Stack Overflow: What is github.ref when merging PR to master?"
133
+ - url: "https://stackoverflow.com/questions/78162051/obtain-branch-name-in-github-action-on-pull-request"
134
+ label: "Stack Overflow: Obtain branch name in github action on pull request"
@@ -0,0 +1,123 @@
1
+ id: triggers-012
2
+ title: "Tag Pushes Bypass paths: Filter — Workflow Fires on Every Tag Regardless of Changed Files"
3
+ category: triggers
4
+ severity: silent-failure
5
+ tags:
6
+ - push
7
+ - tags
8
+ - paths-filter
9
+ - tag-push
10
+ - trigger
11
+ - branches
12
+ patterns:
13
+ - regex: "on:\\s*\\n\\s*push:\\s*\\n\\s*(\\w[^\\n]*\\n\\s*)*paths:"
14
+ flags: "im"
15
+ - regex: "Triggered by refs/tags/"
16
+ flags: "i"
17
+ - regex: "push.*paths.*tags.*ignored"
18
+ flags: "i"
19
+ error_messages:
20
+ - "Run triggered by push to refs/tags/v1.0.0"
21
+ - "Evaluation skipped: tag push does not evaluate path filters"
22
+ root_cause: |
23
+ GitHub Actions evaluates `paths:` and `paths-ignore:` filters ONLY for branch pushes.
24
+ When a tag is pushed, path filters are completely bypassed — the workflow runs regardless
25
+ of which files were changed.
26
+
27
+ This means a workflow like:
28
+
29
+ on:
30
+ push:
31
+ paths:
32
+ - "src/**"
33
+
34
+ will fire on every tag push (e.g., `git push origin v1.2.3`) even if no files under
35
+ `src/` were modified in the tagged commit.
36
+
37
+ Additionally, if a workflow has `on: push:` with NO branches/tags filter, a tag push
38
+ produces a `push` webhook event that triggers the workflow. Developers expect tag pushes
39
+ to be governed by path filters, but the docs explicitly state path filters are not
40
+ evaluated for tag events.
41
+
42
+ Source: actions/runner#3933 (path filters not respected for tag pushes)
43
+ Source: Stack Overflow #76037078 (paths also triggered when pushing a new tag)
44
+ Docs: https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/triggering-a-workflow#using-filters-to-target-specific-paths-for-pull-request-or-push-events
45
+ fix: |
46
+ If you want path-filtered push workflows to run ONLY on branch pushes (not tag pushes),
47
+ explicitly add a `tags-ignore: ["**"]` filter or restrict to branches explicitly.
48
+
49
+ Option A — Add `tags-ignore` to suppress all tag events:
50
+ on:
51
+ push:
52
+ paths:
53
+ - "src/**"
54
+ tags-ignore:
55
+ - "**"
56
+
57
+ Option B — Add an explicit `branches` filter (only branch pushes match):
58
+ on:
59
+ push:
60
+ branches:
61
+ - "**" # all branches
62
+ paths:
63
+ - "src/**"
64
+
65
+ Note: Option B is equivalent — defining `branches` or `tags` implicitly excludes the
66
+ other git ref type from triggering the workflow.
67
+ fix_code:
68
+ - language: yaml
69
+ label: "Add tags-ignore to prevent tag pushes from bypassing path filters"
70
+ code: |
71
+ on:
72
+ push:
73
+ # Path filter only works for branch pushes — add tags-ignore to prevent
74
+ # tag pushes from triggering this workflow unconditionally.
75
+ tags-ignore:
76
+ - "**"
77
+ paths:
78
+ - "src/**"
79
+ - "lib/**"
80
+
81
+ - language: yaml
82
+ label: "Restrict to all branches (implicitly excludes tags)"
83
+ code: |
84
+ on:
85
+ push:
86
+ branches:
87
+ - "**" # matches all branch pushes, ignores tag pushes
88
+ paths:
89
+ - "src/**"
90
+
91
+ - language: yaml
92
+ label: "Separate workflows for branch CI vs tag release"
93
+ code: |
94
+ # ci.yml — triggered by branch pushes with path filtering
95
+ on:
96
+ push:
97
+ branches:
98
+ - main
99
+ - "feature/**"
100
+ paths:
101
+ - "src/**"
102
+
103
+ ---
104
+ # release.yml — triggered by version tags
105
+ on:
106
+ push:
107
+ tags:
108
+ - "v*.*.*"
109
+
110
+ prevention:
111
+ - "Never rely on `paths:` filters to suppress tag-push triggers — they are not evaluated for tags."
112
+ - "Always add an explicit `branches:` or `tags-ignore: [\"**\"]` when your workflow is path-filtered and meant only for code changes."
113
+ - "Keep branch-CI workflows and release/tag workflows in separate files to avoid trigger ambiguity."
114
+ - "Test your trigger logic with `act` locally — push a tag and verify the workflow does not fire unexpectedly."
115
+ docs:
116
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/triggering-a-workflow#using-filters-to-target-specific-paths-for-pull-request-or-push-events"
117
+ label: "GitHub Docs: Using filters to target specific paths"
118
+ - url: "https://github.com/actions/runner/issues/3933"
119
+ label: "actions/runner#3933: Path filters not respected for tag pushes"
120
+ - url: "https://stackoverflow.com/questions/76037078/why-is-my-github-action-on-paths-also-triggered-when-pushing-a-new-tag"
121
+ label: "Stack Overflow: Why is paths: also triggered when pushing a new tag?"
122
+ - url: "https://stackoverflow.com/questions/70743715/how-do-i-configure-a-github-actions-workflow-so-it-does-not-run-on-a-tag-push"
123
+ label: "Stack Overflow: How to prevent workflow from running on tag push"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htekdev/actions-debugger",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "description": "65+ real GitHub Actions errors, queryable by agents. MCP server + Copilot skills + error database.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",