@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.
- 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/known-unsolved/workflow-rerun-limit.yml +101 -0
- 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/gcp-oidc-workload-identity-misconfigured.yml +130 -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/node20-to-node24-migration.yml +118 -0
- 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/silent-failures/sparse-checkout-sticky-cone-mode.yml +120 -0
- 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/reusable-workflow-missing-output-declaration.yml +140 -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
|
@@ -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"
|