@htekdev/actions-debugger 1.0.79 → 1.0.80

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,81 @@
1
+ id: caching-artifacts-046
2
+ title: "actions/cache exact key hit skips save step — caches go stale when dependency hash doesn't change"
3
+ category: caching-artifacts
4
+ severity: silent-failure
5
+ tags:
6
+ - cache
7
+ - save-always
8
+ - cache-hit
9
+ - stale-cache
10
+ - cache-invalidation
11
+ patterns:
12
+ - regex: 'Cache hit occurred on the primary key'
13
+ flags: i
14
+ - regex: 'Not saving cache'
15
+ flags: i
16
+ error_messages:
17
+ - "Cache hit occurred on the primary key, not saving cache."
18
+ - "Not saving cache as it is not requested."
19
+ root_cause: |
20
+ When actions/cache finds an exact match for the primary key, it sets
21
+ cache-hit: 'true' and the post-step save is skipped entirely. The rationale is
22
+ that since the key already exists, re-saving an identical entry would be wasteful.
23
+
24
+ However, this behaviour means that cache content changes that do NOT affect the
25
+ hash (e.g., transitive package security patches, tool binary updates, or
26
+ generated files included in the cached path) are never persisted. The cache
27
+ entry stays frozen at the state it was in when the key was first saved.
28
+
29
+ Common scenario: a workflow caches node_modules keyed on package-lock.json hash.
30
+ The lock file goes unchanged for weeks, but npm packages receive silent patch
31
+ updates or a cached binary becomes corrupt. Every run gets a cache hit, skips the
32
+ save, and the stale or corrupt content continues to be served until the lock file
33
+ hash finally changes.
34
+ fix: |
35
+ Set save-always: true on the cache step to force a save even when the exact key
36
+ already exists. For finer control, split the action into separate
37
+ actions/cache/restore and actions/cache/save steps so the save can run
38
+ conditionally. To immediately invalidate a specific cache entry, delete it via
39
+ the GitHub REST API or the Actions UI under Repository > Actions > Caches.
40
+ fix_code:
41
+ - language: yaml
42
+ label: "Force save on every run with save-always"
43
+ code: |
44
+ - name: Cache node_modules
45
+ uses: actions/cache@v4
46
+ with:
47
+ path: node_modules
48
+ key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
49
+ restore-keys: ${{ runner.os }}-node-
50
+ # Always save even if exact key already exists in the cache
51
+ save-always: true
52
+
53
+ - language: yaml
54
+ label: "Split restore and save for conditional save logic"
55
+ code: |
56
+ - name: Restore cache
57
+ id: cache-restore
58
+ uses: actions/cache/restore@v4
59
+ with:
60
+ path: node_modules
61
+ key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
62
+ restore-keys: ${{ runner.os }}-node-
63
+
64
+ - name: Install dependencies
65
+ run: npm ci
66
+
67
+ - name: Save cache
68
+ uses: actions/cache/save@v4
69
+ if: always()
70
+ with:
71
+ path: node_modules
72
+ key: ${{ steps.cache-restore.outputs.cache-primary-key }}
73
+ prevention:
74
+ - "Use save-always: true when cached content may diverge from the hash key (e.g., tool caches, binary downloads)."
75
+ - "Periodically evict stale cache entries via the GitHub REST API DELETE /repos/{owner}/{repo}/actions/caches/{cache_id}."
76
+ - "Include a tool version or date component in the cache key when the content should rotate on a schedule."
77
+ docs:
78
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows"
79
+ label: "GitHub Actions: Caching dependencies"
80
+ - url: "https://github.com/actions/cache#save-always"
81
+ label: "actions/cache README: save-always option"
@@ -0,0 +1,64 @@
1
+ id: concurrency-timing-040
2
+ title: "workflow_dispatch and push share concurrency group, dispatch cancels in-progress CI"
3
+ category: concurrency-timing
4
+ severity: error
5
+ tags:
6
+ - concurrency
7
+ - workflow-dispatch
8
+ - push
9
+ - cancel-in-progress
10
+ - event-name
11
+ patterns:
12
+ - regex: 'This run was cancelled'
13
+ flags: i
14
+ - regex: 'concurrency.*workflow_dispatch|workflow_dispatch.*concurrency'
15
+ flags: ims
16
+ error_messages:
17
+ - "This run was cancelled."
18
+ - "A run for this workflow is already in progress."
19
+ root_cause: |
20
+ When a concurrency group key is built from github.workflow and github.ref alone,
21
+ both workflow_dispatch and push events on the same branch produce an identical key.
22
+ GitHub treats them as competing occupants of the same concurrency slot.
23
+
24
+ With cancel-in-progress: true, a manually dispatched run immediately cancels any
25
+ push-triggered CI run already in progress (or vice versa). Without cancel-in-progress,
26
+ the dispatch run queues behind the push run but still competes for the same slot.
27
+
28
+ This catches developers off guard when they manually trigger a workflow for
29
+ debugging while CI is running — the in-progress CI run is silently cancelled. Or a
30
+ push to the same branch during a long dispatch run causes the dispatch to be evicted.
31
+ fix: |
32
+ Include github.event_name in the concurrency group key to give workflow_dispatch
33
+ and push events separate concurrency slots. Alternatively, use a conditional
34
+ cancel-in-progress expression so manual dispatches are never cancelled.
35
+ fix_code:
36
+ - language: yaml
37
+ label: "Include event_name to separate dispatch and push slots"
38
+ code: |
39
+ # WRONG: dispatch and push on same branch share a slot and cancel each other
40
+ # concurrency:
41
+ # group: ${{ github.workflow }}-${{ github.ref }}
42
+ # cancel-in-progress: true
43
+
44
+ # CORRECT: each event type gets its own concurrency slot
45
+ concurrency:
46
+ group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}
47
+ cancel-in-progress: true
48
+
49
+ - language: yaml
50
+ label: "Alternative: only cancel-in-progress for push and pull_request, not dispatch"
51
+ code: |
52
+ concurrency:
53
+ group: ${{ github.workflow }}-${{ github.ref }}
54
+ # Manual dispatches are never cancelled; push/PR runs are stacked-and-cancelled
55
+ cancel-in-progress: ${{ github.event_name != 'workflow_dispatch' }}
56
+ prevention:
57
+ - "Always include github.event_name in concurrency group keys when a workflow has multiple trigger events."
58
+ - "Test concurrency behavior by triggering both events in quick succession; bugs only surface under race conditions."
59
+ - "For release or deploy workflows, consider separate workflows for dispatch vs automated CI rather than sharing concurrency."
60
+ docs:
61
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#concurrency"
62
+ label: "GitHub Actions: Concurrency syntax"
63
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_dispatch"
64
+ label: "GitHub Actions: workflow_dispatch event"
@@ -0,0 +1,81 @@
1
+ id: permissions-auth-048
2
+ title: "Dependabot PR workflows cannot access repository secrets — only Dependabot secrets are injected"
3
+ category: permissions-auth
4
+ severity: error
5
+ tags:
6
+ - dependabot
7
+ - secrets
8
+ - pull-request
9
+ - registry-auth
10
+ - secret-isolation
11
+ patterns:
12
+ - regex: 'Input required and not supplied'
13
+ flags: i
14
+ - regex: '401 Unauthorized'
15
+ flags: i
16
+ error_messages:
17
+ - "Error: Input required and not supplied: token"
18
+ - "npm ERR! code E401"
19
+ - "Error: Unauthorized"
20
+ root_cause: |
21
+ When Dependabot opens or updates a pull request, GitHub Actions workflows triggered
22
+ by that PR run in an isolated secret context. Repository secrets (defined under
23
+ Settings > Secrets and variables > Actions) are NOT injected into Dependabot-triggered
24
+ workflow runs. Only secrets defined under Settings > Secrets and variables > Dependabot
25
+ are available.
26
+
27
+ This means steps that reference secrets.NPM_TOKEN, secrets.DOCKER_PASSWORD,
28
+ secrets.SONAR_TOKEN, or any custom repository secret will receive an empty string.
29
+ Actions that validate their inputs (e.g., a custom action with required: true on a
30
+ token input) will fail with "Input required and not supplied". Registry steps will
31
+ fail with 401 Unauthorized.
32
+
33
+ GITHUB_TOKEN is exempt and is still injected normally for Dependabot runs.
34
+ fix: |
35
+ Re-create the required secrets under Settings > Secrets and variables > Dependabot
36
+ (a separate namespace from Actions secrets). Dependabot reads from its own secret
37
+ store, not the repository Actions secret store. Alternatively, restructure the
38
+ workflow so secret-dependent steps only run on non-Dependabot actors using an
39
+ if: condition.
40
+ fix_code:
41
+ - language: yaml
42
+ label: "Add secrets to Dependabot secret store in GitHub UI"
43
+ code: |
44
+ # In GitHub: Settings > Secrets and variables > Dependabot
45
+ # Add the same secret names you use in your Actions secrets.
46
+ # They are stored separately and only injected for Dependabot-triggered runs.
47
+
48
+ # No workflow YAML change required — just add the secret in the UI.
49
+ # Example workflow remains unchanged:
50
+ jobs:
51
+ build:
52
+ runs-on: ubuntu-latest
53
+ steps:
54
+ - uses: actions/checkout@v4
55
+ - run: npm publish
56
+ env:
57
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} # Works once added to Dependabot secrets
58
+
59
+ - language: yaml
60
+ label: "Skip secret-dependent steps when actor is dependabot"
61
+ code: |
62
+ jobs:
63
+ build:
64
+ runs-on: ubuntu-latest
65
+ steps:
66
+ - uses: actions/checkout@v4
67
+ - name: Publish to registry
68
+ # Skip publish step for Dependabot PRs that lack the token
69
+ if: github.actor != 'dependabot[bot]'
70
+ run: npm publish
71
+ env:
72
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
73
+ prevention:
74
+ - "Maintain parallel secrets under both Actions and Dependabot secret stores for tokens Dependabot PRs need."
75
+ - "Audit workflows triggered by pull_request to identify steps using custom secrets — they silently fail for Dependabot."
76
+ - "Use github.actor != 'dependabot[bot]' guards on publish/deploy steps that Dependabot PRs should skip."
77
+ docs:
78
+ - url: "https://docs.github.com/en/code-security/dependabot/working-with-dependabot/automating-dependabot-with-github-actions#accessing-secrets"
79
+ label: "GitHub Docs: Accessing secrets in Dependabot workflows"
80
+ - url: "https://docs.github.com/en/code-security/dependabot/working-with-dependabot/configuring-access-to-private-registries-for-dependabot"
81
+ label: "GitHub Docs: Dependabot and private registries"
@@ -0,0 +1,72 @@
1
+ id: yaml-syntax-050
2
+ title: "secrets context used in job/step if: condition rejected — only valid in env: and with: blocks"
3
+ category: yaml-syntax
4
+ severity: error
5
+ tags:
6
+ - secrets
7
+ - if-condition
8
+ - expression-context
9
+ - actionlint
10
+ - context-availability
11
+ patterns:
12
+ - regex: 'Unrecognized named-value: ''secrets'''
13
+ flags: i
14
+ - regex: 'Context access might be invalid: secrets'
15
+ flags: i
16
+ error_messages:
17
+ - "Unrecognized named-value: 'secrets'. Located at position 1 within expression"
18
+ - "Context access might be invalid: secrets"
19
+ root_cause: |
20
+ The secrets context is only available inside env: blocks and action input with: blocks.
21
+ It cannot be used in if: conditions at the job or step level.
22
+
23
+ A common pattern is to conditionally run a deployment step only when a secret is
24
+ configured: if: secrets.DEPLOY_TOKEN != ''. GitHub's expression evaluator rejects
25
+ this at runtime with "Unrecognized named-value: 'secrets'", failing the step or job
26
+ before it even starts. actionlint reports this as a static analysis error under
27
+ "Context access might be invalid: secrets".
28
+
29
+ The restriction is documented in GitHub's context availability table: the secrets
30
+ context is listed as unavailable for job.<job_id>.if and steps.<step_id>.if.
31
+ fix: |
32
+ Map the secret to an environment variable in an env: block, then check the
33
+ environment variable in the if: condition using the env context. For a job-level
34
+ gate, set the env var at the job level and reference it in a step if: condition.
35
+ fix_code:
36
+ - language: yaml
37
+ label: "Bridge secret through env var for step-level if:"
38
+ code: |
39
+ # WRONG: secrets context not available in if: conditions
40
+ # - name: Deploy
41
+ # if: secrets.DEPLOY_TOKEN != ''
42
+ # run: ./deploy.sh
43
+
44
+ # CORRECT: map secret to env var, check env var in if:
45
+ - name: Deploy
46
+ if: env.DEPLOY_TOKEN != ''
47
+ env:
48
+ DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
49
+ run: ./deploy.sh
50
+
51
+ - language: yaml
52
+ label: "Job-level env gate evaluated in step if:"
53
+ code: |
54
+ jobs:
55
+ deploy:
56
+ runs-on: ubuntu-latest
57
+ env:
58
+ # Set at job level so all steps can reference it
59
+ DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
60
+ steps:
61
+ - name: Deploy
62
+ if: env.DEPLOY_TOKEN != ''
63
+ run: ./deploy.sh
64
+ prevention:
65
+ - "Never reference secrets.* in if: conditions — always bridge through an env: variable first."
66
+ - "Run actionlint in CI to catch 'Context access might be invalid: secrets' errors before they reach production."
67
+ - "Consider using a boolean repository variable (vars.DEPLOY_ENABLED) as a conditional gate rather than checking secret presence."
68
+ docs:
69
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#context-availability"
70
+ label: "GitHub Actions: Context availability"
71
+ - url: "https://rhysd.github.io/actionlint/checks.html#check-contexts-and-special-functions"
72
+ label: "actionlint: Context availability checks"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htekdev/actions-debugger",
3
- "version": "1.0.79",
3
+ "version": "1.0.80",
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",