@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,59 +1,59 @@
|
|
|
1
|
-
id: triggers-003
|
|
2
|
-
title: "Cron Schedule Running Late or Not Running"
|
|
3
|
-
category: triggers
|
|
4
|
-
severity: warning
|
|
5
|
-
tags:
|
|
6
|
-
- cron
|
|
7
|
-
- schedule
|
|
8
|
-
- delay
|
|
9
|
-
- forks
|
|
10
|
-
- best-effort
|
|
11
|
-
patterns:
|
|
12
|
-
- regex: "schedule"
|
|
13
|
-
flags: "i"
|
|
14
|
-
- regex: "Delayed"
|
|
15
|
-
flags: "i"
|
|
16
|
-
- regex: "This event will only trigger a workflow run if the workflow file exists on the default branch"
|
|
17
|
-
flags: "i"
|
|
18
|
-
error_messages:
|
|
19
|
-
- "Scheduled workflows can be delayed during periods of high loads of GitHub Actions workflow runs."
|
|
20
|
-
root_cause: |
|
|
21
|
-
GitHub Actions cron is best-effort, not real-time scheduling. During peak usage windows,
|
|
22
|
-
scheduled workflows can start 15 to 45 minutes late. In forks, scheduled workflows are also
|
|
23
|
-
disabled by default, so a copied workflow may never run until someone explicitly enables it.
|
|
24
|
-
|
|
25
|
-
The YAML can be correct and the repository can still see timing drift because the platform
|
|
26
|
-
does not guarantee precise minute-by-minute execution.
|
|
27
|
-
fix: |
|
|
28
|
-
Treat cron timing as approximate. Schedule important automations away from the top of the
|
|
29
|
-
hour, add tolerance for startup drift, and provide a `workflow_dispatch` fallback for jobs
|
|
30
|
-
that sometimes need manual recovery.
|
|
31
|
-
fix_code:
|
|
32
|
-
- language: yaml
|
|
33
|
-
label: "Add jitter-friendly scheduling and manual fallback"
|
|
34
|
-
code: |
|
|
35
|
-
name: Nightly maintenance
|
|
36
|
-
|
|
37
|
-
on:
|
|
38
|
-
schedule:
|
|
39
|
-
- cron: '17 3 * * *'
|
|
40
|
-
workflow_dispatch:
|
|
41
|
-
|
|
42
|
-
jobs:
|
|
43
|
-
maintain:
|
|
44
|
-
runs-on: ubuntu-latest
|
|
45
|
-
steps:
|
|
46
|
-
- uses: actions/checkout@v4
|
|
47
|
-
- run: ./scripts/maintenance.sh
|
|
48
|
-
prevention:
|
|
49
|
-
- "Avoid scheduling critical jobs exactly at minute 0 because that is a common contention window."
|
|
50
|
-
- "Use external monitoring if a schedule must be near-real-time."
|
|
51
|
-
- "Enable scheduled workflows manually after creating a fork or after long inactivity."
|
|
52
|
-
docs:
|
|
53
|
-
- url: "https://docs.github.com/en/actions/reference/events-that-trigger-workflows#schedule"
|
|
54
|
-
label: "schedule event"
|
|
55
|
-
- url: "https://docs.github.com/en/actions/managing-workflow-runs/disabling-and-enabling-a-workflow"
|
|
56
|
-
label: "Disable and enable a workflow"
|
|
57
|
-
source:
|
|
58
|
-
article: "https://htek.dev/articles/github-actions-debugging-guide"
|
|
59
|
-
section: "Cron schedules running late"
|
|
1
|
+
id: triggers-003
|
|
2
|
+
title: "Cron Schedule Running Late or Not Running"
|
|
3
|
+
category: triggers
|
|
4
|
+
severity: warning
|
|
5
|
+
tags:
|
|
6
|
+
- cron
|
|
7
|
+
- schedule
|
|
8
|
+
- delay
|
|
9
|
+
- forks
|
|
10
|
+
- best-effort
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: "schedule"
|
|
13
|
+
flags: "i"
|
|
14
|
+
- regex: "Delayed"
|
|
15
|
+
flags: "i"
|
|
16
|
+
- regex: "This event will only trigger a workflow run if the workflow file exists on the default branch"
|
|
17
|
+
flags: "i"
|
|
18
|
+
error_messages:
|
|
19
|
+
- "Scheduled workflows can be delayed during periods of high loads of GitHub Actions workflow runs."
|
|
20
|
+
root_cause: |
|
|
21
|
+
GitHub Actions cron is best-effort, not real-time scheduling. During peak usage windows,
|
|
22
|
+
scheduled workflows can start 15 to 45 minutes late. In forks, scheduled workflows are also
|
|
23
|
+
disabled by default, so a copied workflow may never run until someone explicitly enables it.
|
|
24
|
+
|
|
25
|
+
The YAML can be correct and the repository can still see timing drift because the platform
|
|
26
|
+
does not guarantee precise minute-by-minute execution.
|
|
27
|
+
fix: |
|
|
28
|
+
Treat cron timing as approximate. Schedule important automations away from the top of the
|
|
29
|
+
hour, add tolerance for startup drift, and provide a `workflow_dispatch` fallback for jobs
|
|
30
|
+
that sometimes need manual recovery.
|
|
31
|
+
fix_code:
|
|
32
|
+
- language: yaml
|
|
33
|
+
label: "Add jitter-friendly scheduling and manual fallback"
|
|
34
|
+
code: |
|
|
35
|
+
name: Nightly maintenance
|
|
36
|
+
|
|
37
|
+
on:
|
|
38
|
+
schedule:
|
|
39
|
+
- cron: '17 3 * * *'
|
|
40
|
+
workflow_dispatch:
|
|
41
|
+
|
|
42
|
+
jobs:
|
|
43
|
+
maintain:
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@v4
|
|
47
|
+
- run: ./scripts/maintenance.sh
|
|
48
|
+
prevention:
|
|
49
|
+
- "Avoid scheduling critical jobs exactly at minute 0 because that is a common contention window."
|
|
50
|
+
- "Use external monitoring if a schedule must be near-real-time."
|
|
51
|
+
- "Enable scheduled workflows manually after creating a fork or after long inactivity."
|
|
52
|
+
docs:
|
|
53
|
+
- url: "https://docs.github.com/en/actions/reference/events-that-trigger-workflows#schedule"
|
|
54
|
+
label: "schedule event"
|
|
55
|
+
- url: "https://docs.github.com/en/actions/managing-workflow-runs/disabling-and-enabling-a-workflow"
|
|
56
|
+
label: "Disable and enable a workflow"
|
|
57
|
+
source:
|
|
58
|
+
article: "https://htek.dev/articles/github-actions-debugging-guide"
|
|
59
|
+
section: "Cron schedules running late"
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
id: triggers-005
|
|
2
|
+
title: "pull_request_target Runs Fork Code with Base Branch Secrets — RCE Risk"
|
|
3
|
+
category: triggers
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- pull_request_target
|
|
7
|
+
- security
|
|
8
|
+
- fork
|
|
9
|
+
- secrets
|
|
10
|
+
- code-injection
|
|
11
|
+
- pwn-request
|
|
12
|
+
- base-branch
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: "pull_request_target"
|
|
15
|
+
flags: "i"
|
|
16
|
+
- regex: "github\\.event\\.pull_request\\.head\\.sha"
|
|
17
|
+
flags: "i"
|
|
18
|
+
error_messages:
|
|
19
|
+
- "Warning: Workflow uses pull_request_target with actions/checkout on PR head — potential code injection vulnerability."
|
|
20
|
+
root_cause: |
|
|
21
|
+
`pull_request_target` was designed to give workflows triggered by fork PRs access to
|
|
22
|
+
**base branch secrets and write permissions**. Unlike `pull_request`, it runs in the
|
|
23
|
+
context of the **base repository**, not the fork — so `secrets.*` is available and
|
|
24
|
+
`GITHUB_TOKEN` has write permissions.
|
|
25
|
+
|
|
26
|
+
The danger: many developers combine `pull_request_target` with
|
|
27
|
+
`actions/checkout@v4 ref: ${{ github.event.pull_request.head.sha }}` to check out the
|
|
28
|
+
**fork's code** for testing. Running untrusted fork code with full secret access is a
|
|
29
|
+
critical Remote Code Execution (RCE) vulnerability — the contributor can exfiltrate
|
|
30
|
+
all repository secrets simply by adding malicious code to their PR.
|
|
31
|
+
|
|
32
|
+
This class of vulnerability is known as "pwn request" and has been exploited against
|
|
33
|
+
major open-source projects.
|
|
34
|
+
fix: |
|
|
35
|
+
When using `pull_request_target`, ALWAYS check out the base branch (not the PR head).
|
|
36
|
+
If you need to run the PR author's code AND have secret access, use a two-workflow pattern:
|
|
37
|
+
an unprivileged `pull_request` workflow builds and uploads artifacts, then a privileged
|
|
38
|
+
`workflow_run` workflow (with no access to fork code) deploys them.
|
|
39
|
+
fix_code:
|
|
40
|
+
- language: yaml
|
|
41
|
+
label: "CRITICAL VULNERABILITY — checkout of fork code with secret access"
|
|
42
|
+
code: |
|
|
43
|
+
on: pull_request_target # has secret access
|
|
44
|
+
|
|
45
|
+
jobs:
|
|
46
|
+
test:
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
steps:
|
|
49
|
+
# DANGEROUS: checking out untrusted PR code with base repo secrets
|
|
50
|
+
- uses: actions/checkout@v4
|
|
51
|
+
with:
|
|
52
|
+
ref: ${{ github.event.pull_request.head.sha }} # NEVER DO THIS
|
|
53
|
+
- run: npm test # attacker's code runs with your secrets
|
|
54
|
+
- language: yaml
|
|
55
|
+
label: "SAFE — pull_request_target checking out base only (for labels/comments)"
|
|
56
|
+
code: |
|
|
57
|
+
on:
|
|
58
|
+
pull_request_target:
|
|
59
|
+
types: [opened, labeled]
|
|
60
|
+
|
|
61
|
+
jobs:
|
|
62
|
+
label:
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
permissions:
|
|
65
|
+
pull-requests: write
|
|
66
|
+
steps:
|
|
67
|
+
# SAFE: checking out base repo code only (not the PR branch)
|
|
68
|
+
- uses: actions/checkout@v4
|
|
69
|
+
# No 'ref:' — defaults to base branch
|
|
70
|
+
- name: Add label
|
|
71
|
+
uses: actions-ecosystem/action-add-labels@v1
|
|
72
|
+
with:
|
|
73
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
74
|
+
labels: needs-review
|
|
75
|
+
- language: yaml
|
|
76
|
+
label: "SAFE — two-workflow pattern: build unprivileged, deploy privileged"
|
|
77
|
+
code: |
|
|
78
|
+
# Workflow 1: ci.yml — triggered by pull_request (no secrets, untrusted code OK)
|
|
79
|
+
on: pull_request
|
|
80
|
+
jobs:
|
|
81
|
+
build:
|
|
82
|
+
runs-on: ubuntu-latest
|
|
83
|
+
steps:
|
|
84
|
+
- uses: actions/checkout@v4 # fork code, but no secrets
|
|
85
|
+
- run: npm ci && npm run build
|
|
86
|
+
- uses: actions/upload-artifact@v4
|
|
87
|
+
with:
|
|
88
|
+
name: build-output
|
|
89
|
+
path: dist/
|
|
90
|
+
|
|
91
|
+
# Workflow 2: deploy-pr-preview.yml — triggered by workflow_run (has secrets, no fork code)
|
|
92
|
+
on:
|
|
93
|
+
workflow_run:
|
|
94
|
+
workflows: [CI]
|
|
95
|
+
types: [completed]
|
|
96
|
+
jobs:
|
|
97
|
+
deploy:
|
|
98
|
+
runs-on: ubuntu-latest
|
|
99
|
+
if: github.event.workflow_run.conclusion == 'success'
|
|
100
|
+
steps:
|
|
101
|
+
- uses: actions/download-artifact@v4 # downloads artifact, not fork code
|
|
102
|
+
with:
|
|
103
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
104
|
+
run-id: ${{ github.event.workflow_run.id }}
|
|
105
|
+
name: build-output
|
|
106
|
+
- run: ./deploy-preview.sh # safe: runs base repo script with downloaded artifact
|
|
107
|
+
prevention:
|
|
108
|
+
- "NEVER use `actions/checkout ref: github.event.pull_request.head.sha` inside a `pull_request_target` workflow."
|
|
109
|
+
- "Use the two-workflow pattern (unprivileged `pull_request` + privileged `workflow_run`) for PR preview deployments."
|
|
110
|
+
- "Restrict `pull_request_target` to safe operations: labeling, commenting, and running base repo scripts only."
|
|
111
|
+
docs:
|
|
112
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request_target"
|
|
113
|
+
label: "pull_request_target event"
|
|
114
|
+
- url: "https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/"
|
|
115
|
+
label: "Preventing pwn requests (GitHub Security Lab)"
|
|
116
|
+
- url: "https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#understanding-the-risk-of-script-injections"
|
|
117
|
+
label: "Security hardening — script injection"
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
id: triggers-001
|
|
2
|
-
title: "Workflow Not Triggering At All"
|
|
3
|
-
category: triggers
|
|
4
|
-
severity: error
|
|
5
|
-
tags:
|
|
6
|
-
- triggers
|
|
7
|
-
- workflow-file
|
|
8
|
-
- default-branch
|
|
9
|
-
- on
|
|
10
|
-
- events
|
|
11
|
-
patterns:
|
|
12
|
-
- regex: "This event will only trigger a workflow run if the workflow file exists on the default branch"
|
|
13
|
-
flags: "i"
|
|
14
|
-
- regex: "Workflow file .* not found on the default branch"
|
|
15
|
-
flags: "i"
|
|
16
|
-
- regex: "No runs found for this workflow"
|
|
17
|
-
flags: "i"
|
|
18
|
-
error_messages:
|
|
19
|
-
- "This event will only trigger a workflow run if the workflow file exists on the default branch"
|
|
20
|
-
root_cause: |
|
|
21
|
-
Some events only trigger if the workflow file itself exists on the repository's default
|
|
22
|
-
branch. A workflow can look perfectly valid in a feature branch, but GitHub will ignore it
|
|
23
|
-
for certain event types until the file is present on the default branch with correct `on:`
|
|
24
|
-
syntax and placement under `.github/workflows/`.
|
|
25
|
-
|
|
26
|
-
A wrong indentation level under `on:`, a typo in the event name, or putting the file in the
|
|
27
|
-
wrong directory can create the same symptom: nothing runs.
|
|
28
|
-
fix: |
|
|
29
|
-
Confirm the workflow file lives in `.github/workflows/`, validate the `on:` block, and make
|
|
30
|
-
sure the workflow file already exists on the default branch for the event you expect to fire.
|
|
31
|
-
fix_code:
|
|
32
|
-
- language: yaml
|
|
33
|
-
label: "Use valid workflow location and trigger syntax"
|
|
34
|
-
code: |
|
|
35
|
-
name: CI
|
|
36
|
-
|
|
37
|
-
on:
|
|
38
|
-
push:
|
|
39
|
-
branches:
|
|
40
|
-
- main
|
|
41
|
-
pull_request:
|
|
42
|
-
|
|
43
|
-
jobs:
|
|
44
|
-
test:
|
|
45
|
-
runs-on: ubuntu-latest
|
|
46
|
-
steps:
|
|
47
|
-
- uses: actions/checkout@v4
|
|
48
|
-
- run: npm test
|
|
49
|
-
prevention:
|
|
50
|
-
- "Keep workflow files only under `.github/workflows/`."
|
|
51
|
-
- "Merge new workflow files to the default branch before relying on events like `schedule` or `workflow_dispatch`."
|
|
52
|
-
- "Validate event names and indentation in every `on:` block."
|
|
53
|
-
docs:
|
|
54
|
-
- url: "https://docs.github.com/en/actions/reference/events-that-trigger-workflows"
|
|
55
|
-
label: "Events that trigger workflows"
|
|
56
|
-
- url: "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions"
|
|
57
|
-
label: "Workflow syntax for GitHub Actions"
|
|
58
|
-
source:
|
|
59
|
-
article: "https://htek.dev/articles/github-actions-debugging-guide"
|
|
60
|
-
section: "Workflow not triggering"
|
|
1
|
+
id: triggers-001
|
|
2
|
+
title: "Workflow Not Triggering At All"
|
|
3
|
+
category: triggers
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- triggers
|
|
7
|
+
- workflow-file
|
|
8
|
+
- default-branch
|
|
9
|
+
- on
|
|
10
|
+
- events
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: "This event will only trigger a workflow run if the workflow file exists on the default branch"
|
|
13
|
+
flags: "i"
|
|
14
|
+
- regex: "Workflow file .* not found on the default branch"
|
|
15
|
+
flags: "i"
|
|
16
|
+
- regex: "No runs found for this workflow"
|
|
17
|
+
flags: "i"
|
|
18
|
+
error_messages:
|
|
19
|
+
- "This event will only trigger a workflow run if the workflow file exists on the default branch"
|
|
20
|
+
root_cause: |
|
|
21
|
+
Some events only trigger if the workflow file itself exists on the repository's default
|
|
22
|
+
branch. A workflow can look perfectly valid in a feature branch, but GitHub will ignore it
|
|
23
|
+
for certain event types until the file is present on the default branch with correct `on:`
|
|
24
|
+
syntax and placement under `.github/workflows/`.
|
|
25
|
+
|
|
26
|
+
A wrong indentation level under `on:`, a typo in the event name, or putting the file in the
|
|
27
|
+
wrong directory can create the same symptom: nothing runs.
|
|
28
|
+
fix: |
|
|
29
|
+
Confirm the workflow file lives in `.github/workflows/`, validate the `on:` block, and make
|
|
30
|
+
sure the workflow file already exists on the default branch for the event you expect to fire.
|
|
31
|
+
fix_code:
|
|
32
|
+
- language: yaml
|
|
33
|
+
label: "Use valid workflow location and trigger syntax"
|
|
34
|
+
code: |
|
|
35
|
+
name: CI
|
|
36
|
+
|
|
37
|
+
on:
|
|
38
|
+
push:
|
|
39
|
+
branches:
|
|
40
|
+
- main
|
|
41
|
+
pull_request:
|
|
42
|
+
|
|
43
|
+
jobs:
|
|
44
|
+
test:
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v4
|
|
48
|
+
- run: npm test
|
|
49
|
+
prevention:
|
|
50
|
+
- "Keep workflow files only under `.github/workflows/`."
|
|
51
|
+
- "Merge new workflow files to the default branch before relying on events like `schedule` or `workflow_dispatch`."
|
|
52
|
+
- "Validate event names and indentation in every `on:` block."
|
|
53
|
+
docs:
|
|
54
|
+
- url: "https://docs.github.com/en/actions/reference/events-that-trigger-workflows"
|
|
55
|
+
label: "Events that trigger workflows"
|
|
56
|
+
- url: "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions"
|
|
57
|
+
label: "Workflow syntax for GitHub Actions"
|
|
58
|
+
source:
|
|
59
|
+
article: "https://htek.dev/articles/github-actions-debugging-guide"
|
|
60
|
+
section: "Workflow not triggering"
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
id: triggers-004
|
|
2
|
+
title: "workflow_run Trigger Fires Only When Source Workflow Exists on Default Branch"
|
|
3
|
+
category: triggers
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- workflow_run
|
|
7
|
+
- triggers
|
|
8
|
+
- default-branch
|
|
9
|
+
- main
|
|
10
|
+
- workflow-file
|
|
11
|
+
- not-triggering
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: "workflow_run.*not triggering"
|
|
14
|
+
flags: "i"
|
|
15
|
+
- regex: "workflow_run.*workflow.*not found"
|
|
16
|
+
flags: "i"
|
|
17
|
+
error_messages:
|
|
18
|
+
- "The workflow 'CI' referenced by workflow_run trigger was not found or does not exist on the default branch."
|
|
19
|
+
root_cause: |
|
|
20
|
+
GitHub resolves `workflow_run` triggers by looking up the **source workflow's file name
|
|
21
|
+
on the repository's default branch** at trigger time. This has two important implications:
|
|
22
|
+
|
|
23
|
+
1. **The source workflow file must exist on the default branch** — a `workflow_run` trigger
|
|
24
|
+
in a PR branch will not fire when the referenced workflow runs on that branch, if the
|
|
25
|
+
source workflow file doesn't exist on `main`/`master` yet.
|
|
26
|
+
|
|
27
|
+
2. **The trigger workflow itself must also be on the default branch** — the `workflow_run`
|
|
28
|
+
trigger in `on:` is only read from the default branch, regardless of which branch
|
|
29
|
+
the triggering push happened on.
|
|
30
|
+
|
|
31
|
+
This is a common blocker during initial feature development: a developer adds both the
|
|
32
|
+
source workflow and the `workflow_run` consumer in the same PR branch. Neither fires
|
|
33
|
+
correctly until both files are merged to the default branch.
|
|
34
|
+
fix: |
|
|
35
|
+
Ensure both the source workflow and the `workflow_run` consumer exist on the default
|
|
36
|
+
branch before testing. When adding new CI workflows, merge to main/master first, then
|
|
37
|
+
test from a feature branch.
|
|
38
|
+
fix_code:
|
|
39
|
+
- language: yaml
|
|
40
|
+
label: "Example workflow_run trigger — source must be on default branch"
|
|
41
|
+
code: |
|
|
42
|
+
# .github/workflows/deploy.yml (must be on default branch to work)
|
|
43
|
+
on:
|
|
44
|
+
workflow_run:
|
|
45
|
+
workflows: ["CI"] # "CI" must match the 'name:' field in ci.yml
|
|
46
|
+
types: [completed] # fires when CI workflow completes (any branch)
|
|
47
|
+
branches: [main] # optional: only when CI ran on these branches
|
|
48
|
+
|
|
49
|
+
jobs:
|
|
50
|
+
deploy:
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
|
53
|
+
steps:
|
|
54
|
+
- run: ./deploy.sh
|
|
55
|
+
- language: yaml
|
|
56
|
+
label: "Check workflow name matches exactly (case-sensitive)"
|
|
57
|
+
code: |
|
|
58
|
+
# .github/workflows/ci.yml
|
|
59
|
+
name: CI # this exact string must match workflow_run trigger
|
|
60
|
+
|
|
61
|
+
on:
|
|
62
|
+
push:
|
|
63
|
+
branches: [main, 'feature/**']
|
|
64
|
+
|
|
65
|
+
jobs:
|
|
66
|
+
build:
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
steps:
|
|
69
|
+
- run: npm test
|
|
70
|
+
prevention:
|
|
71
|
+
- "Merge the source workflow to the default branch before adding a `workflow_run` consumer — test with both files on `main`."
|
|
72
|
+
- "The `workflows:` list matches on the workflow's `name:` field (the YAML `name:` key), not the filename."
|
|
73
|
+
- "Use `branches:` filter in `workflow_run` to prevent deploy from triggering on every feature branch run."
|
|
74
|
+
docs:
|
|
75
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_run"
|
|
76
|
+
label: "workflow_run trigger"
|
|
77
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/triggering-a-workflow#triggering-a-workflow-from-a-workflow"
|
|
78
|
+
label: "Triggering a workflow from a workflow"
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
id: yaml-syntax-009
|
|
2
|
+
title: "YAML Anchors and Aliases Rejected by Workflow Parser"
|
|
3
|
+
category: yaml-syntax
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- yaml
|
|
7
|
+
- anchors
|
|
8
|
+
- aliases
|
|
9
|
+
- dry
|
|
10
|
+
- reuse
|
|
11
|
+
- syntax
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: "Anchors are not supported"
|
|
14
|
+
flags: "i"
|
|
15
|
+
- regex: "could not parse the yaml file"
|
|
16
|
+
flags: "i"
|
|
17
|
+
- regex: "mapping values are not allowed in this context"
|
|
18
|
+
flags: "i"
|
|
19
|
+
error_messages:
|
|
20
|
+
- "The workflow is not valid. .github/workflows/ci.yml: Anchors are not supported."
|
|
21
|
+
- "could not parse the yaml file '.github/workflows/ci.yml'"
|
|
22
|
+
root_cause: |
|
|
23
|
+
GitHub Actions' workflow parser explicitly rejects YAML anchors (`&`) and aliases (`*`)
|
|
24
|
+
even though they are valid YAML 1.2 constructs. Developers familiar with Docker Compose
|
|
25
|
+
or Kubernetes manifests commonly attempt to DRY up repetitive step blocks using anchors
|
|
26
|
+
and merge keys (`<<: *defaults`), but the GitHub-hosted workflow validator rejects the
|
|
27
|
+
file on parse rather than silently ignoring the constructs.
|
|
28
|
+
|
|
29
|
+
The restriction is documented and intentional — GitHub's parser does not implement the
|
|
30
|
+
full YAML 1.2 merge-key extension.
|
|
31
|
+
fix: |
|
|
32
|
+
Remove all YAML anchors and aliases from workflow files. Use one of GitHub Actions'
|
|
33
|
+
native reuse mechanisms instead: composite actions for shared step sequences, reusable
|
|
34
|
+
workflows (`workflow_call`) for sharing entire job graphs, or a matrix strategy for
|
|
35
|
+
parameterized repetition.
|
|
36
|
+
fix_code:
|
|
37
|
+
- language: yaml
|
|
38
|
+
label: "WRONG — YAML anchor and merge key (rejected)"
|
|
39
|
+
code: |
|
|
40
|
+
.defaults: &defaults
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
timeout-minutes: 10
|
|
43
|
+
|
|
44
|
+
jobs:
|
|
45
|
+
build:
|
|
46
|
+
<<: *defaults
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@v4
|
|
49
|
+
- run: npm ci && npm run build
|
|
50
|
+
|
|
51
|
+
test:
|
|
52
|
+
<<: *defaults
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@v4
|
|
55
|
+
- run: npm test
|
|
56
|
+
- language: yaml
|
|
57
|
+
label: "CORRECT — composite action for shared steps"
|
|
58
|
+
code: |
|
|
59
|
+
# .github/actions/setup/action.yml
|
|
60
|
+
name: Setup
|
|
61
|
+
runs:
|
|
62
|
+
using: composite
|
|
63
|
+
steps:
|
|
64
|
+
- uses: actions/checkout@v4
|
|
65
|
+
- uses: actions/setup-node@v4
|
|
66
|
+
with:
|
|
67
|
+
node-version: 20
|
|
68
|
+
cache: npm
|
|
69
|
+
|
|
70
|
+
# .github/workflows/ci.yml
|
|
71
|
+
jobs:
|
|
72
|
+
build:
|
|
73
|
+
runs-on: ubuntu-latest
|
|
74
|
+
timeout-minutes: 10
|
|
75
|
+
steps:
|
|
76
|
+
- uses: ./.github/actions/setup
|
|
77
|
+
- run: npm run build
|
|
78
|
+
|
|
79
|
+
test:
|
|
80
|
+
runs-on: ubuntu-latest
|
|
81
|
+
timeout-minutes: 10
|
|
82
|
+
steps:
|
|
83
|
+
- uses: ./.github/actions/setup
|
|
84
|
+
- run: npm test
|
|
85
|
+
prevention:
|
|
86
|
+
- "Use composite actions (`.github/actions/`) to share step sequences across jobs."
|
|
87
|
+
- "Use reusable workflows (`workflow_call`) to share entire job structures."
|
|
88
|
+
- "Lint workflow files with `actionlint` locally — it reports anchor usage before pushing."
|
|
89
|
+
docs:
|
|
90
|
+
- url: "https://docs.github.com/en/actions/sharing-automations/reusing-workflows"
|
|
91
|
+
label: "Reusing workflows"
|
|
92
|
+
- url: "https://docs.github.com/en/actions/sharing-automations/creating-actions/creating-a-composite-action"
|
|
93
|
+
label: "Creating a composite action"
|
|
94
|
+
- url: "https://rhysd.github.io/actionlint/"
|
|
95
|
+
label: "actionlint — static checker for GitHub Actions"
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
id: yaml-syntax-008
|
|
2
|
+
title: "Dynamic Matrix fromJSON Fails on Empty or Malformed JSON"
|
|
3
|
+
category: yaml-syntax
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- matrix
|
|
7
|
+
- fromJSON
|
|
8
|
+
- dynamic-matrix
|
|
9
|
+
- strategy
|
|
10
|
+
- expressions
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: "Error when evaluating 'strategy' for job"
|
|
13
|
+
flags: "i"
|
|
14
|
+
- regex: "Error parsing fromJson"
|
|
15
|
+
flags: "i"
|
|
16
|
+
- regex: "Error reading JToken from JsonReader"
|
|
17
|
+
flags: "i"
|
|
18
|
+
- regex: "matrix contains zero elements"
|
|
19
|
+
flags: "i"
|
|
20
|
+
- regex: "Unexpected type of value '', expected type: Sequence"
|
|
21
|
+
flags: "i"
|
|
22
|
+
error_messages:
|
|
23
|
+
- "Error when evaluating 'strategy' for job 'build'. .github/workflows/ci.yml (Line: 12, Col: 14): Error parsing fromJson"
|
|
24
|
+
- "Error reading JToken from JsonReader. Path '', line 0, position 0."
|
|
25
|
+
- "Unexpected type of value '', expected type: Sequence."
|
|
26
|
+
- "Error when evaluating 'strategy' for job 'test'. matrix contains zero elements"
|
|
27
|
+
root_cause: |
|
|
28
|
+
When using `fromJSON()` in a matrix strategy to build a dynamic matrix from a previous
|
|
29
|
+
job's output, three common failure modes occur:
|
|
30
|
+
|
|
31
|
+
1. **Empty string**: The upstream step produced no output (empty stdout or unset output
|
|
32
|
+
variable), so `fromJSON('')` receives an empty string and the JSON parser fails with
|
|
33
|
+
"Error reading JToken from JsonReader."
|
|
34
|
+
|
|
35
|
+
2. **Zero-element array**: The upstream step produces a valid JSON array but it is empty
|
|
36
|
+
(`[]`). GitHub Actions evaluates the strategy and then immediately fails the job
|
|
37
|
+
because it has nothing to schedule — "matrix contains zero elements."
|
|
38
|
+
|
|
39
|
+
3. **Malformed JSON**: Newlines, unescaped quotes, or shell word-splitting corrupts the
|
|
40
|
+
JSON string before it reaches fromJSON, producing parse errors such as
|
|
41
|
+
"Unexpected type of value '', expected type: Sequence."
|
|
42
|
+
|
|
43
|
+
All three root causes trace back to the step that generates the matrix JSON, not to
|
|
44
|
+
fromJSON itself. Using `jq` without `-c` (compact output) can embed literal newlines
|
|
45
|
+
that break the output variable; similarly, forgetting to set the output with
|
|
46
|
+
`echo "matrix=..." >> $GITHUB_OUTPUT` leaves the variable empty.
|
|
47
|
+
fix: |
|
|
48
|
+
1. Always produce compact, single-line JSON with `jq -c` and write it to
|
|
49
|
+
`$GITHUB_OUTPUT` (not `$GITHUB_ENV`) in the generator step.
|
|
50
|
+
2. Guard against an empty matrix by providing a fallback single-element array, or add
|
|
51
|
+
an `if` condition to skip the matrix job when the generator output is empty.
|
|
52
|
+
3. Echo and verify the generated JSON in a debug step before the matrix job runs.
|
|
53
|
+
fix_code:
|
|
54
|
+
- language: yaml
|
|
55
|
+
label: "Correct dynamic matrix pattern with empty-guard"
|
|
56
|
+
code: |
|
|
57
|
+
jobs:
|
|
58
|
+
generate:
|
|
59
|
+
runs-on: ubuntu-latest
|
|
60
|
+
outputs:
|
|
61
|
+
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
|
62
|
+
steps:
|
|
63
|
+
- id: set-matrix
|
|
64
|
+
run: |
|
|
65
|
+
# Produce compact JSON; default to ["none"] if list is empty
|
|
66
|
+
ITEMS=$(cat targets.txt | jq -Rc '[.]' | jq -sc 'add // ["none"]')
|
|
67
|
+
echo "matrix=${ITEMS}" >> $GITHUB_OUTPUT
|
|
68
|
+
|
|
69
|
+
build:
|
|
70
|
+
needs: generate
|
|
71
|
+
# Skip if only the fallback placeholder is present
|
|
72
|
+
if: ${{ needs.generate.outputs.matrix != '["none"]' }}
|
|
73
|
+
strategy:
|
|
74
|
+
matrix:
|
|
75
|
+
target: ${{ fromJSON(needs.generate.outputs.matrix) }}
|
|
76
|
+
runs-on: ubuntu-latest
|
|
77
|
+
steps:
|
|
78
|
+
- run: echo "Building ${{ matrix.target }}"
|
|
79
|
+
- language: yaml
|
|
80
|
+
label: "Debug step to verify JSON before matrix job"
|
|
81
|
+
code: |
|
|
82
|
+
- name: Verify matrix JSON
|
|
83
|
+
run: |
|
|
84
|
+
echo "Matrix value: ${{ needs.generate.outputs.matrix }}"
|
|
85
|
+
echo '${{ needs.generate.outputs.matrix }}' | jq .
|
|
86
|
+
prevention:
|
|
87
|
+
- "Always use `jq -c` (compact output) when producing JSON for matrix outputs to avoid embedded newlines."
|
|
88
|
+
- "Write matrix JSON to `$GITHUB_OUTPUT`, not `$GITHUB_ENV` — environment variables are not available as job outputs."
|
|
89
|
+
- "Add an empty-matrix guard (`if` condition or fallback value) so a zero-element array does not silently break your pipeline."
|
|
90
|
+
- "Add a debug step after the generator to echo and validate the JSON before the dependent job runs."
|
|
91
|
+
docs:
|
|
92
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/running-variations-of-jobs-in-a-workflow"
|
|
93
|
+
label: "Running variations of jobs in a workflow (matrix)"
|
|
94
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#fromjson"
|
|
95
|
+
label: "fromJSON expression function"
|
|
96
|
+
- url: "https://github.com/actions/runner/issues/2424"
|
|
97
|
+
label: "actions/runner#2424 — fromJSON parsing failures in nested workflows"
|
|
98
|
+
- url: "https://github.com/orgs/community/discussions/27096"
|
|
99
|
+
label: "Community: matrix contains zero elements"
|