@htekdev/actions-debugger 1.0.0 → 1.0.1

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.
Files changed (53) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +108 -108
  3. package/errors/_schema.json +89 -89
  4. package/errors/caching-artifacts/artifact-storage-quota-exceeded.yml +118 -0
  5. package/errors/caching-artifacts/cache-miss.yml +56 -56
  6. package/errors/caching-artifacts/cache-save-cancelled-job.yml +82 -0
  7. package/errors/caching-artifacts/cache-v3-to-v4-breaking-changes.yml +95 -0
  8. package/errors/caching-artifacts/cross-repo-artifacts-not-supported.yml +102 -0
  9. package/errors/caching-artifacts/upload-artifact-no-files-found.yml +92 -0
  10. package/errors/caching-artifacts/upload-artifact-v4-breaking.yml +67 -67
  11. package/errors/concurrency-timing/cancel-in-progress-deploy-drops.yml +97 -0
  12. package/errors/concurrency-timing/jobs-cancelled-unexpectedly.yml +60 -60
  13. package/errors/concurrency-timing/skipped-needs-cascade.yml +103 -0
  14. package/errors/concurrency-timing/workflow-run-conclusion-unchecked.yml +100 -0
  15. package/errors/known-unsolved/composite-input-env-vars-missing.yml +91 -0
  16. package/errors/known-unsolved/composite-nested-outputs-null.yml +101 -0
  17. package/errors/known-unsolved/no-dynamic-secret-access.yml +111 -0
  18. package/errors/known-unsolved/no-step-level-rerun.yml +94 -0
  19. package/errors/known-unsolved/no-step-retry.yml +53 -53
  20. package/errors/permissions-auth/checkout-submodule-private-auth.yml +91 -0
  21. package/errors/permissions-auth/fork-pr-secrets-unavailable.yml +97 -0
  22. package/errors/permissions-auth/github-token-403.yml +64 -64
  23. package/errors/permissions-auth/github-token-protected-branch-push.yml +109 -0
  24. package/errors/permissions-auth/oidc-aws-failure.yml +85 -85
  25. package/errors/permissions-auth/oidc-azure-subject-mismatch.yml +91 -0
  26. package/errors/runner-environment/disk-space.yml +57 -57
  27. package/errors/runner-environment/docker-buildx-not-setup.yml +106 -0
  28. package/errors/runner-environment/macos-homebrew-path.yml +90 -0
  29. package/errors/runner-environment/node-runtime-deprecation.yml +56 -56
  30. package/errors/runner-environment/npm-ci-lockfile-mismatch.yml +112 -0
  31. package/errors/runner-environment/self-hosted-stale-toolcache.yml +73 -0
  32. package/errors/runner-environment/setup-node-version-file-missing.yml +105 -0
  33. package/errors/runner-environment/windows-execution-policy.yml +83 -0
  34. package/errors/silent-failures/add-mask-no-retroactive-masking.yml +75 -0
  35. package/errors/silent-failures/composite-boolean-inputs-as-strings.yml +110 -0
  36. package/errors/silent-failures/conditional-output-null-downstream.yml +82 -0
  37. package/errors/silent-failures/continue-on-error-masks-failure.yml +86 -0
  38. package/errors/silent-failures/github-token-no-trigger.yml +57 -57
  39. package/errors/silent-failures/reusable-workflow-env-secrets-empty.yml +90 -0
  40. package/errors/silent-failures/scheduled-workflow-disabled.yml +59 -59
  41. package/errors/triggers/cron-schedule-late.yml +59 -59
  42. package/errors/triggers/pull-request-target-rce-risk.yml +117 -0
  43. package/errors/triggers/workflow-not-triggering.yml +60 -60
  44. package/errors/triggers/workflow-run-default-branch-requirement.yml +78 -0
  45. package/errors/yaml-syntax/anchors-not-supported.yml +95 -0
  46. package/errors/yaml-syntax/dynamic-matrix-fromjson-failure.yml +99 -0
  47. package/errors/yaml-syntax/if-always-true.yml +52 -52
  48. package/errors/yaml-syntax/missing-expression-wrapper.yml +67 -0
  49. package/errors/yaml-syntax/needs-indirect-outputs.yml +91 -0
  50. package/errors/yaml-syntax/secrets-in-if.yml +55 -55
  51. package/errors/yaml-syntax/unexpected-yaml-key.yml +69 -69
  52. package/errors/yaml-syntax/working-directory-ignored-on-uses.yml +66 -0
  53. package/package.json +70 -67
@@ -1,52 +1,52 @@
1
- id: yaml-syntax-007
2
- title: "if: Conditionals Always Evaluating to true"
3
- category: yaml-syntax
4
- severity: silent-failure
5
- tags:
6
- - if
7
- - expressions
8
- - conditionals
9
- - yaml
10
- - truthy
11
- patterns:
12
- - regex: "Evaluating condition for step: .*"
13
- flags: "i"
14
- - regex: "Expanded: '.+\\n.+"
15
- flags: "i"
16
- - regex: "Result: true"
17
- flags: "i"
18
- error_messages:
19
- - "Result: true"
20
- root_cause: |
21
- Using a block scalar such as `if: |` turns the condition into a multi-line string.
22
- In GitHub Actions expressions, any non-empty string is truthy, so the step or job can
23
- run even when the intended logical check should have been false.
24
-
25
- A similar footgun happens when the expression is written with extra trailing text or
26
- whitespace outside the `${{ }}` block, which changes the value from a boolean expression
27
- into a plain string.
28
- fix: |
29
- Keep `if:` expressions on a single line and avoid YAML pipe scalars for conditionals.
30
- Make sure the entire value is the expression itself, with no extra text after `${{ }}`.
31
- fix_code:
32
- - language: yaml
33
- label: "Write if as a single-line expression"
34
- code: |
35
- jobs:
36
- deploy:
37
- runs-on: ubuntu-latest
38
- if: ${{ github.ref == 'refs/heads/main' && github.event_name == 'push' }}
39
- steps:
40
- - run: ./deploy.sh
41
- prevention:
42
- - "Never use `if: |` for GitHub Actions conditionals."
43
- - "Turn on step debug logging when a condition seems inverted and inspect the `Expanded:` and `Result:` lines."
44
- - "Keep boolean logic entirely inside a single `${{ }}` expression."
45
- docs:
46
- - url: "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idif"
47
- label: "jobs.<job_id>.if"
48
- - url: "https://docs.github.com/en/actions/learn-github-actions/expressions"
49
- label: "Expressions"
50
- source:
51
- article: "https://htek.dev/articles/github-actions-debugging-guide"
52
- section: "if expressions that always evaluate true"
1
+ id: yaml-syntax-007
2
+ title: "if: Conditionals Always Evaluating to true"
3
+ category: yaml-syntax
4
+ severity: silent-failure
5
+ tags:
6
+ - if
7
+ - expressions
8
+ - conditionals
9
+ - yaml
10
+ - truthy
11
+ patterns:
12
+ - regex: "Evaluating condition for step: .*"
13
+ flags: "i"
14
+ - regex: "Expanded: '.+\\n.+"
15
+ flags: "i"
16
+ - regex: "Result: true"
17
+ flags: "i"
18
+ error_messages:
19
+ - "Result: true"
20
+ root_cause: |
21
+ Using a block scalar such as `if: |` turns the condition into a multi-line string.
22
+ In GitHub Actions expressions, any non-empty string is truthy, so the step or job can
23
+ run even when the intended logical check should have been false.
24
+
25
+ A similar footgun happens when the expression is written with extra trailing text or
26
+ whitespace outside the `${{ }}` block, which changes the value from a boolean expression
27
+ into a plain string.
28
+ fix: |
29
+ Keep `if:` expressions on a single line and avoid YAML pipe scalars for conditionals.
30
+ Make sure the entire value is the expression itself, with no extra text after `${{ }}`.
31
+ fix_code:
32
+ - language: yaml
33
+ label: "Write if as a single-line expression"
34
+ code: |
35
+ jobs:
36
+ deploy:
37
+ runs-on: ubuntu-latest
38
+ if: ${{ github.ref == 'refs/heads/main' && github.event_name == 'push' }}
39
+ steps:
40
+ - run: ./deploy.sh
41
+ prevention:
42
+ - "Never use `if: |` for GitHub Actions conditionals."
43
+ - "Turn on step debug logging when a condition seems inverted and inspect the `Expanded:` and `Result:` lines."
44
+ - "Keep boolean logic entirely inside a single `${{ }}` expression."
45
+ docs:
46
+ - url: "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idif"
47
+ label: "jobs.<job_id>.if"
48
+ - url: "https://docs.github.com/en/actions/learn-github-actions/expressions"
49
+ label: "Expressions"
50
+ source:
51
+ article: "https://htek.dev/articles/github-actions-debugging-guide"
52
+ section: "if expressions that always evaluate true"
@@ -0,0 +1,67 @@
1
+ id: yaml-syntax-010
2
+ title: "Expression Context Reference Without ${{ }} Wrapper Produces Literal String"
3
+ category: yaml-syntax
4
+ severity: silent-failure
5
+ tags:
6
+ - yaml
7
+ - expressions
8
+ - context
9
+ - interpolation
10
+ - env
11
+ - variables
12
+ patterns:
13
+ - regex: "github\\.sha|github\\.ref|github\\.actor"
14
+ flags: "i"
15
+ - regex: "env\\.[A-Z_]+ is not a valid"
16
+ flags: "i"
17
+ error_messages:
18
+ - "Unexpected value 'github.sha'"
19
+ - "The expression 'github.ref' is not valid. Expected a string, number, boolean, or null literal."
20
+ root_cause: |
21
+ GitHub Actions expressions must be wrapped in `${{ }}` to be evaluated. Without the
22
+ wrapper, the value is treated as a literal YAML string and passed verbatim.
23
+
24
+ This commonly happens in `env:` maps, `with:` inputs, and step outputs where developers
25
+ write `MY_VAR: github.sha` instead of `MY_VAR: ${{ github.sha }}`. The workflow runs
26
+ successfully but every downstream consumer sees the literal string `"github.sha"` rather
27
+ than the actual commit SHA.
28
+
29
+ The same issue affects `run:` steps using `echo $github.sha` (which bash interprets as
30
+ `$github` dot `sha`, producing an empty or unexpected value) instead of
31
+ `echo ${{ github.sha }}` or the equivalent `$GITHUB_SHA` environment variable.
32
+ fix: |
33
+ Wrap every context reference in `${{ }}`. Prefer the built-in `GITHUB_*` environment
34
+ variables inside `run:` steps — they are always set and do not require expression syntax.
35
+ fix_code:
36
+ - language: yaml
37
+ label: "WRONG — literal strings instead of expressions"
38
+ code: |
39
+ jobs:
40
+ build:
41
+ runs-on: ubuntu-latest
42
+ env:
43
+ COMMIT: github.sha # literal string "github.sha"
44
+ BRANCH: github.ref_name # literal string "github.ref_name"
45
+ steps:
46
+ - run: echo "Building github.sha on github.ref_name"
47
+ - language: yaml
48
+ label: "CORRECT — use ${{ }} wrapper or built-in env vars"
49
+ code: |
50
+ jobs:
51
+ build:
52
+ runs-on: ubuntu-latest
53
+ env:
54
+ COMMIT: ${{ github.sha }}
55
+ BRANCH: ${{ github.ref_name }}
56
+ steps:
57
+ # Inside run: steps, prefer built-in env vars — no expression syntax needed
58
+ - run: echo "Building $GITHUB_SHA on $GITHUB_REF_NAME"
59
+ prevention:
60
+ - "Always wrap context references (`github.*`, `env.*`, `secrets.*`, `steps.*`) in `${{ }}`."
61
+ - "Inside `run:` steps, prefer the built-in `GITHUB_*` environment variables over expression syntax."
62
+ - "Use `actionlint` locally — it catches bare context references before you push."
63
+ docs:
64
+ - url: "https://docs.github.com/en/actions/learn-github-actions/expressions"
65
+ label: "Expressions"
66
+ - url: "https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables"
67
+ label: "Default environment variables"
@@ -0,0 +1,91 @@
1
+ id: yaml-syntax-011
2
+ title: "Accessing Outputs from Non-Direct needs Dependency Fails"
3
+ category: yaml-syntax
4
+ severity: error
5
+ tags:
6
+ - needs
7
+ - outputs
8
+ - context
9
+ - job-dependencies
10
+ - expressions
11
+ patterns:
12
+ - regex: "Unrecognized named-value: 'needs'"
13
+ flags: "i"
14
+ - regex: "needs\\.[a-z_-]+\\.outputs\\.[a-z_-]+ is not available"
15
+ flags: "i"
16
+ - regex: "Job '[^']+' references output '[^']+' from job '[^']+' that is not a direct dependency"
17
+ flags: "i"
18
+ error_messages:
19
+ - "Unrecognized named-value: 'needs'. Located at position 1 within expression: needs.build.outputs.version"
20
+ - "Job 'deploy' references output 'version' from job 'build' that is not a direct dependency"
21
+ root_cause: |
22
+ The `needs` context is only populated for the direct dependencies listed in a job's
23
+ `needs:` array. A job cannot reference outputs from a grandparent job that is not in
24
+ its own `needs:` list, even if an intermediate job depends on it.
25
+
26
+ For example, if `test` needs `build`, and `deploy` needs `test`, then `deploy` cannot
27
+ access `needs.build.outputs.version` — only `needs.test.outputs.*` is available.
28
+ `deploy` would need to either also list `build` in its `needs:`, or `test` would need
29
+ to re-expose `build`'s output as its own output.
30
+ fix: |
31
+ Either add the upstream job directly to the dependent job's `needs:` list, or re-expose
32
+ the needed output through each intermediate job in the chain.
33
+ fix_code:
34
+ - language: yaml
35
+ label: "WRONG — accessing grandparent output without direct dependency"
36
+ code: |
37
+ jobs:
38
+ build:
39
+ runs-on: ubuntu-latest
40
+ outputs:
41
+ version: ${{ steps.tag.outputs.version }}
42
+ steps:
43
+ - id: tag
44
+ run: echo "version=1.2.3" >> $GITHUB_OUTPUT
45
+
46
+ test:
47
+ needs: build
48
+ runs-on: ubuntu-latest
49
+ steps:
50
+ - run: npm test
51
+
52
+ deploy:
53
+ needs: test # build is NOT in this list
54
+ runs-on: ubuntu-latest
55
+ steps:
56
+ # ERROR: needs.build.outputs.version is unavailable here
57
+ - run: echo "Deploying ${{ needs.build.outputs.version }}"
58
+ - language: yaml
59
+ label: "CORRECT option 1 — add build to deploy's needs directly"
60
+ code: |
61
+ jobs:
62
+ deploy:
63
+ needs: [test, build] # both listed
64
+ runs-on: ubuntu-latest
65
+ steps:
66
+ - run: echo "Deploying ${{ needs.build.outputs.version }}"
67
+ - language: yaml
68
+ label: "CORRECT option 2 — propagate output through intermediate job"
69
+ code: |
70
+ jobs:
71
+ test:
72
+ needs: build
73
+ runs-on: ubuntu-latest
74
+ outputs:
75
+ version: ${{ needs.build.outputs.version }} # re-expose
76
+ steps:
77
+ - run: npm test
78
+
79
+ deploy:
80
+ needs: test
81
+ runs-on: ubuntu-latest
82
+ steps:
83
+ - run: echo "Deploying ${{ needs.test.outputs.version }}"
84
+ prevention:
85
+ - "Draw your job dependency graph before writing `needs:` — a job can only see outputs from jobs it directly depends on."
86
+ - "When a value needs to flow through multiple jobs, explicitly re-expose it as an output at each stage."
87
+ docs:
88
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/passing-information-between-jobs"
89
+ label: "Passing information between jobs"
90
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idneeds"
91
+ label: "jobs.<job_id>.needs"
@@ -1,55 +1,55 @@
1
- id: yaml-syntax-005
2
- title: "secrets.* in if: Conditions — Silent Failures"
3
- category: yaml-syntax
4
- severity: silent-failure
5
- tags:
6
- - secrets
7
- - if
8
- - expressions
9
- - contexts
10
- - env
11
- patterns:
12
- - regex: "Unrecognized named-value: 'secrets'"
13
- flags: "i"
14
- - regex: "The workflow is not valid\\..*named-value: 'secrets'"
15
- flags: "i"
16
- - regex: "Context access might be invalid: secrets\\."
17
- flags: "i"
18
- error_messages:
19
- - "Unrecognized named-value: 'secrets'"
20
- root_cause: |
21
- The `secrets` context is not available everywhere an expression can appear, and using
22
- `secrets.*` directly inside an `if:` condition is a common trap. Depending on where the
23
- expression is evaluated, GitHub Actions can reject the workflow or effectively treat the
24
- check as unavailable.
25
-
26
- The safe pattern is to map the secret into an environment variable first, then evaluate
27
- the environment variable in the `if:` expression.
28
- fix: |
29
- Pass the secret through `env:` and reference `env.NAME` in the `if:`. This keeps the
30
- conditional supported and avoids direct `secrets.*` access in the condition.
31
- fix_code:
32
- - language: yaml
33
- label: "Gate a step using env instead of secrets directly"
34
- code: |
35
- jobs:
36
- publish:
37
- runs-on: ubuntu-latest
38
- env:
39
- HAS_TOKEN: ${{ secrets.NPM_TOKEN }}
40
- steps:
41
- - name: Publish
42
- if: ${{ env.HAS_TOKEN != '' }}
43
- run: npm publish
44
- prevention:
45
- - "Do not reference `secrets.*` directly in `if:` unless the docs explicitly allow that context."
46
- - "Promote secrets into `env` when a step should be conditionally gated."
47
- - "Check the contexts reference before using a context in expressions."
48
- docs:
49
- - url: "https://docs.github.com/en/actions/learn-github-actions/contexts"
50
- label: "Contexts"
51
- - url: "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsif"
52
- label: "jobs.<job_id>.steps[*].if"
53
- source:
54
- article: "https://htek.dev/articles/github-actions-debugging-guide"
55
- section: "Secrets in if conditions"
1
+ id: yaml-syntax-005
2
+ title: "secrets.* in if: Conditions — Silent Failures"
3
+ category: yaml-syntax
4
+ severity: silent-failure
5
+ tags:
6
+ - secrets
7
+ - if
8
+ - expressions
9
+ - contexts
10
+ - env
11
+ patterns:
12
+ - regex: "Unrecognized named-value: 'secrets'"
13
+ flags: "i"
14
+ - regex: "The workflow is not valid\\..*named-value: 'secrets'"
15
+ flags: "i"
16
+ - regex: "Context access might be invalid: secrets\\."
17
+ flags: "i"
18
+ error_messages:
19
+ - "Unrecognized named-value: 'secrets'"
20
+ root_cause: |
21
+ The `secrets` context is not available everywhere an expression can appear, and using
22
+ `secrets.*` directly inside an `if:` condition is a common trap. Depending on where the
23
+ expression is evaluated, GitHub Actions can reject the workflow or effectively treat the
24
+ check as unavailable.
25
+
26
+ The safe pattern is to map the secret into an environment variable first, then evaluate
27
+ the environment variable in the `if:` expression.
28
+ fix: |
29
+ Pass the secret through `env:` and reference `env.NAME` in the `if:`. This keeps the
30
+ conditional supported and avoids direct `secrets.*` access in the condition.
31
+ fix_code:
32
+ - language: yaml
33
+ label: "Gate a step using env instead of secrets directly"
34
+ code: |
35
+ jobs:
36
+ publish:
37
+ runs-on: ubuntu-latest
38
+ env:
39
+ HAS_TOKEN: ${{ secrets.NPM_TOKEN }}
40
+ steps:
41
+ - name: Publish
42
+ if: ${{ env.HAS_TOKEN != '' }}
43
+ run: npm publish
44
+ prevention:
45
+ - "Do not reference `secrets.*` directly in `if:` unless the docs explicitly allow that context."
46
+ - "Promote secrets into `env` when a step should be conditionally gated."
47
+ - "Check the contexts reference before using a context in expressions."
48
+ docs:
49
+ - url: "https://docs.github.com/en/actions/learn-github-actions/contexts"
50
+ label: "Contexts"
51
+ - url: "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsif"
52
+ label: "jobs.<job_id>.steps[*].if"
53
+ source:
54
+ article: "https://htek.dev/articles/github-actions-debugging-guide"
55
+ section: "Secrets in if conditions"
@@ -1,69 +1,69 @@
1
- id: yaml-syntax-001
2
- title: "Unexpected or Typo'd YAML Keys"
3
- category: yaml-syntax
4
- severity: error
5
- tags:
6
- - yaml
7
- - syntax
8
- - validation
9
- - keys
10
- - typos
11
- patterns:
12
- - regex: "Unexpected value '\\w+'"
13
- flags: "i"
14
- - regex: "unexpected key \"\\w+\" for step"
15
- flags: "i"
16
- - regex: "The workflow is not valid\\..*Unexpected value '\\w+'"
17
- flags: "i"
18
- error_messages:
19
- - "Unexpected value 'default'"
20
- - "Unexpected value 'Shell'"
21
- - "Unexpected value 'branch'"
22
- root_cause: |
23
- GitHub Actions workflow keys are schema-validated and case-sensitive. A typo like
24
- `default:` instead of `defaults:`, `Shell:` instead of `shell:`, or `branch:` instead
25
- of `branches:` is treated as an unknown key and the workflow is rejected before it runs.
26
-
27
- This usually happens when copying snippets from memory or mixing YAML conventions from
28
- other tools into GitHub Actions syntax.
29
- fix: |
30
- Replace the invalid key with the exact schema-supported key name. Double-check plural
31
- forms and casing against the workflow syntax reference.
32
-
33
- Common fixes:
34
- - `default:` -> `defaults:`
35
- - `Shell:` -> `shell:`
36
- - `branch:` -> `branches:`
37
- fix_code:
38
- - language: yaml
39
- label: "Use valid GitHub Actions keys"
40
- code: |
41
- name: CI
42
-
43
- on:
44
- push:
45
- branches:
46
- - main
47
-
48
- defaults:
49
- run:
50
- shell: bash
51
-
52
- jobs:
53
- test:
54
- runs-on: ubuntu-latest
55
- steps:
56
- - uses: actions/checkout@v4
57
- - run: npm test
58
- prevention:
59
- - "Validate workflow files against the GitHub Actions workflow syntax docs before committing."
60
- - "Prefer editing from working examples instead of typing keys from memory."
61
- - "Use code review checks for `defaults`, `shell`, and `branches` because those typos are common."
62
- docs:
63
- - url: "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions"
64
- label: "Workflow syntax for GitHub Actions"
65
- - url: "https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions"
66
- label: "Understanding GitHub Actions"
67
- source:
68
- article: "https://htek.dev/articles/github-actions-debugging-guide"
69
- section: "YAML validation and typo'd keys"
1
+ id: yaml-syntax-001
2
+ title: "Unexpected or Typo'd YAML Keys"
3
+ category: yaml-syntax
4
+ severity: error
5
+ tags:
6
+ - yaml
7
+ - syntax
8
+ - validation
9
+ - keys
10
+ - typos
11
+ patterns:
12
+ - regex: "Unexpected value '\\w+'"
13
+ flags: "i"
14
+ - regex: "unexpected key \"\\w+\" for step"
15
+ flags: "i"
16
+ - regex: "The workflow is not valid\\..*Unexpected value '\\w+'"
17
+ flags: "i"
18
+ error_messages:
19
+ - "Unexpected value 'default'"
20
+ - "Unexpected value 'Shell'"
21
+ - "Unexpected value 'branch'"
22
+ root_cause: |
23
+ GitHub Actions workflow keys are schema-validated and case-sensitive. A typo like
24
+ `default:` instead of `defaults:`, `Shell:` instead of `shell:`, or `branch:` instead
25
+ of `branches:` is treated as an unknown key and the workflow is rejected before it runs.
26
+
27
+ This usually happens when copying snippets from memory or mixing YAML conventions from
28
+ other tools into GitHub Actions syntax.
29
+ fix: |
30
+ Replace the invalid key with the exact schema-supported key name. Double-check plural
31
+ forms and casing against the workflow syntax reference.
32
+
33
+ Common fixes:
34
+ - `default:` -> `defaults:`
35
+ - `Shell:` -> `shell:`
36
+ - `branch:` -> `branches:`
37
+ fix_code:
38
+ - language: yaml
39
+ label: "Use valid GitHub Actions keys"
40
+ code: |
41
+ name: CI
42
+
43
+ on:
44
+ push:
45
+ branches:
46
+ - main
47
+
48
+ defaults:
49
+ run:
50
+ shell: bash
51
+
52
+ jobs:
53
+ test:
54
+ runs-on: ubuntu-latest
55
+ steps:
56
+ - uses: actions/checkout@v4
57
+ - run: npm test
58
+ prevention:
59
+ - "Validate workflow files against the GitHub Actions workflow syntax docs before committing."
60
+ - "Prefer editing from working examples instead of typing keys from memory."
61
+ - "Use code review checks for `defaults`, `shell`, and `branches` because those typos are common."
62
+ docs:
63
+ - url: "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions"
64
+ label: "Workflow syntax for GitHub Actions"
65
+ - url: "https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions"
66
+ label: "Understanding GitHub Actions"
67
+ source:
68
+ article: "https://htek.dev/articles/github-actions-debugging-guide"
69
+ section: "YAML validation and typo'd keys"
@@ -0,0 +1,66 @@
1
+ id: yaml-syntax-012
2
+ title: "working-directory Silently Ignored on uses: Action Steps"
3
+ category: yaml-syntax
4
+ severity: silent-failure
5
+ tags:
6
+ - working-directory
7
+ - uses
8
+ - run
9
+ - composite
10
+ - silent
11
+ - monorepo
12
+ patterns:
13
+ - regex: "working-directory"
14
+ flags: "i"
15
+ error_messages:
16
+ - "The key 'working-directory' is not valid for a step that uses an action."
17
+ root_cause: |
18
+ The `working-directory` step property only applies to `run:` steps. When set on a step
19
+ that uses `uses:`, GitHub Actions silently ignores it (or in stricter runtime versions,
20
+ emits a warning but still executes the action from its own checkout root).
21
+
22
+ This catches developers off-guard in monorepo setups where they try to scope an action
23
+ such as `actions/setup-node` to a subdirectory. The action always runs from the workspace
24
+ root regardless of `working-directory`.
25
+
26
+ If a custom composite action needs to operate in a specific directory, the caller must
27
+ pass the path as an `with:` input, or the composite action must use `cd` internally.
28
+ fix: |
29
+ Remove `working-directory` from any `uses:` step. Pass the directory as an explicit
30
+ `with:` input if the action supports it, or add a separate `run: cd path && ...` step.
31
+ fix_code:
32
+ - language: yaml
33
+ label: "WRONG — working-directory on a uses: step (silently ignored)"
34
+ code: |
35
+ steps:
36
+ - uses: actions/setup-node@v4
37
+ working-directory: ./packages/api # has no effect
38
+ with:
39
+ node-version: 20
40
+
41
+ - uses: ./.github/actions/lint
42
+ working-directory: ./packages/ui # also silently ignored
43
+ - language: yaml
44
+ label: "CORRECT — use an explicit run step to change directory first"
45
+ code: |
46
+ steps:
47
+ # setup-node always reads from workspace root
48
+ - uses: actions/setup-node@v4
49
+ with:
50
+ node-version: 20
51
+ cache: npm
52
+ cache-dependency-path: packages/api/package-lock.json
53
+
54
+ # For run: steps, working-directory works correctly
55
+ - name: Lint UI package
56
+ run: npx eslint .
57
+ working-directory: ./packages/ui
58
+ prevention:
59
+ - "Only use `working-directory` on `run:` steps — never on `uses:` steps."
60
+ - "For actions that need a path, look for a `path` or `working-directory` `with:` input in the action's README."
61
+ - "Run `actionlint` locally — it will flag `working-directory` on `uses:` steps."
62
+ docs:
63
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepswith"
64
+ label: "jobs.<job_id>.steps[*].with"
65
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun"
66
+ label: "jobs.<job_id>.steps[*].run"