@htekdev/actions-debugger 1.0.78 → 1.0.79

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,80 @@
1
+ id: caching-artifacts-045
2
+ title: "Merge queue (merge_group) runs cannot restore cache saved by pull_request runs"
3
+ category: caching-artifacts
4
+ severity: silent-failure
5
+ tags:
6
+ - merge-queue
7
+ - merge_group
8
+ - cache-isolation
9
+ - branch-scoping
10
+ - cache-miss
11
+ patterns:
12
+ - regex: 'Cache not found for input keys'
13
+ flags: i
14
+ - regex: 'gh-readonly-queue'
15
+ flags: i
16
+ error_messages:
17
+ - "Cache not found for input keys:"
18
+ - "No cache found for key: Linux-node-"
19
+ root_cause: |
20
+ GitHub Actions caches are branch-scoped. When the merge_group trigger fires,
21
+ GitHub creates a temporary branch named
22
+ gh-readonly-queue/main/pr-<number>-<sha> with a fresh merge commit. This
23
+ temporary branch has no prior cache entries, so every cache lookup is a cache
24
+ miss — even if the identical hashFiles() key was successfully saved during the
25
+ preceding pull_request run on the feature branch.
26
+
27
+ Branch-scoped cache fallback rules allow access to the base branch (e.g., main)
28
+ but NOT to arbitrary feature branches. The gh-readonly-queue/* branch is treated
29
+ as a new branch with no cache history and no access to feature-branch caches.
30
+ Only caches saved directly to main (or the configured merge target) are accessible
31
+ in merge queue runs.
32
+
33
+ The result: CI times effectively double. The pull_request run warms the cache
34
+ but the merge queue run cannot use it and must rebuild from scratch.
35
+ fix: |
36
+ Seed caches on the base branch via push-triggered or scheduled workflows so
37
+ merge queue runs can restore from main's cache. Use restore-keys with a
38
+ branch-agnostic prefix to maximize fallback hit rate.
39
+ fix_code:
40
+ - language: yaml
41
+ label: "Use restore-keys for base branch fallback"
42
+ code: |
43
+ - name: Cache dependencies
44
+ uses: actions/cache@v4
45
+ with:
46
+ path: ~/.npm
47
+ # Exact key includes lock file hash — works for push/PR
48
+ key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
49
+ # restore-keys fall back to base branch cache (accessible in merge_group)
50
+ restore-keys: |
51
+ ${{ runner.os }}-node-
52
+
53
+ - language: yaml
54
+ label: "Seed base branch cache via push workflow"
55
+ code: |
56
+ # Separate workflow to warm cache on main after every merge
57
+ on:
58
+ push:
59
+ branches: [main]
60
+
61
+ jobs:
62
+ warm-cache:
63
+ runs-on: ubuntu-latest
64
+ steps:
65
+ - uses: actions/checkout@v4
66
+ - uses: actions/setup-node@v4
67
+ with:
68
+ node-version: '20'
69
+ cache: npm
70
+ - run: npm ci
71
+ prevention:
72
+ - "Seed caches on your base branch (main) so merge queue runs can restore from it."
73
+ - "Use branch-agnostic restore-keys prefixes — they survive the gh-readonly-queue/* branch context."
74
+ - "Avoid cache keys that include branch name or github.head_ref — they will never match in merge queue."
75
+ - "setup-node/setup-python cache: integration automatically includes restore-keys and handles this gracefully."
76
+ docs:
77
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#merge_group"
78
+ label: "GitHub Actions: merge_group trigger"
79
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows#restrictions-for-accessing-a-cache"
80
+ label: "GitHub Actions: Cache branch access restrictions"
@@ -0,0 +1,67 @@
1
+ id: concurrency-timing-039
2
+ title: "Manual re-run cancels original run when concurrency group omits github.run_attempt"
3
+ category: concurrency-timing
4
+ severity: error
5
+ tags:
6
+ - concurrency
7
+ - re-run
8
+ - cancel-in-progress
9
+ - run-attempt
10
+ - manual-rerun
11
+ patterns:
12
+ - regex: 'This run was cancelled'
13
+ flags: i
14
+ - regex: 'run_attempt'
15
+ flags: i
16
+ error_messages:
17
+ - "This run was cancelled."
18
+ - "A run for this workflow is already in progress."
19
+ root_cause: |
20
+ When cancel-in-progress: true is set and the concurrency group key does not
21
+ include github.run_attempt, every manual re-run of a workflow is treated as a
22
+ duplicate of the original run (since run_id and ref are the same). The re-run
23
+ immediately cancels the still-executing original attempt, or the concurrency
24
+ group queues the re-run and cancels any pending run — which may be the active
25
+ original.
26
+
27
+ The run_id is stable across re-runs but run_attempt increments (1, 2, 3...).
28
+ Without run_attempt in the concurrency group key, GitHub has no way to
29
+ distinguish re-run attempt 2 from the still-running attempt 1.
30
+
31
+ This produces confusing CI failures: a developer clicks "Re-run jobs" on a
32
+ failed workflow and immediately sees the original (or the re-run itself)
33
+ cancelled by the concurrency system.
34
+ fix: |
35
+ Include github.run_attempt in the concurrency group key so each attempt is
36
+ treated as a distinct slot. This allows re-runs to coexist with or cleanly
37
+ supersede the original without unexpected cancellations.
38
+ fix_code:
39
+ - language: yaml
40
+ label: "Include run_attempt in concurrency group key"
41
+ code: |
42
+ # WRONG: re-runs and originals share the same concurrency slot
43
+ # concurrency:
44
+ # group: ${{ github.workflow }}-${{ github.ref }}
45
+ # cancel-in-progress: true
46
+
47
+ # CORRECT: each attempt gets its own slot, preventing cross-attempt cancellation
48
+ concurrency:
49
+ group: ${{ github.workflow }}-${{ github.ref }}-${{ github.run_attempt }}
50
+ cancel-in-progress: true
51
+
52
+ - language: yaml
53
+ label: "Alternative: cancel-in-progress only for push/PR, not re-runs"
54
+ code: |
55
+ concurrency:
56
+ group: ${{ github.workflow }}-${{ github.ref }}
57
+ # Only cancel-in-progress for first attempt; re-runs are never cancelled
58
+ cancel-in-progress: ${{ github.run_attempt == 1 }}
59
+ prevention:
60
+ - "Always include github.run_attempt in concurrency group keys when cancel-in-progress: true is set."
61
+ - "Test re-run behavior explicitly — concurrency cancellation bugs only surface when you manually re-run."
62
+ - "Consider using cancel-in-progress: ${{ github.run_attempt == 1 }} to preserve re-run integrity."
63
+ docs:
64
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#concurrency"
65
+ label: "GitHub Actions: Concurrency syntax"
66
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#github-context"
67
+ label: "GitHub Actions: github.run_attempt context"
@@ -0,0 +1,77 @@
1
+ id: silent-failures-074
2
+ title: "fromJSON() object or array stored in env: block silently becomes '[object Object]'"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - fromjson
7
+ - env-context
8
+ - type-coercion
9
+ - json-parsing
10
+ - stringification
11
+ patterns:
12
+ - regex: 'env\s*:.*\$\{\{\s*fromJSON\('
13
+ flags: ims
14
+ error_messages:
15
+ - "[object Object]"
16
+ - "Unexpected token 'o', \"[object O\"... is not valid JSON"
17
+ root_cause: |
18
+ The fromJSON() function in GitHub Actions expressions parses a JSON string
19
+ into a typed value — object, array, boolean, or number. However, when the
20
+ result is assigned to an env: variable, the Actions runner coerces the value
21
+ to a string using JavaScript's default toString(). For objects this produces
22
+ the literal string [object Object]; for arrays it produces a comma-joined
23
+ string (e.g., a,b,c).
24
+
25
+ The step exits with code 0 and the env variable appears set, but its value is
26
+ the stringified form rather than the JSON structure the developer expected.
27
+ Subsequent steps that reference ${{ env.CONFIG }} or echo the variable and
28
+ pipe it through jq will receive [object Object] and fail to parse — or silently
29
+ produce wrong results.
30
+
31
+ Booleans and numbers survive correctly: fromJSON('true') in env: produces the
32
+ string 'true', and fromJSON('42') produces '42' — these are the only safe uses.
33
+ fix: |
34
+ Pass structured JSON data between steps via GITHUB_OUTPUT (as a raw JSON
35
+ string), then consume the stored string with fromJSON() in downstream
36
+ expression contexts. Never store objects or arrays via fromJSON() in env: blocks.
37
+ fix_code:
38
+ - language: yaml
39
+ label: "Store JSON in GITHUB_OUTPUT, consume via fromJSON in expressions"
40
+ code: |
41
+ jobs:
42
+ build:
43
+ runs-on: ubuntu-latest
44
+ steps:
45
+ # WRONG: fromJSON object in env: becomes '[object Object]'
46
+ # - name: Bad config
47
+ # env:
48
+ # CONFIG: ${{ fromJSON(inputs.config_json) }}
49
+ # run: echo "$CONFIG" | jq .host # fails: '[object Object]' is not JSON
50
+
51
+ # CORRECT: store raw JSON string in GITHUB_OUTPUT
52
+ - name: Store config
53
+ id: cfg
54
+ run: echo 'config=${{ inputs.config_json }}' >> $GITHUB_OUTPUT
55
+
56
+ # Access fields with fromJSON() directly in expression context
57
+ - name: Use config
58
+ run: |
59
+ echo "Host: ${{ fromJSON(steps.cfg.outputs.config).host }}"
60
+ echo "Port: ${{ fromJSON(steps.cfg.outputs.config).port }}"
61
+
62
+ # Scalar fromJSON values are safe in env: (boolean, number)
63
+ - name: Scalar fromJSON is fine
64
+ env:
65
+ IS_PROD: ${{ fromJSON(inputs.is_prod) }}
66
+ TIMEOUT: ${{ fromJSON(inputs.timeout) }}
67
+ run: echo "prod=$IS_PROD timeout=$TIMEOUT"
68
+ prevention:
69
+ - "Never assign fromJSON() results that produce objects or arrays to env: variables."
70
+ - "Use fromJSON() inline in expression contexts (${{ fromJSON(x).field }}) rather than materializing into env vars."
71
+ - "Store JSON blobs as raw strings in GITHUB_OUTPUT and parse with jq in shell or fromJSON() in expressions."
72
+ - "For object env vars, keep the value as a raw JSON string and parse in shell with jq or python -c."
73
+ docs:
74
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#fromjson"
75
+ label: "GitHub Actions: fromJSON expression function"
76
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/passing-information-between-jobs"
77
+ label: "GitHub Actions: Passing information between jobs"
@@ -0,0 +1,89 @@
1
+ id: triggers-053
2
+ title: "Unknown or misspelled values in on.<event>.types[] are silently ignored — workflow never triggers"
3
+ category: triggers
4
+ severity: silent-failure
5
+ tags:
6
+ - types-filter
7
+ - trigger
8
+ - typo
9
+ - pull-request
10
+ - silent-failure
11
+ patterns:
12
+ - regex: 'types\s*:\s*\[.*(?:syncronize|synchronised|synchronize d|re-opened|labeld|assign)\]'
13
+ flags: i
14
+ - regex: 'types\s*:\s*\n(?:\s+-\s+\w+\n)*\s+-\s+(?!opened|closed|reopened|synchronize|labeled|unlabeled|assigned|unassigned|review_requested|ready_for_review|converted_to_draft|locked|unlocked|milestoned|demilestoned|edited)\w'
15
+ flags: im
16
+ error_messages:
17
+ - "Workflow is not triggered"
18
+ - "No runs found"
19
+ root_cause: |
20
+ GitHub Actions silently discards unrecognized values in the types: filter
21
+ array for pull_request, pull_request_target, and other typed events. There is
22
+ no validation error, no schema warning, and no run log entry — the workflow
23
+ simply never fires for the intended activity type.
24
+
25
+ The most common cause is a typo in a well-known type name:
26
+ - syncronize (correct: synchronize)
27
+ - re-opened (correct: reopened)
28
+ - labeld (correct: labeled)
29
+ - closed (correct: closed — note: not 'merged')
30
+
31
+ A second common cause is listing only the new type while forgetting that the
32
+ default types are no longer active. For example, types: [synchronize] drops
33
+ the implicit opened and reopened behaviors, so a newly opened PR will not
34
+ trigger CI at all.
35
+
36
+ actionlint >=0.7.0 can detect unknown type values but is not always used in
37
+ local development workflows.
38
+ fix: |
39
+ Verify all type values against the official list for each event. Include all
40
+ intended types explicitly — once types: is specified, the defaults no longer
41
+ apply.
42
+ fix_code:
43
+ - language: yaml
44
+ label: "Correct types for pull_request CI — always include all intended types"
45
+ code: |
46
+ on:
47
+ pull_request:
48
+ # WRONG examples (silently never trigger):
49
+ # types: [opened, syncronize, re-opened] # typos
50
+ # types: [synchronize] # drops opened/reopened
51
+
52
+ # CORRECT: include all intended activity types
53
+ types:
54
+ - opened
55
+ - synchronize
56
+ - reopened
57
+
58
+ - language: yaml
59
+ label: "All valid pull_request types for reference"
60
+ code: |
61
+ on:
62
+ pull_request:
63
+ types:
64
+ # Commonly needed for CI:
65
+ - opened # new PR created
66
+ - synchronize # new commit pushed to PR branch
67
+ - reopened # closed PR re-opened
68
+ # Useful for label-gated workflows:
69
+ - labeled
70
+ - unlabeled
71
+ # Draft/review flow:
72
+ - ready_for_review
73
+ - converted_to_draft
74
+ # Assignment:
75
+ - assigned
76
+ - unassigned
77
+ - review_requested
78
+ prevention:
79
+ - "Run actionlint (>=0.7.0) in CI to detect unknown type values — it reports them as errors."
80
+ - "When adding types:, explicitly list ALL types you need — defaults no longer apply once types: is present."
81
+ - "After changing types:, trigger one manual test run per type to confirm the filter is working."
82
+ - "Use the GitHub Actions VS Code extension — it underlines unknown type values as warnings."
83
+ docs:
84
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request"
85
+ label: "GitHub Actions: pull_request event types"
86
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request_target"
87
+ label: "GitHub Actions: pull_request_target event types"
88
+ - url: "https://rhysd.github.io/actionlint/"
89
+ label: "actionlint: GitHub Actions linter"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htekdev/actions-debugger",
3
- "version": "1.0.78",
3
+ "version": "1.0.79",
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",