@htekdev/actions-debugger 1.0.73 → 1.0.74

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,127 @@
1
+ id: caching-artifacts-044
2
+ title: 'actions/cache post step skipped when job fails — cache not saved on failure (post-if: success() default)'
3
+ category: caching-artifacts
4
+ severity: silent-failure
5
+ tags:
6
+ - actions-cache
7
+ - cache-save
8
+ - job-failure
9
+ - post-if
10
+ - save-always
11
+ - silent-skip
12
+ patterns:
13
+ - regex: 'Post\s+Run\s+actions/cache'
14
+ flags: 'i'
15
+ - regex: 'save-always'
16
+ flags: 'i'
17
+ - regex: 'Cache\s+not\s+found'
18
+ flags: 'i'
19
+ error_messages:
20
+ - "Cache was not saved. Exiting with failure."
21
+ - "Post Run actions/cache@v4 skipped"
22
+ - "Cache miss on subsequent run after failed job"
23
+ - "cache-hit: false even though previous run had cache action"
24
+ root_cause: |
25
+ actions/cache (v3 and v4) uses a `post-if: success()` condition on the cache save post step
26
+ by default. This means the cache save step only runs when ALL preceding steps in the job
27
+ succeeded. When any step fails:
28
+ - The job transitions to "failure" state
29
+ - The cache post step is SKIPPED silently — no warning, annotation, or error is logged
30
+ - The next run gets a cache miss and must re-download/rebuild from scratch
31
+
32
+ This is commonly discovered when:
33
+ - A test suite installs dependencies (cached) then runs tests (which fail)
34
+ - The cache works on the first run but never again after a flaky failure
35
+ - A build step fails, wasting all compilation work that could have been cached
36
+ - CI is slow because each failed run discards the cache and rebuilds from zero
37
+
38
+ Note: This is DIFFERENT from caching-artifacts-036 which covers the case where the job
39
+ is CANCELLED (via concurrency cancel-in-progress). Cancellation also skips the post step,
40
+ but for a different reason — cancellation interrupts all runners immediately.
41
+
42
+ The failure case is separate: the job runs to completion (with a failure), the post step
43
+ lifecycle still runs, but the post-if condition evaluates to false and skips it silently.
44
+ fix: |
45
+ Option 1 (recommended): Set `save-always: true` on the restore step (actions/cache v3.3.3+ and v4+):
46
+ - uses: actions/cache@v4
47
+ with:
48
+ path: ~/.npm
49
+ key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
50
+ save-always: true # Save cache even if job fails
51
+
52
+ Option 2: Use the standalone cache/save action in an explicit cleanup step:
53
+ - uses: actions/cache/restore@v4
54
+ id: cache-restore
55
+ with:
56
+ path: ~/.npm
57
+ key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
58
+ - run: npm ci
59
+ - uses: actions/cache/save@v4
60
+ if: always() # Explicit save even on failure
61
+ with:
62
+ path: ~/.npm
63
+ key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
64
+
65
+ Option 3 (v3 only): Use `cache-v3-save-always-unexpected-input` — note that `save-always`
66
+ was not available before v3.3.3. On older versions, use the split restore/save approach.
67
+ fix_code:
68
+ - language: yaml
69
+ label: 'Save cache on job failure using save-always: true (v4)'
70
+ code: |
71
+ jobs:
72
+ build:
73
+ runs-on: ubuntu-latest
74
+ steps:
75
+ - uses: actions/checkout@v4
76
+
77
+ - uses: actions/cache@v4
78
+ with:
79
+ path: ~/.npm
80
+ key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
81
+ restore-keys: |
82
+ ${{ runner.os }}-npm-
83
+ save-always: true # Cache saves even if subsequent steps fail
84
+
85
+ - run: npm ci
86
+ - run: npm test # If this fails, cache is still saved
87
+ - language: yaml
88
+ label: 'Explicit restore then save with if: always() (works on all versions)'
89
+ code: |
90
+ jobs:
91
+ build:
92
+ runs-on: ubuntu-latest
93
+ steps:
94
+ - uses: actions/checkout@v4
95
+
96
+ - name: Restore cache
97
+ id: npm-cache
98
+ uses: actions/cache/restore@v4
99
+ with:
100
+ path: ~/.npm
101
+ key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
102
+ restore-keys: |
103
+ ${{ runner.os }}-npm-
104
+
105
+ - run: npm ci
106
+ - run: npm test
107
+
108
+ - name: Save cache (always, even on failure)
109
+ uses: actions/cache/save@v4
110
+ if: always()
111
+ with:
112
+ path: ~/.npm
113
+ key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
114
+ prevention:
115
+ - 'Add save-always: true to actions/cache when partial installs (e.g., npm ci with an error) are still worth caching'
116
+ - 'Consider whether caching a partial/failed state is desirable — for compiled artifacts, only cache on success'
117
+ - 'Use the split restore/save action pattern for fine-grained control over when the cache is saved'
118
+ - 'Monitor cache hit rates in the Actions UI — consistently low rates after failures indicate post-if skips'
119
+ docs:
120
+ - url: 'https://github.com/actions/cache#save-cache-even-if-the-build-fails'
121
+ label: 'actions/cache — save-always: true option'
122
+ - url: 'https://github.com/actions/cache/blob/main/save/README.md'
123
+ label: 'actions/cache/save — standalone save action'
124
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows'
125
+ label: 'GitHub Docs — Caching dependencies to speed up workflows'
126
+ - url: 'https://github.com/actions/cache/issues/92'
127
+ label: 'actions/cache#92 — Feature request: save cache on failure (highly voted)'
@@ -0,0 +1,113 @@
1
+ id: concurrency-timing-038
2
+ title: 'push and pull_request events use different github.ref formats — concurrency slots never shared between event types'
3
+ category: concurrency-timing
4
+ severity: silent-failure
5
+ tags:
6
+ - concurrency
7
+ - github-ref
8
+ - pull-request
9
+ - push
10
+ - cancel-in-progress
11
+ - slot-sharing
12
+ patterns:
13
+ - regex: 'group:\s+\$\{\{\s*github\.workflow\s*\}\}-\$\{\{\s*github\.ref\s*\}\}'
14
+ flags: 'i'
15
+ - regex: 'refs/pull/\d+/merge'
16
+ flags: ''
17
+ error_messages:
18
+ - "Push deploy and PR deploy run in parallel despite same concurrency group"
19
+ - "concurrency group does not prevent push and pull_request from running simultaneously"
20
+ - "Both workflows triggered at the same time even with concurrency group set"
21
+ root_cause: |
22
+ When concurrency group uses `${{ github.ref }}`, the ref value differs by event type:
23
+ - `on: push` to main → github.ref = 'refs/heads/main'
24
+ - `on: pull_request` targeting main → github.ref = 'refs/pull/123/merge' (synthetic merge ref)
25
+
26
+ These produce different concurrency group keys, so push and pull_request runs NEVER share
27
+ a concurrency slot. Developers who want "one deploy at a time" across push and PR events
28
+ are surprised when both run in parallel.
29
+
30
+ Common scenario:
31
+ - Deploy workflow triggers on both push (to main) and pull_request (for preview)
32
+ - A push to main is deploying
33
+ - A new PR triggers a deploy
34
+ - Both run simultaneously because their github.ref values are different strings
35
+ - Race condition or resource contention on the deployment target
36
+
37
+ This is distinct from the `github.head_ref` empty-on-push issue (which over-cancels).
38
+ Here, using `github.ref` under-cancels by never sharing slots between event types.
39
+ fix: |
40
+ To serialize push and pull_request deploys into one slot, use a ref-agnostic key
41
+ or normalize the ref to a shared value.
42
+
43
+ Option 1: Use a static concurrency key scoped to just the workflow name (one slot total):
44
+ group: ${{ github.workflow }}
45
+ cancel-in-progress: true
46
+
47
+ Option 2: Normalize to the target/base branch using head_ref for PRs and ref_name for push:
48
+ group: ${{ github.workflow }}-${{ github.head_ref || github.ref_name }}
49
+ cancel-in-progress: true
50
+
51
+ For github.head_ref || github.ref_name:
52
+ - pull_request: github.head_ref = 'feature/my-branch' (PR source branch)
53
+ - push: github.ref_name = 'main' (pushed branch name)
54
+ - Both give meaningful branch names, but they still differ — PRs use source branch, push uses target
55
+ - For "one deploy to main at a time" across both events, use github.base_ref || github.ref_name
56
+
57
+ Option 3: Use the target/base branch for both:
58
+ group: ${{ github.workflow }}-${{ github.base_ref || github.ref_name }}
59
+ cancel-in-progress: true
60
+ - pull_request: github.base_ref = 'main' (target branch)
61
+ - push: github.ref_name = 'main' (pushed branch)
62
+ - Both produce the same key for operations targeting main — serializes push and PR deploys
63
+ fix_code:
64
+ - language: yaml
65
+ label: 'Serialize push and pull_request deploys to the same target branch'
66
+ code: |
67
+ on:
68
+ push:
69
+ branches: [main]
70
+ pull_request:
71
+ branches: [main]
72
+
73
+ concurrency:
74
+ # Use base_ref (PR target) or ref_name (push branch) — both equal 'main'
75
+ # when targeting main, so push and PR deploys share one slot
76
+ group: ${{ github.workflow }}-${{ github.base_ref || github.ref_name }}
77
+ cancel-in-progress: true
78
+
79
+ jobs:
80
+ deploy:
81
+ runs-on: ubuntu-latest
82
+ steps:
83
+ - name: Deploy
84
+ run: echo "Deploying to ${{ github.base_ref || github.ref_name }}"
85
+ - language: yaml
86
+ label: 'One global slot for the entire workflow (simplest serialization)'
87
+ code: |
88
+ on:
89
+ push:
90
+ branches: [main]
91
+ pull_request:
92
+
93
+ concurrency:
94
+ group: ${{ github.workflow }}
95
+ cancel-in-progress: true
96
+
97
+ jobs:
98
+ build:
99
+ runs-on: ubuntu-latest
100
+ steps:
101
+ - run: echo "Only one run at a time, any trigger"
102
+ prevention:
103
+ - 'Understand that github.ref differs between push (refs/heads/BRANCH) and pull_request (refs/pull/N/merge) events'
104
+ - 'Use github.base_ref || github.ref_name to get the target/base branch name for both event types'
105
+ - 'Test concurrency behavior with simultaneous push and PR triggers before relying on it for deploy serialization'
106
+ - 'Use github.head_ref for the PR source branch or github.ref_name for push branch — never github.ref directly in concurrency keys unless same-event-type serialization is the goal'
107
+ docs:
108
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/controlling-concurrency'
109
+ label: 'GitHub Actions — Controlling concurrency'
110
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#github-context'
111
+ label: 'GitHub context — github.ref, github.head_ref, github.base_ref, github.ref_name'
112
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request'
113
+ label: 'pull_request event — github.ref is refs/pull/N/merge'
@@ -0,0 +1,132 @@
1
+ id: known-unsolved-046
2
+ title: 'GITHUB_STEP_SUMMARY content is not accessible by downstream jobs or reusable workflows'
3
+ category: known-unsolved
4
+ severity: limitation
5
+ tags:
6
+ - github-step-summary
7
+ - step-summary
8
+ - cross-job
9
+ - job-outputs
10
+ - reusable-workflow
11
+ - limitation
12
+ patterns:
13
+ - regex: 'GITHUB_STEP_SUMMARY'
14
+ flags: 'i'
15
+ - regex: 'step.summary'
16
+ flags: 'i'
17
+ error_messages:
18
+ - "Cannot read GITHUB_STEP_SUMMARY from another job"
19
+ - "Step summary not available as job output"
20
+ - "How to share step summary content between jobs"
21
+ root_cause: |
22
+ `GITHUB_STEP_SUMMARY` is a write-only file path for adding Markdown content to the job
23
+ summary page in the GitHub Actions UI. The content written to it is visible in the UI
24
+ but is NOT accessible programmatically from:
25
+ - Other jobs in the same workflow (even with `needs:` dependency)
26
+ - Downstream caller workflows that invoke this as a reusable workflow
27
+ - Workflow run APIs — the summary content cannot be retrieved via the REST API
28
+
29
+ The summary file exists only on the runner's local filesystem during execution and is
30
+ uploaded to GitHub as display-only content. There is no `steps.<id>.summary` output
31
+ or `needs.<job>.summary` context available.
32
+
33
+ Common failure patterns:
34
+ - Build job writes a changelog summary; deploy job tries to use it in a notification
35
+ - Reusable workflow summarizes test results; caller tries to aggregate summaries
36
+ - Reporting job expects to read markdown generated by upstream jobs
37
+
38
+ GitHub has no native mechanism to read back summary content once written.
39
+ This is a long-standing requested feature with no announced roadmap.
40
+ fix: |
41
+ Use job outputs or artifacts to share data that needs to be readable by downstream jobs.
42
+ GITHUB_STEP_SUMMARY is display-only — treat it as a write-once UI annotation.
43
+
44
+ Workaround 1 — Dual-write (write to both summary AND output/artifact):
45
+ Write the same content to GITHUB_STEP_SUMMARY for display AND to $GITHUB_OUTPUT or
46
+ an artifact for programmatic consumption by downstream jobs.
47
+
48
+ Workaround 2 — Generate in a script and capture output:
49
+ Run the data-generation logic in a script, capture to a variable, write to both
50
+ $GITHUB_STEP_SUMMARY and $GITHUB_OUTPUT in the same step.
51
+
52
+ There is no workaround that reads GITHUB_STEP_SUMMARY after it has been written.
53
+ Data sharing between jobs MUST use job outputs or artifacts.
54
+ fix_code:
55
+ - language: yaml
56
+ label: 'Dual-write: populate GITHUB_STEP_SUMMARY for UI AND job output for downstream use'
57
+ code: |
58
+ jobs:
59
+ build:
60
+ runs-on: ubuntu-latest
61
+ outputs:
62
+ changelog: ${{ steps.gen.outputs.changelog }}
63
+ steps:
64
+ - name: Generate changelog
65
+ id: gen
66
+ run: |
67
+ CHANGES=$(git log --oneline HEAD~5..HEAD)
68
+
69
+ # Write to step summary for UI display
70
+ echo "## Changes" >> $GITHUB_STEP_SUMMARY
71
+ echo "$CHANGES" >> $GITHUB_STEP_SUMMARY
72
+
73
+ # Also write to output for downstream job consumption
74
+ # Use heredoc for multiline output
75
+ {
76
+ echo "changelog<<EOF"
77
+ echo "$CHANGES"
78
+ echo "EOF"
79
+ } >> $GITHUB_OUTPUT
80
+
81
+ notify:
82
+ needs: build
83
+ runs-on: ubuntu-latest
84
+ steps:
85
+ - name: Use changelog from build job
86
+ run: |
87
+ echo "Changes to notify: ${{ needs.build.outputs.changelog }}"
88
+ - language: yaml
89
+ label: 'Upload summary content as artifact for reusable workflow callers'
90
+ code: |
91
+ jobs:
92
+ test:
93
+ runs-on: ubuntu-latest
94
+ steps:
95
+ - name: Run tests and generate report
96
+ run: |
97
+ # Write display summary
98
+ echo "## Test Results" >> $GITHUB_STEP_SUMMARY
99
+ echo "All tests passed" >> $GITHUB_STEP_SUMMARY
100
+
101
+ # Write machine-readable copy to a file (upload as artifact)
102
+ echo "All tests passed" > test-summary.md
103
+
104
+ - name: Upload summary as artifact
105
+ uses: actions/upload-artifact@v4
106
+ with:
107
+ name: test-summary
108
+ path: test-summary.md
109
+
110
+ deploy:
111
+ needs: test
112
+ runs-on: ubuntu-latest
113
+ steps:
114
+ - name: Download test summary
115
+ uses: actions/download-artifact@v4
116
+ with:
117
+ name: test-summary
118
+
119
+ - name: Use test summary
120
+ run: cat test-summary.md
121
+ prevention:
122
+ - 'Never assume GITHUB_STEP_SUMMARY content can be read back — it is write-only display output'
123
+ - 'Design workflows to use job outputs ($GITHUB_OUTPUT) or artifacts for any data that must flow between jobs'
124
+ - 'Write data to both GITHUB_STEP_SUMMARY (for UI) and $GITHUB_OUTPUT (for downstream) in the same step when both are needed'
125
+ - 'Document this limitation for team members who discover it while trying to aggregate summaries across jobs'
126
+ docs:
127
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#adding-a-job-summary'
128
+ label: 'GitHub Docs — Adding a job summary (GITHUB_STEP_SUMMARY)'
129
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/passing-information-between-jobs'
130
+ label: 'GitHub Docs — Passing information between jobs (outputs and artifacts)'
131
+ - url: 'https://github.com/orgs/community/discussions/12836'
132
+ label: 'GitHub Community — Read GITHUB_STEP_SUMMARY from downstream jobs (no native support)'
@@ -0,0 +1,121 @@
1
+ id: yaml-syntax-048
2
+ title: 'workflow_call inputs do not support type: choice — validation error when copying from workflow_dispatch'
3
+ category: yaml-syntax
4
+ severity: error
5
+ tags:
6
+ - workflow-call
7
+ - reusable-workflow
8
+ - inputs
9
+ - type-choice
10
+ - workflow-dispatch
11
+ - validation-error
12
+ patterns:
13
+ - regex: 'Unexpected\s+value\s+[''"]choice[''"]'
14
+ flags: 'i'
15
+ - regex: 'type:\s+choice'
16
+ flags: 'i'
17
+ - regex: 'on\.workflow_call\.inputs\.[^.]+\.type.*choice'
18
+ flags: 'i'
19
+ error_messages:
20
+ - "Unexpected value 'choice'"
21
+ - "Invalid workflow file: .github/workflows/deploy.yml#L12: Unexpected value 'choice'"
22
+ - "on.workflow_call.inputs.environment.type: Unexpected value 'choice'"
23
+ - "inputs.environment.options: Unexpected value"
24
+ root_cause: |
25
+ GitHub Actions supports two input type systems that are NOT identical:
26
+ - workflow_dispatch inputs support: string, choice, boolean, environment, number
27
+ - workflow_call inputs support: string, boolean, number ONLY
28
+
29
+ The `choice` type (with its `options:` list) is exclusive to workflow_dispatch manual triggers.
30
+ Reusable workflows (workflow_call) do not support `type: choice` or the `options:` field.
31
+
32
+ This error is most commonly hit when:
33
+ 1. A developer builds a manual workflow_dispatch workflow with choice inputs
34
+ 2. They convert it to a reusable workflow by changing `on: workflow_dispatch` to `on: workflow_call`
35
+ 3. They leave the `type: choice` and `options:` keys intact
36
+ 4. The workflow fails validation with "Unexpected value 'choice'"
37
+
38
+ Example invalid workflow_call input:
39
+ on:
40
+ workflow_call:
41
+ inputs:
42
+ environment:
43
+ type: choice # ERROR: not supported in workflow_call
44
+ options: # ERROR: not supported in workflow_call
45
+ - staging
46
+ - production
47
+ required: true
48
+ fix: |
49
+ Change `type: choice` to `type: string` in workflow_call inputs and remove the `options:` key.
50
+ To enforce valid values, validate the input inside the workflow body using an `if:` condition
51
+ or a run step that exits on invalid input.
52
+
53
+ The calling workflow or documentation should enumerate the valid values since workflow_call
54
+ cannot enforce them at the input schema level.
55
+ fix_code:
56
+ - language: yaml
57
+ label: 'workflow_call input with string type and manual validation (called workflow)'
58
+ code: |
59
+ # .github/workflows/deploy-reusable.yml
60
+ on:
61
+ workflow_call:
62
+ inputs:
63
+ environment:
64
+ type: string # Change 'choice' to 'string'
65
+ required: true
66
+ description: 'Target environment: staging or production'
67
+ # No 'options:' key — not supported in workflow_call
68
+
69
+ jobs:
70
+ validate-input:
71
+ runs-on: ubuntu-latest
72
+ steps:
73
+ - name: Validate environment input
74
+ run: |
75
+ if [[ "${{ inputs.environment }}" != "staging" && "${{ inputs.environment }}" != "production" ]]; then
76
+ echo "Invalid environment: ${{ inputs.environment }}"
77
+ echo "Valid values: staging, production"
78
+ exit 1
79
+ fi
80
+
81
+ deploy:
82
+ needs: validate-input
83
+ runs-on: ubuntu-latest
84
+ environment: ${{ inputs.environment }}
85
+ steps:
86
+ - run: echo "Deploying to ${{ inputs.environment }}"
87
+ - language: yaml
88
+ label: 'Calling workflow passing the environment string input'
89
+ code: |
90
+ # .github/workflows/deploy-caller.yml
91
+ on:
92
+ workflow_dispatch:
93
+ inputs:
94
+ environment:
95
+ type: choice # choice IS supported here in workflow_dispatch
96
+ options:
97
+ - staging
98
+ - production
99
+ required: true
100
+
101
+ jobs:
102
+ call-deploy:
103
+ uses: ./.github/workflows/deploy-reusable.yml
104
+ with:
105
+ environment: ${{ inputs.environment }} # Pass validated string to reusable
106
+ secrets: inherit
107
+ prevention:
108
+ - 'workflow_call inputs only support type: string, boolean, and number — never type: choice or type: environment'
109
+ - 'Keep workflow_dispatch wrappers that expose choice inputs and call the reusable workflow internally'
110
+ - 'Document the valid values for string inputs in the description field of workflow_call inputs'
111
+ - 'Add an explicit validation step at the start of the reusable workflow to enforce allowed values'
112
+ - 'Use actionlint to catch unsupported input types before pushing the workflow file'
113
+ docs:
114
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_call'
115
+ label: 'GitHub Docs — workflow_call inputs (string, boolean, number only)'
116
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_dispatch'
117
+ label: 'GitHub Docs — workflow_dispatch inputs (includes choice, environment types)'
118
+ - url: 'https://docs.github.com/en/actions/sharing-automations/reusing-workflows#using-inputs-and-secrets-in-a-reusable-workflow'
119
+ label: 'GitHub Docs — Reusable workflow inputs and secrets'
120
+ - url: 'https://github.com/orgs/community/discussions/39357'
121
+ label: 'GitHub Community — workflow_call does not support type: choice inputs'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htekdev/actions-debugger",
3
- "version": "1.0.73",
3
+ "version": "1.0.74",
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",