@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.
- package/LICENSE +21 -21
- package/README.md +108 -108
- package/errors/_schema.json +89 -89
- package/errors/caching-artifacts/artifact-storage-quota-exceeded.yml +118 -0
- package/errors/caching-artifacts/cache-miss.yml +56 -56
- package/errors/caching-artifacts/cache-save-cancelled-job.yml +82 -0
- package/errors/caching-artifacts/cache-v3-to-v4-breaking-changes.yml +95 -0
- package/errors/caching-artifacts/cross-repo-artifacts-not-supported.yml +102 -0
- package/errors/caching-artifacts/upload-artifact-no-files-found.yml +92 -0
- package/errors/caching-artifacts/upload-artifact-v4-breaking.yml +67 -67
- package/errors/concurrency-timing/cancel-in-progress-deploy-drops.yml +97 -0
- package/errors/concurrency-timing/jobs-cancelled-unexpectedly.yml +60 -60
- package/errors/concurrency-timing/skipped-needs-cascade.yml +103 -0
- package/errors/concurrency-timing/workflow-run-conclusion-unchecked.yml +100 -0
- package/errors/known-unsolved/composite-input-env-vars-missing.yml +91 -0
- package/errors/known-unsolved/composite-nested-outputs-null.yml +101 -0
- package/errors/known-unsolved/no-dynamic-secret-access.yml +111 -0
- package/errors/known-unsolved/no-step-level-rerun.yml +94 -0
- package/errors/known-unsolved/no-step-retry.yml +53 -53
- package/errors/permissions-auth/checkout-submodule-private-auth.yml +91 -0
- package/errors/permissions-auth/fork-pr-secrets-unavailable.yml +97 -0
- package/errors/permissions-auth/github-token-403.yml +64 -64
- package/errors/permissions-auth/github-token-protected-branch-push.yml +109 -0
- package/errors/permissions-auth/oidc-aws-failure.yml +85 -85
- package/errors/permissions-auth/oidc-azure-subject-mismatch.yml +91 -0
- package/errors/runner-environment/disk-space.yml +57 -57
- package/errors/runner-environment/docker-buildx-not-setup.yml +106 -0
- package/errors/runner-environment/macos-homebrew-path.yml +90 -0
- package/errors/runner-environment/node-runtime-deprecation.yml +56 -56
- package/errors/runner-environment/npm-ci-lockfile-mismatch.yml +112 -0
- package/errors/runner-environment/self-hosted-stale-toolcache.yml +73 -0
- package/errors/runner-environment/setup-node-version-file-missing.yml +105 -0
- package/errors/runner-environment/windows-execution-policy.yml +83 -0
- package/errors/silent-failures/add-mask-no-retroactive-masking.yml +75 -0
- package/errors/silent-failures/composite-boolean-inputs-as-strings.yml +110 -0
- package/errors/silent-failures/conditional-output-null-downstream.yml +82 -0
- package/errors/silent-failures/continue-on-error-masks-failure.yml +86 -0
- package/errors/silent-failures/github-token-no-trigger.yml +57 -57
- package/errors/silent-failures/reusable-workflow-env-secrets-empty.yml +90 -0
- package/errors/silent-failures/scheduled-workflow-disabled.yml +59 -59
- package/errors/triggers/cron-schedule-late.yml +59 -59
- package/errors/triggers/pull-request-target-rce-risk.yml +117 -0
- package/errors/triggers/workflow-not-triggering.yml +60 -60
- package/errors/triggers/workflow-run-default-branch-requirement.yml +78 -0
- package/errors/yaml-syntax/anchors-not-supported.yml +95 -0
- package/errors/yaml-syntax/dynamic-matrix-fromjson-failure.yml +99 -0
- package/errors/yaml-syntax/if-always-true.yml +52 -52
- package/errors/yaml-syntax/missing-expression-wrapper.yml +67 -0
- package/errors/yaml-syntax/needs-indirect-outputs.yml +91 -0
- package/errors/yaml-syntax/secrets-in-if.yml +55 -55
- package/errors/yaml-syntax/unexpected-yaml-key.yml +69 -69
- package/errors/yaml-syntax/working-directory-ignored-on-uses.yml +66 -0
- 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"
|