@htekdev/actions-debugger 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +108 -108
  3. package/errors/_schema.json +89 -89
  4. package/errors/caching-artifacts/artifact-storage-quota-exceeded.yml +118 -0
  5. package/errors/caching-artifacts/cache-miss.yml +56 -56
  6. package/errors/caching-artifacts/cache-save-cancelled-job.yml +82 -0
  7. package/errors/caching-artifacts/cache-v3-to-v4-breaking-changes.yml +95 -0
  8. package/errors/caching-artifacts/cross-repo-artifacts-not-supported.yml +102 -0
  9. package/errors/caching-artifacts/upload-artifact-no-files-found.yml +92 -0
  10. package/errors/caching-artifacts/upload-artifact-v4-breaking.yml +67 -67
  11. package/errors/concurrency-timing/cancel-in-progress-deploy-drops.yml +97 -0
  12. package/errors/concurrency-timing/jobs-cancelled-unexpectedly.yml +60 -60
  13. package/errors/concurrency-timing/skipped-needs-cascade.yml +103 -0
  14. package/errors/concurrency-timing/workflow-run-conclusion-unchecked.yml +100 -0
  15. package/errors/known-unsolved/composite-input-env-vars-missing.yml +91 -0
  16. package/errors/known-unsolved/composite-nested-outputs-null.yml +101 -0
  17. package/errors/known-unsolved/no-dynamic-secret-access.yml +111 -0
  18. package/errors/known-unsolved/no-step-level-rerun.yml +94 -0
  19. package/errors/known-unsolved/no-step-retry.yml +53 -53
  20. package/errors/known-unsolved/workflow-rerun-limit.yml +101 -0
  21. package/errors/permissions-auth/checkout-submodule-private-auth.yml +91 -0
  22. package/errors/permissions-auth/fork-pr-secrets-unavailable.yml +97 -0
  23. package/errors/permissions-auth/gcp-oidc-workload-identity-misconfigured.yml +130 -0
  24. package/errors/permissions-auth/github-token-403.yml +64 -64
  25. package/errors/permissions-auth/github-token-protected-branch-push.yml +109 -0
  26. package/errors/permissions-auth/oidc-aws-failure.yml +85 -85
  27. package/errors/permissions-auth/oidc-azure-subject-mismatch.yml +91 -0
  28. package/errors/runner-environment/disk-space.yml +57 -57
  29. package/errors/runner-environment/docker-buildx-not-setup.yml +106 -0
  30. package/errors/runner-environment/macos-homebrew-path.yml +90 -0
  31. package/errors/runner-environment/node-runtime-deprecation.yml +56 -56
  32. package/errors/runner-environment/node20-to-node24-migration.yml +118 -0
  33. package/errors/runner-environment/npm-ci-lockfile-mismatch.yml +112 -0
  34. package/errors/runner-environment/self-hosted-stale-toolcache.yml +73 -0
  35. package/errors/runner-environment/setup-node-version-file-missing.yml +105 -0
  36. package/errors/runner-environment/windows-execution-policy.yml +83 -0
  37. package/errors/silent-failures/add-mask-no-retroactive-masking.yml +75 -0
  38. package/errors/silent-failures/composite-boolean-inputs-as-strings.yml +110 -0
  39. package/errors/silent-failures/conditional-output-null-downstream.yml +82 -0
  40. package/errors/silent-failures/continue-on-error-masks-failure.yml +86 -0
  41. package/errors/silent-failures/github-token-no-trigger.yml +57 -57
  42. package/errors/silent-failures/reusable-workflow-env-secrets-empty.yml +90 -0
  43. package/errors/silent-failures/scheduled-workflow-disabled.yml +59 -59
  44. package/errors/silent-failures/sparse-checkout-sticky-cone-mode.yml +120 -0
  45. package/errors/triggers/cron-schedule-late.yml +59 -59
  46. package/errors/triggers/pull-request-target-rce-risk.yml +117 -0
  47. package/errors/triggers/workflow-not-triggering.yml +60 -60
  48. package/errors/triggers/workflow-run-default-branch-requirement.yml +78 -0
  49. package/errors/yaml-syntax/anchors-not-supported.yml +95 -0
  50. package/errors/yaml-syntax/dynamic-matrix-fromjson-failure.yml +99 -0
  51. package/errors/yaml-syntax/if-always-true.yml +52 -52
  52. package/errors/yaml-syntax/missing-expression-wrapper.yml +67 -0
  53. package/errors/yaml-syntax/needs-indirect-outputs.yml +91 -0
  54. package/errors/yaml-syntax/reusable-workflow-missing-output-declaration.yml +140 -0
  55. package/errors/yaml-syntax/secrets-in-if.yml +55 -55
  56. package/errors/yaml-syntax/unexpected-yaml-key.yml +69 -69
  57. package/errors/yaml-syntax/working-directory-ignored-on-uses.yml +66 -0
  58. package/package.json +70 -67
@@ -1,57 +1,57 @@
1
- id: silent-failures-002
2
- title: "GITHUB_TOKEN Cannot Trigger Downstream Workflows"
3
- category: silent-failures
4
- severity: silent-failure
5
- tags:
6
- - github-token
7
- - triggers
8
- - downstream
9
- - workflow-chain
10
- - authentication
11
- patterns:
12
- - regex: "events triggered by the GITHUB_TOKEN.*will not create a new workflow run"
13
- flags: "i"
14
- - regex: "github-actions\\[bot\\]"
15
- flags: "i"
16
- - regex: "GITHUB_TOKEN"
17
- flags: "i"
18
- error_messages:
19
- - "Events triggered by the GITHUB_TOKEN will not create a new workflow run."
20
- root_cause: |
21
- Commits, tags, and releases created with the repository `GITHUB_TOKEN` are intentionally
22
- prevented from triggering most downstream workflows. This is a platform safety feature to
23
- stop accidental recursion and workflow loops.
24
-
25
- The upstream workflow appears to succeed, but the dependent workflow never starts, which
26
- makes this feel like a silent trigger failure.
27
- fix: |
28
- Use a GitHub App installation token or a PAT when you intentionally need one workflow to
29
- trigger another via `push`, `create`, or `release`. Keep `GITHUB_TOKEN` for normal repo
30
- automation that should not fan out into new workflow runs.
31
- fix_code:
32
- - language: yaml
33
- label: "Use a non-GITHUB_TOKEN credential for recursive automation"
34
- code: |
35
- jobs:
36
- release:
37
- runs-on: ubuntu-latest
38
- steps:
39
- - uses: actions/checkout@v4
40
- - name: Create tag with a PAT
41
- env:
42
- GH_TOKEN: ${{ secrets.RELEASE_PAT }}
43
- run: |
44
- git tag v${{ github.run_number }}
45
- git push https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git --tags
46
- prevention:
47
- - "Assume `GITHUB_TOKEN` will not fan out into downstream workflow runs unless you are using `workflow_dispatch` or `repository_dispatch`."
48
- - "Document which automations require a GitHub App token or PAT."
49
- - "Avoid recursive workflow designs that depend on implicit `push` triggers from `github-actions[bot]`."
50
- docs:
51
- - url: "https://docs.github.com/en/actions/security-guides/automatic-token-authentication"
52
- label: "Automatic token authentication"
53
- - url: "https://docs.github.com/en/actions/reference/events-that-trigger-workflows"
54
- label: "Events that trigger workflows"
55
- source:
56
- article: "https://htek.dev/articles/github-actions-debugging-guide"
57
- section: "GITHUB_TOKEN downstream trigger limitations"
1
+ id: silent-failures-002
2
+ title: "GITHUB_TOKEN Cannot Trigger Downstream Workflows"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - github-token
7
+ - triggers
8
+ - downstream
9
+ - workflow-chain
10
+ - authentication
11
+ patterns:
12
+ - regex: "events triggered by the GITHUB_TOKEN.*will not create a new workflow run"
13
+ flags: "i"
14
+ - regex: "github-actions\\[bot\\]"
15
+ flags: "i"
16
+ - regex: "GITHUB_TOKEN"
17
+ flags: "i"
18
+ error_messages:
19
+ - "Events triggered by the GITHUB_TOKEN will not create a new workflow run."
20
+ root_cause: |
21
+ Commits, tags, and releases created with the repository `GITHUB_TOKEN` are intentionally
22
+ prevented from triggering most downstream workflows. This is a platform safety feature to
23
+ stop accidental recursion and workflow loops.
24
+
25
+ The upstream workflow appears to succeed, but the dependent workflow never starts, which
26
+ makes this feel like a silent trigger failure.
27
+ fix: |
28
+ Use a GitHub App installation token or a PAT when you intentionally need one workflow to
29
+ trigger another via `push`, `create`, or `release`. Keep `GITHUB_TOKEN` for normal repo
30
+ automation that should not fan out into new workflow runs.
31
+ fix_code:
32
+ - language: yaml
33
+ label: "Use a non-GITHUB_TOKEN credential for recursive automation"
34
+ code: |
35
+ jobs:
36
+ release:
37
+ runs-on: ubuntu-latest
38
+ steps:
39
+ - uses: actions/checkout@v4
40
+ - name: Create tag with a PAT
41
+ env:
42
+ GH_TOKEN: ${{ secrets.RELEASE_PAT }}
43
+ run: |
44
+ git tag v${{ github.run_number }}
45
+ git push https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git --tags
46
+ prevention:
47
+ - "Assume `GITHUB_TOKEN` will not fan out into downstream workflow runs unless you are using `workflow_dispatch` or `repository_dispatch`."
48
+ - "Document which automations require a GitHub App token or PAT."
49
+ - "Avoid recursive workflow designs that depend on implicit `push` triggers from `github-actions[bot]`."
50
+ docs:
51
+ - url: "https://docs.github.com/en/actions/security-guides/automatic-token-authentication"
52
+ label: "Automatic token authentication"
53
+ - url: "https://docs.github.com/en/actions/reference/events-that-trigger-workflows"
54
+ label: "Events that trigger workflows"
55
+ source:
56
+ article: "https://htek.dev/articles/github-actions-debugging-guide"
57
+ section: "GITHUB_TOKEN downstream trigger limitations"
@@ -0,0 +1,90 @@
1
+ id: silent-failures-003
2
+ title: "Reusable Workflow Environment-Scoped Secrets Resolve as Empty String"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - reusable-workflows
7
+ - secrets
8
+ - environments
9
+ - workflow-call
10
+ - secrets-inherit
11
+ patterns:
12
+ - regex: "MY_SECRET length: 0"
13
+ flags: "i"
14
+ - regex: "secrets\\.[A-Z_]+\\s*:\\s*$"
15
+ flags: "m"
16
+ error_messages:
17
+ - "MY_SECRET length: 0"
18
+ - "EMPTY"
19
+ root_cause: |
20
+ When a reusable workflow (called via `workflow_call`) declares `environment: ${{ inputs.environment_name }}`
21
+ on its job, the GitHub Actions documentation states that environment-scoped secrets should resolve from
22
+ that environment. In practice, secrets resolve to empty string unless the caller adds `secrets: inherit`.
23
+
24
+ The `secrets: inherit` flag passes all of the caller's accessible secrets to the reusable workflow,
25
+ including environment-scoped secrets. Without it, the called workflow's secret resolution context is
26
+ narrowly scoped to explicitly mapped secrets — and environment-scoped secrets are not injected even when
27
+ the job correctly declares the environment name.
28
+
29
+ This is especially dangerous in matrix-based CI/CD pipelines where different matrix entries target
30
+ different environments (e.g., per-tenant deployments). The reusable workflow appears to run normally but
31
+ every secret it tries to use is silently empty. The failure can be masked for days if downstream systems
32
+ tolerate empty credentials during a grace period (e.g., pods using in-cluster Kubernetes Secrets).
33
+ fix: |
34
+ Add `secrets: inherit` to the caller's job definition. This enables the reusable workflow to resolve
35
+ environment-scoped secrets from the environment declared on its job:
36
+
37
+ Alternatively, explicitly enumerate each secret you need to pass via the `secrets:` mapping block.
38
+ The explicit form is more secure for cross-repository reusable workflows.
39
+ fix_code:
40
+ - language: yaml
41
+ label: "Add secrets: inherit so environment-scoped secrets resolve in the reusable workflow"
42
+ code: |
43
+ # Caller workflow
44
+ jobs:
45
+ deploy:
46
+ uses: ./.github/workflows/deploy.yml
47
+ with:
48
+ target_environment: production
49
+ secrets: inherit # required — without this, env-scoped secrets are empty
50
+
51
+ # Reusable workflow (.github/workflows/deploy.yml) — no changes needed
52
+ on:
53
+ workflow_call:
54
+ inputs:
55
+ target_environment:
56
+ required: true
57
+ type: string
58
+ jobs:
59
+ worker:
60
+ runs-on: ubuntu-latest
61
+ environment: ${{ inputs.target_environment }}
62
+ steps:
63
+ - name: Use secret
64
+ env:
65
+ API_KEY: ${{ secrets.API_KEY }}
66
+ run: |
67
+ echo "API_KEY length: ${#API_KEY}"
68
+ - language: yaml
69
+ label: "Explicit secrets mapping (more secure for cross-repo reusable workflows)"
70
+ code: |
71
+ jobs:
72
+ deploy:
73
+ uses: org/infra/.github/workflows/deploy.yml@main
74
+ with:
75
+ target_environment: production
76
+ secrets:
77
+ API_KEY: ${{ secrets.API_KEY }}
78
+ DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
79
+ prevention:
80
+ - "Always add `secrets: inherit` when a reusable workflow needs environment-scoped secrets."
81
+ - "Verify secret resolution by printing the secret length: `echo \"length ${#MY_SECRET}\"` — never print the value."
82
+ - "In matrix deployments targeting different environments, confirm each matrix item resolves its secrets before shipping."
83
+ - "Consider explicit secrets mapping for cross-repository workflows to avoid accidentally leaking unrelated secrets."
84
+ docs:
85
+ - url: "https://docs.github.com/en/actions/sharing-automations/reusing-workflows#passing-secrets-to-called-workflows"
86
+ label: "Passing secrets to called workflows"
87
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/using-environments-for-deployment"
88
+ label: "Using environments for deployment"
89
+ - url: "https://github.com/actions/runner/issues/4453"
90
+ label: "actions/runner#4453 — Environment-scoped secrets unreachable without secrets: inherit"
@@ -1,59 +1,59 @@
1
- id: silent-failures-001
2
- title: "Scheduled Workflows Silently Disabled After 60 Days"
3
- category: silent-failures
4
- severity: silent-failure
5
- tags:
6
- - schedule
7
- - cron
8
- - inactivity
9
- - disabled
10
- - automation
11
- patterns:
12
- - regex: "This scheduled workflow is disabled because there hasn't been activity in this repository for at least 60 days"
13
- flags: "i"
14
- - regex: "schedule.*workflow.*disabled"
15
- flags: "i"
16
- error_messages:
17
- - "This scheduled workflow is disabled because there hasn't been activity in this repository for at least 60 days"
18
- root_cause: |
19
- In public repositories, GitHub automatically disables scheduled workflows after about
20
- 60 days with no repository activity. Nothing in the workflow YAML is technically wrong,
21
- but the cron job stops firing until someone re-enables it or new activity occurs.
22
-
23
- This feels like a silent failure because the expected schedule disappears rather than
24
- producing a normal failed run.
25
- fix: |
26
- Re-enable the workflow in the Actions UI and keep the repository active. If the schedule
27
- must stay alive in a low-activity repository, add a keepalive workflow that periodically
28
- creates harmless activity.
29
- fix_code:
30
- - language: yaml
31
- label: "Keep scheduled workflows active"
32
- code: |
33
- name: Keepalive
34
-
35
- on:
36
- schedule:
37
- - cron: '0 6 * * 1'
38
- workflow_dispatch:
39
-
40
- jobs:
41
- keepalive:
42
- runs-on: ubuntu-latest
43
- steps:
44
- - uses: gautamkrishnar/keepalive-workflow@v2
45
- with:
46
- committer_username: github-actions[bot]
47
- committer_email: 41898282+github-actions[bot]@users.noreply.github.com
48
- prevention:
49
- - "Check the Actions tab periodically for disabled scheduled workflows in low-activity repositories."
50
- - "Pair important cron automations with `workflow_dispatch` for manual recovery."
51
- - "Use a keepalive strategy for public repos that rely on unattended schedules."
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: "Scheduled workflows disabled after inactivity"
1
+ id: silent-failures-001
2
+ title: "Scheduled Workflows Silently Disabled After 60 Days"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - schedule
7
+ - cron
8
+ - inactivity
9
+ - disabled
10
+ - automation
11
+ patterns:
12
+ - regex: "This scheduled workflow is disabled because there hasn't been activity in this repository for at least 60 days"
13
+ flags: "i"
14
+ - regex: "schedule.*workflow.*disabled"
15
+ flags: "i"
16
+ error_messages:
17
+ - "This scheduled workflow is disabled because there hasn't been activity in this repository for at least 60 days"
18
+ root_cause: |
19
+ In public repositories, GitHub automatically disables scheduled workflows after about
20
+ 60 days with no repository activity. Nothing in the workflow YAML is technically wrong,
21
+ but the cron job stops firing until someone re-enables it or new activity occurs.
22
+
23
+ This feels like a silent failure because the expected schedule disappears rather than
24
+ producing a normal failed run.
25
+ fix: |
26
+ Re-enable the workflow in the Actions UI and keep the repository active. If the schedule
27
+ must stay alive in a low-activity repository, add a keepalive workflow that periodically
28
+ creates harmless activity.
29
+ fix_code:
30
+ - language: yaml
31
+ label: "Keep scheduled workflows active"
32
+ code: |
33
+ name: Keepalive
34
+
35
+ on:
36
+ schedule:
37
+ - cron: '0 6 * * 1'
38
+ workflow_dispatch:
39
+
40
+ jobs:
41
+ keepalive:
42
+ runs-on: ubuntu-latest
43
+ steps:
44
+ - uses: gautamkrishnar/keepalive-workflow@v2
45
+ with:
46
+ committer_username: github-actions[bot]
47
+ committer_email: 41898282+github-actions[bot]@users.noreply.github.com
48
+ prevention:
49
+ - "Check the Actions tab periodically for disabled scheduled workflows in low-activity repositories."
50
+ - "Pair important cron automations with `workflow_dispatch` for manual recovery."
51
+ - "Use a keepalive strategy for public repos that rely on unattended schedules."
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: "Scheduled workflows disabled after inactivity"
@@ -0,0 +1,120 @@
1
+ id: silent-failures-008
2
+ title: "Sparse Checkout Persists to Subsequent Checkout Steps (Sticky Cone Mode)"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - checkout
7
+ - sparse-checkout
8
+ - cone-mode
9
+ - composite-actions
10
+ - file-missing
11
+ patterns:
12
+ - regex: "sparse.*checkout.*persist"
13
+ flags: "i"
14
+ - regex: "core\\.sparseCheckout.*true"
15
+ flags: "i"
16
+ - regex: "sparse-checkout.*not disabled"
17
+ flags: "i"
18
+ error_messages:
19
+ - "Run actions/checkout@v4"
20
+ - "Expected full checkout but only sparse tree present"
21
+ root_cause: |
22
+ When `actions/checkout` is called with `sparse-checkout:` options, it sets the git
23
+ repository's `core.sparseCheckout = true` config. A subsequent call to `actions/checkout`
24
+ in the same job — even WITHOUT specifying sparse-checkout — re-uses the existing git
25
+ repository and inherits the sticky `core.sparseCheckout = true` setting.
26
+
27
+ Result: the second checkout appears to succeed (no error), but the working directory
28
+ still contains only the sparse subset from the first checkout. Files outside the
29
+ original sparse pattern are silently absent.
30
+
31
+ This most commonly occurs in two scenarios:
32
+ 1. A workflow calls `actions/checkout` with sparse-checkout for a fast initial clone,
33
+ then calls `actions/checkout` again (different ref, different path spec) expecting
34
+ a full checkout.
35
+ 2. A workflow uses sparse-checkout, then calls a composite action that internally runs
36
+ its own `actions/checkout`. The composite action's checkout inherits the sparse
37
+ setting from the parent workflow's checkout.
38
+
39
+ Root cause: a bug in `actions/checkout` — the `disableSparseCheckout()` method does not
40
+ explicitly set `core.sparseCheckout false` when `sparse-checkout` input is absent. A
41
+ fix PR (#2034) exists in the repo but has not been merged as of 2026.
42
+ fix: |
43
+ **Option 1 (recommended): Explicitly reset sparse-checkout between checkouts**
44
+ Add a `git sparse-checkout disable` step between the sparse and full checkouts. This
45
+ clears the sticky `core.sparseCheckout` flag and ensures subsequent checkouts are full.
46
+
47
+ **Option 2: Use separate `path:` directories**
48
+ Checkout into a unique subdirectory with the `path:` input to prevent git config
49
+ sharing. Each `path:` gets its own `.git` config.
50
+
51
+ **Option 3: Use `sparse-checkout-cone-mode: false` carefully**
52
+ When in non-cone mode, review that patterns don't accidentally match more or fewer
53
+ files than expected. Non-cone mode with incorrect patterns is its own source of
54
+ silent failures.
55
+ fix_code:
56
+ - language: yaml
57
+ label: "Reset sparse-checkout before a subsequent full checkout"
58
+ code: |
59
+ steps:
60
+ # First checkout: sparse (fast clone for config files only)
61
+ - uses: actions/checkout@v4
62
+ with:
63
+ sparse-checkout: |
64
+ .github
65
+ config/
66
+
67
+ - name: Reset sparse-checkout so next checkout is full
68
+ shell: bash
69
+ run: git sparse-checkout disable
70
+
71
+ # Second checkout (in composite action or next step): now gets full tree
72
+ - uses: actions/checkout@v4
73
+ with:
74
+ ref: ${{ github.sha }}
75
+ - language: yaml
76
+ label: "Use separate path: directories to avoid shared git config"
77
+ code: |
78
+ steps:
79
+ # Sparse checkout into 'config-only/' subdirectory
80
+ - uses: actions/checkout@v4
81
+ with:
82
+ path: config-only
83
+ sparse-checkout: |
84
+ config/
85
+
86
+ # Full checkout into 'full-repo/' — completely separate git repo config
87
+ - uses: actions/checkout@v4
88
+ with:
89
+ path: full-repo
90
+ - language: yaml
91
+ label: "Composite action defensive reset (add to composite action's beginning)"
92
+ code: |
93
+ # In your composite action's action.yml — reset sparse before own checkout
94
+ runs:
95
+ using: composite
96
+ steps:
97
+ - name: Reset any inherited sparse-checkout
98
+ shell: bash
99
+ run: |
100
+ if git rev-parse --git-dir > /dev/null 2>&1; then
101
+ git sparse-checkout disable 2>/dev/null || true
102
+ fi
103
+
104
+ - uses: actions/checkout@v4
105
+ with:
106
+ ref: ${{ inputs.ref }}
107
+ prevention:
108
+ - "Never assume a subsequent `actions/checkout` step gets a full tree if any earlier step used sparse-checkout."
109
+ - "Add `git sparse-checkout disable` as an explicit step between sparse and full checkouts in the same job."
110
+ - "When writing composite actions that call `actions/checkout`, add a defensive `git sparse-checkout disable` before your checkout step."
111
+ - "Use the `path:` input to isolate checkouts that need different content into separate directories."
112
+ docs:
113
+ - url: "https://github.com/actions/checkout/issues/1498"
114
+ label: "actions/checkout#1498: Sparse checkout persists in composite action"
115
+ - url: "https://github.com/actions/checkout/pull/2034"
116
+ label: "actions/checkout#2034: Fix — disable sparse-checkout on subsequent checkout (open PR)"
117
+ - url: "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsuses"
118
+ label: "Workflow syntax: steps.uses"
119
+ - url: "https://github.com/actions/checkout#usage"
120
+ label: "actions/checkout: Usage and sparse-checkout options"
@@ -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"