@htekdev/actions-debugger 1.0.0 → 1.0.2

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 (58) 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/known-unsolved/workflow-rerun-limit.yml +101 -0
  21. package/errors/permissions-auth/checkout-submodule-private-auth.yml +91 -0
  22. package/errors/permissions-auth/fork-pr-secrets-unavailable.yml +97 -0
  23. package/errors/permissions-auth/gcp-oidc-workload-identity-misconfigured.yml +130 -0
  24. package/errors/permissions-auth/github-token-403.yml +64 -64
  25. package/errors/permissions-auth/github-token-protected-branch-push.yml +109 -0
  26. package/errors/permissions-auth/oidc-aws-failure.yml +85 -85
  27. package/errors/permissions-auth/oidc-azure-subject-mismatch.yml +91 -0
  28. package/errors/runner-environment/disk-space.yml +57 -57
  29. package/errors/runner-environment/docker-buildx-not-setup.yml +106 -0
  30. package/errors/runner-environment/macos-homebrew-path.yml +90 -0
  31. package/errors/runner-environment/node-runtime-deprecation.yml +56 -56
  32. package/errors/runner-environment/node20-to-node24-migration.yml +118 -0
  33. package/errors/runner-environment/npm-ci-lockfile-mismatch.yml +112 -0
  34. package/errors/runner-environment/self-hosted-stale-toolcache.yml +73 -0
  35. package/errors/runner-environment/setup-node-version-file-missing.yml +105 -0
  36. package/errors/runner-environment/windows-execution-policy.yml +83 -0
  37. package/errors/silent-failures/add-mask-no-retroactive-masking.yml +75 -0
  38. package/errors/silent-failures/composite-boolean-inputs-as-strings.yml +110 -0
  39. package/errors/silent-failures/conditional-output-null-downstream.yml +82 -0
  40. package/errors/silent-failures/continue-on-error-masks-failure.yml +86 -0
  41. package/errors/silent-failures/github-token-no-trigger.yml +57 -57
  42. package/errors/silent-failures/reusable-workflow-env-secrets-empty.yml +90 -0
  43. package/errors/silent-failures/scheduled-workflow-disabled.yml +59 -59
  44. package/errors/silent-failures/sparse-checkout-sticky-cone-mode.yml +120 -0
  45. package/errors/triggers/cron-schedule-late.yml +59 -59
  46. package/errors/triggers/pull-request-target-rce-risk.yml +117 -0
  47. package/errors/triggers/workflow-not-triggering.yml +60 -60
  48. package/errors/triggers/workflow-run-default-branch-requirement.yml +78 -0
  49. package/errors/yaml-syntax/anchors-not-supported.yml +95 -0
  50. package/errors/yaml-syntax/dynamic-matrix-fromjson-failure.yml +99 -0
  51. package/errors/yaml-syntax/if-always-true.yml +52 -52
  52. package/errors/yaml-syntax/missing-expression-wrapper.yml +67 -0
  53. package/errors/yaml-syntax/needs-indirect-outputs.yml +91 -0
  54. package/errors/yaml-syntax/reusable-workflow-missing-output-declaration.yml +140 -0
  55. package/errors/yaml-syntax/secrets-in-if.yml +55 -55
  56. package/errors/yaml-syntax/unexpected-yaml-key.yml +69 -69
  57. package/errors/yaml-syntax/working-directory-ignored-on-uses.yml +66 -0
  58. package/package.json +70 -67
@@ -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"
@@ -0,0 +1,140 @@
1
+ id: yaml-syntax-013
2
+ title: "Reusable Workflow Output Missing on.workflow_call.outputs Declaration"
3
+ category: yaml-syntax
4
+ severity: silent-failure
5
+ tags:
6
+ - reusable-workflow
7
+ - workflow-call
8
+ - outputs
9
+ - silent-failure
10
+ - job-outputs
11
+ patterns:
12
+ - regex: "needs\\.[a-zA-Z0-9_-]+\\.outputs\\.[a-zA-Z0-9_-]+"
13
+ flags: "i"
14
+ - regex: "on\\.workflow_call\\.outputs.*not defined"
15
+ flags: "i"
16
+ - regex: "output.*reusable.*workflow.*empty"
17
+ flags: "i"
18
+ error_messages:
19
+ - "The output variable was not found in the called workflow's on.workflow_call.outputs map."
20
+ - "Output 'version' not found in called workflow."
21
+ root_cause: |
22
+ A called (reusable) workflow exposes job-level outputs but forgets to declare them at
23
+ the `workflow_call` trigger level. As a result the caller workflow's
24
+ `needs.<called-job>.outputs.<name>` expression evaluates to an empty string with NO
25
+ error message — a silent failure.
26
+
27
+ GitHub Actions requires a two-layer output declaration for reusable workflows:
28
+ 1. The job inside the called workflow declares step outputs via `outputs:` on the job.
29
+ 2. The called workflow's `on.workflow_call.outputs:` section explicitly maps workflow-
30
+ level output names to job-level output expressions.
31
+
32
+ If layer 2 is missing, the caller never receives the value even though layer 1 exists.
33
+ Because the expression resolves to an empty string (not an error), downstream steps may
34
+ silently receive wrong values — version tags become empty strings, Docker image names
35
+ become malformed, deploy environment names become blank.
36
+
37
+ A second variant occurs when accessing outputs from a called workflow that uses a matrix:
38
+ matrix job outputs cannot be aggregated automatically at the workflow level, so outputs
39
+ from individual matrix legs are inaccessible to the caller.
40
+ fix: |
41
+ Add the `on.workflow_call.outputs:` section to the called workflow, mapping each
42
+ desired output name to the corresponding job output expression.
43
+
44
+ For matrix jobs: aggregate outputs into a single job (e.g. using `toJSON`) or use a
45
+ final non-matrix aggregator job inside the called workflow that reads matrix outputs
46
+ and re-exposes them as a single value.
47
+ fix_code:
48
+ - language: yaml
49
+ label: "Called workflow — correct two-layer output declaration"
50
+ code: |
51
+ # .github/workflows/build-and-version.yml (CALLED workflow)
52
+ on:
53
+ workflow_call:
54
+ # Layer 2: workflow-level outputs (REQUIRED for caller to receive values)
55
+ outputs:
56
+ version:
57
+ description: "The computed version string"
58
+ value: ${{ jobs.build.outputs.version }}
59
+ artifact-name:
60
+ description: "Name of the uploaded artifact"
61
+ value: ${{ jobs.build.outputs.artifact-name }}
62
+
63
+ jobs:
64
+ build:
65
+ runs-on: ubuntu-latest
66
+ # Layer 1: job-level outputs
67
+ outputs:
68
+ version: ${{ steps.compute-version.outputs.version }}
69
+ artifact-name: ${{ steps.upload.outputs.artifact-name }}
70
+ steps:
71
+ - id: compute-version
72
+ run: echo "version=1.2.3-${{ github.sha }}" >> $GITHUB_OUTPUT
73
+
74
+ - id: upload
75
+ uses: actions/upload-artifact@v4
76
+ with:
77
+ name: build-output
78
+ path: dist/
79
+ - language: yaml
80
+ label: "Caller workflow — consuming outputs from called workflow"
81
+ code: |
82
+ # .github/workflows/deploy.yml (CALLER workflow)
83
+ jobs:
84
+ build:
85
+ uses: ./.github/workflows/build-and-version.yml
86
+ secrets: inherit
87
+
88
+ deploy:
89
+ needs: build
90
+ runs-on: ubuntu-latest
91
+ steps:
92
+ - name: Deploy version
93
+ # This only works if the called workflow has on.workflow_call.outputs declared
94
+ run: |
95
+ echo "Deploying version: ${{ needs.build.outputs.version }}"
96
+ echo "Using artifact: ${{ needs.build.outputs.artifact-name }}"
97
+ - language: yaml
98
+ label: "Aggregate matrix outputs in a final job for caller consumption"
99
+ code: |
100
+ # Called workflow with matrix — aggregate results before exposing as outputs
101
+ on:
102
+ workflow_call:
103
+ outputs:
104
+ all-results:
105
+ value: ${{ jobs.aggregate.outputs.results }}
106
+
107
+ jobs:
108
+ test:
109
+ runs-on: ubuntu-latest
110
+ strategy:
111
+ matrix:
112
+ suite: [unit, integration, e2e]
113
+ outputs:
114
+ result-${{ matrix.suite }}: ${{ steps.run.outputs.result }}
115
+ steps:
116
+ - id: run
117
+ run: echo "result=passed" >> $GITHUB_OUTPUT
118
+
119
+ # Aggregator job: collects matrix outputs and re-exposes as single value
120
+ aggregate:
121
+ needs: test
122
+ runs-on: ubuntu-latest
123
+ outputs:
124
+ results: ${{ steps.collect.outputs.results }}
125
+ steps:
126
+ - id: collect
127
+ run: |
128
+ echo "results=${{ toJSON(needs.test.outputs) }}" >> $GITHUB_OUTPUT
129
+ prevention:
130
+ - "Always declare `on.workflow_call.outputs:` in a reusable workflow if any caller needs its outputs."
131
+ - "Test output propagation by printing `${{ needs.<job>.outputs.<name> }}` in a debug step on the caller side."
132
+ - "Treat empty string outputs from called workflows as a sign of missing `on.workflow_call.outputs:` mapping."
133
+ - "Matrix jobs inside called workflows require an aggregator job — matrix outputs cannot be directly mapped."
134
+ docs:
135
+ - url: "https://docs.github.com/en/actions/sharing-automations/reusing-workflows#using-outputs-from-a-reusable-workflow"
136
+ label: "Reusable workflows: using outputs"
137
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#onworkflow_calloutputs"
138
+ label: "Workflow syntax: on.workflow_call.outputs"
139
+ - url: "https://stackoverflow.com/questions/73702333/github-actions-reuse-outputs-from-other-reusable-workflows"
140
+ label: "Stack Overflow: Reuse outputs from reusable workflows (82 upvotes)"
@@ -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"