@htekdev/actions-debugger 1.0.23 → 1.0.25

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 (61) hide show
  1. package/errors/caching-artifacts/artifact-minimum-retention-one-day.yml +153 -0
  2. package/errors/caching-artifacts/cache-api-propagation-delay-post-save.yml +128 -0
  3. package/errors/caching-artifacts/cache-backend-internal-error-skipped.yml +75 -0
  4. package/errors/caching-artifacts/cache-hit-step-id-case-sensitive-mismatch.yml +95 -0
  5. package/errors/caching-artifacts/cache-save-post-step-skipped-on-failure.yml +114 -0
  6. package/errors/concurrency-timing/deploy-pages-in-progress-deployment-wedged.yml +70 -0
  7. package/errors/concurrency-timing/deployment-review-timeout-expired.yml +88 -0
  8. package/errors/concurrency-timing/job-concurrency-scope-per-run-not-global.yml +81 -0
  9. package/errors/concurrency-timing/merge-queue-concurrency-cancel-blocks-all.yml +86 -0
  10. package/errors/concurrency-timing/reusable-workflow-github-workflow-context-cancel.yml +124 -0
  11. package/errors/concurrency-timing/runner-scale-set-jobs-never-start.yml +123 -0
  12. package/errors/concurrency-timing/runner-temp-dir-race-concurrent-workers.yml +90 -0
  13. package/errors/known-unsolved/artifact-download-url-unauthenticated-404.yml +98 -0
  14. package/errors/known-unsolved/checkout-v6-credentials-docker-run-manual.yml +105 -0
  15. package/errors/known-unsolved/concurrency-groups-repo-scoped-only.yml +138 -0
  16. package/errors/known-unsolved/environment-deployment-false-custom-protection.yml +93 -0
  17. package/errors/known-unsolved/matrix-256-job-limit.yml +142 -0
  18. package/errors/known-unsolved/merge-group-paths-filter-not-supported.yml +137 -0
  19. package/errors/known-unsolved/no-job-allow-failure.yml +73 -0
  20. package/errors/known-unsolved/schedule-cron-hours-long-queue-drift.yml +101 -0
  21. package/errors/permissions-auth/checkout-persist-credentials-token-write.yml +90 -0
  22. package/errors/permissions-auth/checkout-v6-cross-repo-token-override.yml +103 -0
  23. package/errors/permissions-auth/create-github-app-token-cross-job-token-revoked.yml +95 -0
  24. package/errors/permissions-auth/github-token-contents-write-missing-git-push.yml +117 -0
  25. package/errors/permissions-auth/org-actions-policy-blocks-unapproved-action.yml +106 -0
  26. package/errors/runner-environment/codeql-action-v2-deprecated.yml +110 -0
  27. package/errors/runner-environment/macos-26-openssl-3-system-library-breaking.yml +114 -0
  28. package/errors/runner-environment/macos-26-ruby-34-default-upgrade.yml +114 -0
  29. package/errors/runner-environment/macos-26-xcode-default-265-pin-required.yml +99 -0
  30. package/errors/runner-environment/macos-latest-label-switches-to-macos26.yml +127 -0
  31. package/errors/runner-environment/maven-gradle-403-cache-backend-outage.yml +116 -0
  32. package/errors/runner-environment/node20-removed-toolcache-default-node22.yml +104 -0
  33. package/errors/runner-environment/powershell-74-76-threadjob-module-rename.yml +124 -0
  34. package/errors/runner-environment/self-hosted-runner-not-found.yml +134 -0
  35. package/errors/runner-environment/self-hosted-runner-selinux-service-exec-failure.yml +116 -0
  36. package/errors/runner-environment/service-container-no-healthcheck.yml +158 -0
  37. package/errors/runner-environment/setup-node-v5-corepack-pnpm-not-found.yml +101 -0
  38. package/errors/runner-environment/setup-node-yarn-not-installed-self-hosted.yml +76 -0
  39. package/errors/runner-environment/setup-python-externally-managed-env-error.yml +95 -0
  40. package/errors/runner-environment/windows-2019-runner-retired-june2025.yml +118 -0
  41. package/errors/runner-environment/windows-2022-docker-daemon-not-started.yml +108 -0
  42. package/errors/silent-failures/cache-hit-output-string-not-boolean.yml +96 -0
  43. package/errors/silent-failures/checkout-lfs-pointer-not-content.yml +105 -0
  44. package/errors/silent-failures/reusable-workflow-output-skipped-contains-secret.yml +115 -0
  45. package/errors/silent-failures/setup-node-silent-download-exit-zero.yml +105 -0
  46. package/errors/silent-failures/setup-python-truncated-manifest-silent-exit.yml +111 -0
  47. package/errors/silent-failures/undefined-env-expression-empty-string-silent.yml +115 -0
  48. package/errors/silent-failures/windows-powershell-github-output-bash-syntax.yml +118 -0
  49. package/errors/triggers/fork-pr-first-time-contributor-approval-required.yml +142 -0
  50. package/errors/triggers/on-push-branches-glob-star-no-slash-match.yml +78 -0
  51. package/errors/triggers/pull-request-target-env-protection-default-branch-eval.yml +117 -0
  52. package/errors/triggers/required-status-check-renamed-never-passes.yml +87 -0
  53. package/errors/triggers/schedule-cron-self-hosted-runner-not-triggered.yml +107 -0
  54. package/errors/yaml-syntax/case-function-runner-version-too-old.yml +100 -0
  55. package/errors/yaml-syntax/composite-action-run-shell-missing.yml +90 -0
  56. package/errors/yaml-syntax/composite-action-secrets-context-unavailable.yml +99 -0
  57. package/errors/yaml-syntax/github-script-octokit-renamed-to-github.yml +130 -0
  58. package/errors/yaml-syntax/labeler-v5-config-format-breaking.yml +67 -0
  59. package/errors/yaml-syntax/runs-on-expression-array-syntax-error.yml +121 -0
  60. package/errors/yaml-syntax/setup-go-matrix-version-float-coercion.yml +69 -0
  61. package/package.json +1 -1
@@ -0,0 +1,108 @@
1
+ id: runner-environment-069
2
+ title: "Windows 2022 Runner Docker Engine Named Pipe Not Found on Start"
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - windows
7
+ - docker
8
+ - runner-image
9
+ - intermittent
10
+ - named-pipe
11
+ patterns:
12
+ - regex: "failed to connect to the docker API at npipe:////\\.?/pipe/docker_engine"
13
+ flags: "i"
14
+ - regex: "open //\\.?/pipe/docker_engine.*The system cannot find the file specified"
15
+ flags: "i"
16
+ - regex: "error during connect.*pipe/docker_engine.*daemon running"
17
+ flags: "i"
18
+ - regex: "Docker Engine.*Stopped|docker.*service.*not running"
19
+ flags: "i"
20
+ error_messages:
21
+ - "failed to connect to the docker API at npipe:////./pipe/docker_engine; check if the path is correct and if the daemon is running: open //./pipe/docker_engine: The system cannot find the file specified."
22
+ - "error during connect: Get \"http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.45/info\": open //./pipe/docker_engine: The system cannot find the file specified."
23
+ root_cause: |
24
+ On GitHub-hosted `windows-2022` runners, the Docker Engine service occasionally
25
+ fails to start before the workflow job begins. The Docker Engine runs as a Windows
26
+ service (`docker`) and the runner sometimes starts executing job steps before the
27
+ service has fully initialized and opened its named pipe at `//./pipe/docker_engine`.
28
+
29
+ This is an intermittent race condition between the runner agent startup and the
30
+ Docker Engine service startup sequence. The issue was reported in February 2026
31
+ (runner-images#13729) and confirmed to affect `windows-2022` at ~50% frequency
32
+ for some users. The `windows-2025` image is less affected.
33
+
34
+ The Docker Engine service shows `Status: Stopped` when queried immediately after
35
+ the runner starts. Manually starting the service (via `Start-Service docker`)
36
+ resolves the issue for that run. Job reruns also frequently succeed because they
37
+ land on a fresh host with Docker already running.
38
+ fix: |
39
+ Add a step early in your job to verify Docker is running and start it if not:
40
+
41
+ ```yaml
42
+ - name: Ensure Docker Engine is running
43
+ shell: pwsh
44
+ run: |
45
+ $service = Get-Service -Name docker -ErrorAction SilentlyContinue
46
+ if ($service.Status -ne 'Running') {
47
+ Start-Service docker
48
+ $timeout = 60
49
+ $elapsed = 0
50
+ while ((Get-Service docker).Status -ne 'Running' -and $elapsed -lt $timeout) {
51
+ Start-Sleep -Seconds 2
52
+ $elapsed += 2
53
+ }
54
+ }
55
+ docker info
56
+ ```
57
+
58
+ If the issue is sporadic, a simpler retry on job failure may suffice. You can
59
+ also switch to `windows-2025` which has a lower incidence of this race condition.
60
+ fix_code:
61
+ - language: yaml
62
+ label: "Guard step — ensure Docker service is running before use"
63
+ code: |
64
+ jobs:
65
+ build:
66
+ runs-on: windows-2022
67
+ steps:
68
+ - uses: actions/checkout@v4
69
+
70
+ - name: Ensure Docker Engine is running
71
+ shell: pwsh
72
+ run: |
73
+ $svc = Get-Service docker -ErrorAction SilentlyContinue
74
+ if ($null -eq $svc -or $svc.Status -ne 'Running') {
75
+ Write-Host "Docker service not running — starting..."
76
+ Start-Service docker
77
+ $deadline = (Get-Date).AddSeconds(60)
78
+ while ((Get-Service docker).Status -ne 'Running') {
79
+ if ((Get-Date) -gt $deadline) { throw "Docker failed to start in 60s" }
80
+ Start-Sleep -Seconds 2
81
+ }
82
+ Write-Host "Docker service started."
83
+ }
84
+ docker info
85
+
86
+ - name: Build Docker image
87
+ run: docker build -t myimage .
88
+ - language: yaml
89
+ label: "Alternative — switch to windows-2025 (less affected)"
90
+ code: |
91
+ jobs:
92
+ build:
93
+ # windows-2025 has a lower frequency of this race condition
94
+ runs-on: windows-2025
95
+ steps:
96
+ - uses: actions/checkout@v4
97
+ - name: Build Docker image
98
+ run: docker build -t myimage .
99
+ prevention:
100
+ - "Add a Docker health-check step before any `docker` commands on Windows runners."
101
+ - "Consider using `windows-2025` which has fewer reports of this race condition."
102
+ - "Enable job reruns — this race condition is intermittent and reruns usually succeed."
103
+ - "Subscribe to runner-images announcements; GitHub is tracking this as a runner startup issue."
104
+ docs:
105
+ - url: "https://github.com/actions/runner-images/issues/13729"
106
+ label: "GitHub Issue: windows-2022 docker not available when runner starts"
107
+ - url: "https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources"
108
+ label: "About GitHub-hosted runners"
@@ -0,0 +1,96 @@
1
+ id: silent-failures-031
2
+ title: "cache-hit Output Is a String Not a Boolean — Bare true Comparison Always False"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - actions/cache
7
+ - cache-hit
8
+ - string-comparison
9
+ - boolean-coercion
10
+ - conditional
11
+ - step-outputs
12
+ patterns:
13
+ - regex: "cache-hit\\s*[!=]=\\s*true(?!')"
14
+ flags: "i"
15
+ - regex: "if:\\s+steps\\.\\w+\\.outputs\\.cache-hit\\s*$"
16
+ flags: "im"
17
+ error_messages:
18
+ - "steps.cache.outputs.cache-hit == true"
19
+ - "steps.cache.outputs.cache-hit != true"
20
+ root_cause: |
21
+ The `cache-hit` output from `actions/cache` and `actions/cache/restore` is a **string** value
22
+ (`'true'` or `'false'`), not a native boolean. GitHub Actions expression syntax uses strict
23
+ equality for `==` — there is no implicit type coercion between strings and booleans.
24
+
25
+ This means:
26
+ - `steps.cache.outputs.cache-hit == true` → ALWAYS false (string 'true' ≠ boolean true)
27
+ - `steps.cache.outputs.cache-hit != true` → ALWAYS true (install step always runs)
28
+ - `if: steps.cache.outputs.cache-hit` → ALWAYS true ('false' is a non-empty string)
29
+
30
+ The most destructive case: `if: steps.cache.outputs.cache-hit != true` is intended to
31
+ skip the install step on cache hit, but it always evaluates to `true` (runs every time),
32
+ so the install always runs even after a successful cache restore. Build times remain
33
+ unchanged, no error is shown, and the caching appears to be broken.
34
+
35
+ This applies to ALL GitHub Actions step outputs — they are always strings. A separate
36
+ but related issue is `cache-hit-restore-keys-misleading` (cache-hit is 'true' on partial
37
+ key match); this entry covers the unquoted boolean comparison pattern specifically.
38
+ fix: |
39
+ Always compare `cache-hit` to the string `'true'` with single quotes:
40
+
41
+ - Skip install on cache hit: `if: steps.cache.outputs.cache-hit != 'true'`
42
+ - Confirm cache was used: `if: steps.cache.outputs.cache-hit == 'true'`
43
+
44
+ Do NOT use bare `true` / `false` (without quotes) in comparisons with step outputs.
45
+ Do NOT use `if: steps.cache.outputs.cache-hit` as a truthy check — the string 'false'
46
+ is truthy in most contexts and will always pass.
47
+ fix_code:
48
+ - language: yaml
49
+ label: "Correct string comparison for cache-hit (single quotes required)"
50
+ code: |
51
+ - name: Cache node_modules
52
+ id: cache
53
+ uses: actions/cache@v4
54
+ with:
55
+ path: node_modules
56
+ key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
57
+
58
+ # ❌ WRONG: string 'true' != boolean true → always runs (never skips on cache hit)
59
+ - name: Install (broken — always runs)
60
+ if: steps.cache.outputs.cache-hit != true
61
+ run: npm ci
62
+
63
+ # ✅ CORRECT: compare to string 'true' with single quotes
64
+ - name: Install (correct — skips on cache hit)
65
+ if: steps.cache.outputs.cache-hit != 'true'
66
+ run: npm ci
67
+ - language: yaml
68
+ label: "Full cache-then-install pattern with correct comparisons"
69
+ code: |
70
+ - uses: actions/cache@v4
71
+ id: npm-cache
72
+ with:
73
+ path: ~/.npm
74
+ key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
75
+ restore-keys: |
76
+ ${{ runner.os }}-npm-
77
+
78
+ - name: Install dependencies
79
+ if: steps.npm-cache.outputs.cache-hit != 'true'
80
+ run: npm ci
81
+
82
+ - name: Confirm cache was used
83
+ if: steps.npm-cache.outputs.cache-hit == 'true'
84
+ run: echo "Cache hit — install skipped"
85
+ prevention:
86
+ - "Always compare step outputs to string literals with quotes: `== 'true'` not `== true`."
87
+ - "Remember: ALL GitHub Actions step outputs are strings — never native booleans or numbers."
88
+ - "Use `actionlint` to lint workflow YAML; it detects boolean vs string type mismatches in conditionals."
89
+ - "Verify caching is working by observing run time reduction — a successful cache hit noticeably speeds up installs."
90
+ docs:
91
+ - url: "https://github.com/actions/cache#outputs"
92
+ label: "actions/cache README: outputs — cache-hit is a string"
93
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/contexts#steps-context"
94
+ label: "GitHub Docs: steps context — all outputs are strings"
95
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#operators"
96
+ label: "GitHub Docs: Expression operators — == uses strict equality"
@@ -0,0 +1,105 @@
1
+ id: silent-failures-033
2
+ title: "actions/checkout lfs: true Leaves LFS Pointer Metadata Instead of Actual File Content"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - checkout
7
+ - git-lfs
8
+ - lfs
9
+ - pointer-file
10
+ - large-file-storage
11
+ - self-hosted
12
+ patterns:
13
+ - regex: "version https://git-lfs\\.github\\.com/spec/v1"
14
+ flags: "i"
15
+ - regex: "oid\\s+sha256:[0-9a-f]{64}"
16
+ flags: "i"
17
+ - regex: "lfs:\\s*true"
18
+ flags: "i"
19
+ error_messages:
20
+ - "version https://git-lfs.github.com/spec/v1"
21
+ - "oid sha256:f23e4c2b1244bc93085dbccf17c447e54..."
22
+ - "size 58951008"
23
+ root_cause: |
24
+ When actions/checkout runs with lfs: true, it configures LFS credentials and
25
+ attempts to download actual file content for LFS-tracked files. However, the
26
+ step can exit 0 (success) while leaving LFS pointer metadata files on disk
27
+ instead of the actual binary or text content.
28
+
29
+ This happens silently in several situations:
30
+
31
+ - Self-hosted runners without git-lfs installed: the LFS fetch is skipped
32
+ because the binary is not present. No error is emitted.
33
+ - LFS bandwidth quota exhausted: GitHub's LFS bandwidth limit (1 GB/month
34
+ free tier) is silently hit; pointer files remain without a clear warning.
35
+ - Private cross-repo LFS: checking out a different repository with lfs: true
36
+ using a token may fail LFS authentication without surfacing an error.
37
+ - Fork pull requests: LFS objects contributed from fork branches may not be
38
+ accessible to the base repository workflow.
39
+
40
+ The result: downstream tools receive a text file starting with
41
+ "version https://git-lfs.github.com/spec/v1" instead of actual content,
42
+ causing opaque failures in build tools, image processors, or test suites.
43
+ fix: |
44
+ Add an explicit LFS fetch step after checkout. On GitHub-hosted runners,
45
+ lfs: true is generally sufficient if LFS is configured on the repository.
46
+ For self-hosted runners, ensure git-lfs is installed before the checkout
47
+ step runs:
48
+ - Ubuntu/Debian: sudo apt-get install git-lfs
49
+ - macOS: brew install git-lfs
50
+ - Windows: winget install GitHub.GitLFS
51
+
52
+ After installation, run the LFS initialization command (git lfs install)
53
+ once per runner to configure the global LFS hooks.
54
+
55
+ To detect unfetched pointer files, add a validation step that checks for
56
+ the LFS pointer header string in files that should contain real content.
57
+ fix_code:
58
+ - language: yaml
59
+ label: "Self-hosted runner — install git-lfs before checkout"
60
+ code: |
61
+ steps:
62
+ - name: Ensure git-lfs is installed
63
+ run: |
64
+ sudo apt-get update -qq
65
+ sudo apt-get install -y git-lfs
66
+ shell: bash
67
+
68
+ - uses: actions/checkout@v4
69
+ with:
70
+ lfs: true
71
+
72
+ - name: Verify LFS content downloaded
73
+ run: |
74
+ if grep -rl "version https://git-lfs.github.com/spec/v1" . \
75
+ --include="*.bin" --include="*.png" --include="*.zip" 2>/dev/null | head -1 | grep -q .; then
76
+ echo "ERROR: LFS pointer files found — actual content was not downloaded"
77
+ exit 1
78
+ fi
79
+ echo "LFS check passed — no pointer files found"
80
+ shell: bash
81
+
82
+ - language: yaml
83
+ label: "GitHub-hosted runner — explicit lfs: true with verification"
84
+ code: |
85
+ steps:
86
+ - uses: actions/checkout@v4
87
+ with:
88
+ lfs: true
89
+ # lfs: true is usually sufficient on GitHub-hosted runners
90
+ # if LFS quota is not exhausted
91
+ prevention:
92
+ - "Verify git-lfs is installed on all self-hosted runners before running checkout workflows."
93
+ - "Monitor GitHub LFS bandwidth usage in repository Settings > Billing to avoid silent quota exhaustion."
94
+ - "Add a post-checkout verification step that confirms LFS-tracked files contain real content, not pointer metadata."
95
+ - "For fork PRs from external contributors, be aware that LFS objects may not be accessible — consider disabling LFS-dependent tests for fork builds."
96
+ - "Use GitHub-hosted runners for LFS-heavy workflows to avoid manual git-lfs installation and configuration."
97
+ docs:
98
+ - url: "https://stackoverflow.com/questions/61463578/github-actions-actions-checkoutv2-lfs-true-flag-not-converting-pointers-to-actual-files"
99
+ label: "Stack Overflow: actions/checkout lfs:true not converting pointers to actual files (Score: 48, 21K views)"
100
+ - url: "https://github.com/actions/checkout#usage"
101
+ label: "actions/checkout: lfs input documentation"
102
+ - url: "https://docs.github.com/en/repositories/working-with-files/managing-large-files/about-git-large-file-storage"
103
+ label: "GitHub Docs: About Git Large File Storage"
104
+ - url: "https://docs.github.com/en/billing/managing-billing-for-your-products/managing-billing-for-git-large-file-storage/about-billing-for-git-large-file-storage"
105
+ label: "GitHub Docs: About billing for Git LFS"
@@ -0,0 +1,115 @@
1
+ id: silent-failures-030
2
+ title: "Reusable Workflow Output Silently Dropped When Value Contains a Secret Substring"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - reusable-workflows
7
+ - secrets-masking
8
+ - workflow-outputs
9
+ - workflow-call
10
+ - secret-substring
11
+ - output-propagation
12
+ patterns:
13
+ - regex: "Skip output '\\w+' since it may contain secret"
14
+ flags: "i"
15
+ - regex: "Skip output.*may contain secret"
16
+ flags: "i"
17
+ error_messages:
18
+ - "Skip output 'file-url' since it may contain secret."
19
+ - "Skip output 'artifact-path' since it may contain secret."
20
+ - "Skip output 'deploy-url' since it may contain secret."
21
+ root_cause: |
22
+ When a reusable workflow (called via `workflow_call`) propagates a workflow-level `output`
23
+ whose value contains a substring matching any registered secret, the runner **silently drops
24
+ the entire output** and logs "Skip output 'X' since it may contain secret." in the callee
25
+ workflow's log. The calling workflow's `needs.<job>.outputs.X` resolves to an empty string
26
+ with no error or warning in the caller's logs.
27
+
28
+ The runner performs substring matching — if ANY registered secret appears anywhere within the
29
+ output string (even as a short substring), the runner refuses to propagate the output. Common
30
+ triggers:
31
+ - S3 URLs where part of the bucket path matches an AWS access key fragment
32
+ - File paths with directory components that happen to match a short registered secret
33
+ - Outputs containing account IDs, port numbers, or other short secrets that appear in
34
+ longer strings by coincidence
35
+ - Base64-encoded outputs whose encoding coincidentally contains a secret substring
36
+
37
+ This is distinct from `job-output-masked-as-secret-empty` (regular job step outputs masked
38
+ by actions/runner#1498). The "Skip output" message only appears in reusable workflow output
39
+ propagation and is ONLY visible in the callee's log — the caller shows no warning, making
40
+ diagnosis extremely difficult.
41
+ fix: |
42
+ Avoid including values that contain (or match substrings of) registered secrets in reusable
43
+ workflow outputs. Structural approaches:
44
+
45
+ 1. **Return only the non-secret portion** of a path or URL, and reconstruct the full value
46
+ in the calling workflow using `vars` context or a known prefix.
47
+ 2. **Use artifacts** (`actions/upload-artifact` / `actions/download-artifact`) to pass files
48
+ or large data payloads between the callee and caller instead of workflow outputs.
49
+ 3. **Check callee logs** for "Skip output" messages — they are invisible from the caller side.
50
+ 4. **Review short secrets**: secrets shorter than ~8 characters risk false-positive substring
51
+ matches. Consider rotating short secrets to longer values.
52
+ fix_code:
53
+ - language: yaml
54
+ label: "Return non-secret path portion; reconstruct in caller"
55
+ code: |
56
+ # ❌ BROKEN: output contains secret substring (S3 bucket name matches a secret)
57
+ on:
58
+ workflow_call:
59
+ outputs:
60
+ artifact-url:
61
+ value: ${{ jobs.build.outputs.url }} # silently skipped if URL contains secret
62
+ jobs:
63
+ build:
64
+ runs-on: ubuntu-latest
65
+ outputs:
66
+ url: ${{ steps.upload.outputs.file-url }}
67
+ steps:
68
+ - id: upload
69
+ run: |
70
+ echo "file-url=https://s3.amazonaws.com/${{ secrets.BUCKET_NAME }}/build-${{ github.run_id }}.zip" \
71
+ >> "$GITHUB_OUTPUT"
72
+
73
+ ---
74
+
75
+ # ✅ WORKAROUND: return only the non-secret key; caller prepends known S3 prefix
76
+ on:
77
+ workflow_call:
78
+ outputs:
79
+ artifact-key:
80
+ value: ${{ jobs.build.outputs.key }} # just "build-12345678.zip" — no secret
81
+ jobs:
82
+ build:
83
+ runs-on: ubuntu-latest
84
+ outputs:
85
+ key: ${{ steps.upload.outputs.key }}
86
+ steps:
87
+ - id: upload
88
+ run: echo "key=build-${{ github.run_id }}.zip" >> "$GITHUB_OUTPUT"
89
+ - language: yaml
90
+ label: "Use artifacts to pass files between reusable workflow and caller"
91
+ code: |
92
+ # In the reusable workflow job:
93
+ - uses: actions/upload-artifact@v4
94
+ with:
95
+ name: build-output-${{ github.run_id }}
96
+ path: dist/
97
+
98
+ # In the calling workflow job (after the reusable workflow completes):
99
+ - uses: actions/download-artifact@v4
100
+ with:
101
+ name: build-output-${{ github.run_id }}
102
+ path: dist/
103
+ prevention:
104
+ - "Never include secret-containing values (URLs, paths, credentials) as reusable workflow outputs."
105
+ - "Reserve workflow outputs for short, non-sensitive metadata: version strings, boolean flags, run IDs."
106
+ - "Use artifacts for any data payload that might contain a value related to a registered secret."
107
+ - "Always check callee workflow logs — not just caller logs — for 'Skip output' messages."
108
+ - "Register secrets that are long and unique enough not to appear as substrings in build output values."
109
+ docs:
110
+ - url: "https://stackoverflow.com/questions/72536256/output-in-reusable-workflow-is-incorrectly-recognized-as-secret-github-actions"
111
+ label: "SO#72536256 — Output incorrectly recognized as secret in reusable workflow (5,709 views)"
112
+ - url: "https://stackoverflow.com/questions/75061897/github-actions-incorrectly-thinks-variable-is-a-secret-and-so-does-not-set-outpu"
113
+ label: "SO#75061897 — Actions incorrectly thinks variable is a secret (2,780 views)"
114
+ - url: "https://docs.github.com/en/actions/sharing-automations/reusing-workflows#using-outputs-from-a-reusable-workflow"
115
+ label: "GitHub Docs: Using outputs from a reusable workflow"
@@ -0,0 +1,105 @@
1
+ id: silent-failures-028
2
+ title: "setup-node Silently Exits 0 Without Installing Node.js on Self-Hosted Runners"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - setup-node
7
+ - self-hosted
8
+ - download-failure
9
+ - silent-exit
10
+ - node-not-found
11
+ patterns:
12
+ - regex: 'Attempting to download [0-9]+\.[0-9]+\.[0-9]+\.\.\.'
13
+ flags: "i"
14
+ - regex: "exec: node: not found"
15
+ flags: "i"
16
+ - regex: "node: not found"
17
+ flags: "i"
18
+ error_messages:
19
+ - "Attempting to download 24.15.0..."
20
+ - "exec: node: not found"
21
+ - "node: not found"
22
+ - "/usr/bin/bash: node: not found"
23
+ root_cause: |
24
+ On self-hosted runners (particularly those using `gha-runner-scale-set` or ephemeral
25
+ ARC runners), `actions/setup-node` can sporadically print
26
+ "Attempting to download <version>..." and then silently exit 0 without completing
27
+ the download or install.
28
+
29
+ The step outcome is `success` and the runner logs show no error — the action
30
+ simply returns without installing Node.js. Subsequent steps that invoke `node`,
31
+ `npm`, `pnpm`, or other Node-dependent tools then fail with "exec: node: not found"
32
+ or equivalent errors, which are far from the actual root cause.
33
+
34
+ This is a transient network or HTTP client failure in the `@actions/tool-cache`
35
+ download path. When the initial download attempt encounters a non-fatal HTTP error
36
+ (connection reset, early EOF, or interrupted read), the action sometimes swallows
37
+ the error and exits cleanly rather than retrying or calling `core.setFailed()`.
38
+ The issue is more common on self-hosted runners where network conditions are more
39
+ variable than on GitHub-hosted runners.
40
+
41
+ The action version affected is v6.x on self-hosted runners with `gha-runner-scale-set`
42
+ 0.13.x and runner 2.334.x. Retrying the job almost always succeeds.
43
+ fix: |
44
+ Add an explicit Node version verification step after setup-node to catch silent
45
+ failures before they cause confusing downstream errors:
46
+
47
+ - run: node --version
48
+
49
+ If this step fails, the issue is with setup-node — not the downstream tool.
50
+
51
+ For persistent failures, add a retry wrapper around setup-node, or use the
52
+ runner's pre-installed Node.js version as a fallback by pinning node-version
53
+ to the runner's system Node.
54
+
55
+ Long-term: upgrade to the latest setup-node patch release — several network
56
+ resilience improvements have been made to the download path. File an issue at
57
+ actions/setup-node with runner version, scale-set version, and the relevant
58
+ log section.
59
+ fix_code:
60
+ - language: yaml
61
+ label: "Add immediate verification to catch silent download failure"
62
+ code: |
63
+ steps:
64
+ - uses: actions/checkout@v4
65
+ - uses: actions/setup-node@v6
66
+ with:
67
+ node-version-file: .nvmrc
68
+ cache: pnpm
69
+
70
+ # Catch silent exit-0 failures immediately
71
+ - name: Verify Node.js installed
72
+ run: |
73
+ node --version || (echo "::error::setup-node silently failed — Node.js not installed" && exit 1)
74
+ npm --version
75
+
76
+ - run: pnpm install --frozen-lockfile
77
+ - language: yaml
78
+ label: "Retry wrapper using nick-invision/retry"
79
+ code: |
80
+ steps:
81
+ - uses: actions/checkout@v4
82
+ - name: Setup Node.js with retry
83
+ uses: nick-invision/retry@v3
84
+ with:
85
+ timeout_minutes: 5
86
+ max_attempts: 3
87
+ command: |
88
+ # Re-run setup-node inline
89
+ echo "Attempt ${{ github.run_attempt }}"
90
+ - uses: actions/setup-node@v6
91
+ with:
92
+ node-version: 24
93
+ prevention:
94
+ - "Always add a node --version step after setup-node on self-hosted runners to catch silent failures."
95
+ - "Use check-latest: true to ensure the action validates the installed version before proceeding."
96
+ - "Report sporadic failures with full runner version, scale-set version, and log output to actions/setup-node."
97
+ - "Consider using the runner's pre-cached Node.js version (omit node-version) to avoid downloads on self-hosted runners."
98
+ - "Monitor for setup-node step outcome === 'success' followed by downstream node-not-found — this pattern indicates silent download failure."
99
+ docs:
100
+ - url: "https://github.com/actions/setup-node/issues/1555"
101
+ label: "actions/setup-node#1555: Sporadic silent failure when downloading Node.js (12 reactions)"
102
+ - url: "https://github.com/actions/download-artifact/issues/454"
103
+ label: "actions/download-artifact#454: Related silent download failure pattern"
104
+ - url: "https://github.com/actions/toolkit/tree/main/packages/tool-cache"
105
+ label: "actions/toolkit: tool-cache package (download internals)"
@@ -0,0 +1,111 @@
1
+ id: silent-failures-029
2
+ title: "setup-python Silently Exits 0 Without Installing Python When versions-manifest.json Is Truncated"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - setup-python
7
+ - versions-manifest
8
+ - silent-exit
9
+ - truncated-response
10
+ - python-not-installed
11
+ patterns:
12
+ - regex: "evaluating 0 versions"
13
+ flags: "i"
14
+ - regex: "Version .+ was not found in the local cache"
15
+ flags: "i"
16
+ - regex: "Node Action run completed with exit code 0"
17
+ flags: "i"
18
+ error_messages:
19
+ - "evaluating 0 versions"
20
+ - "Version 3.11 - 3.13 was not found in the local cache"
21
+ - "Getting manifest from actions/python-versions@main"
22
+ - "##[debug]Node Action run completed with exit code 0"
23
+ - "##[debug]Finishing: Setup python"
24
+ root_cause: |
25
+ `actions/setup-python` fetches `versions-manifest.json` from the
26
+ `actions/python-versions` repository via two GitHub API calls:
27
+
28
+ 1. A git tree request to locate the blob URL.
29
+ 2. A raw blob fetch with `Accept: application/vnd.github.VERSION.raw`.
30
+
31
+ Sporadically, the second call returns HTTP 200 with a **truncated body** — the
32
+ JSON is cut off mid-object and unparseable. The action catches the JSON parse
33
+ error silently, treats the result as an empty release list, logs
34
+ "evaluating 0 versions", and exits with code 0 **without installing Python**.
35
+
36
+ The truncated response has two consistent symptoms:
37
+ - A ~30-second server-side delay before any bytes arrive.
38
+ - Only affects authenticated requests (5,000 req/hour tier); anonymous requests
39
+ return the full manifest, but the 60 req/hour limit is too low for real CI.
40
+
41
+ After the step exits 0, subsequent steps that call `python`, `pip`, or `python3`
42
+ either use the system Python (which may differ in version) or fail with
43
+ "python: not found" — neither of which points back to the manifest fetch failure.
44
+ fix: |
45
+ Add an explicit Python version check immediately after setup-python to catch the
46
+ silent exit before it causes confusing downstream errors:
47
+
48
+ - run: python --version
49
+
50
+ For a more robust workaround, set `python-version` to an exact version string
51
+ (e.g., "3.11.9") rather than a range — exact versions can fall back to the
52
+ runner's pre-cached toolcache without requiring a manifest fetch.
53
+
54
+ If you must use a version range, add a shell-level retry loop around the Python
55
+ invocation, or use the `setup-python` `check-latest: false` option with a pinned
56
+ version to reduce manifest fetches.
57
+
58
+ File the issue with captured truncated manifest bodies at actions/setup-python
59
+ to help maintainers add retry-with-backoff logic to the manifest fetch path.
60
+ fix_code:
61
+ - language: yaml
62
+ label: "Catch silent exit immediately after setup-python"
63
+ code: |
64
+ steps:
65
+ - uses: actions/setup-python@v5
66
+ with:
67
+ python-version: "3.11 - 3.13"
68
+ cache: pip
69
+
70
+ # Catch silent manifest-fetch failure before downstream confusion
71
+ - name: Verify Python installed
72
+ run: |
73
+ python --version || (echo "::error::setup-python silently failed — Python not installed" && exit 1)
74
+ pip --version
75
+
76
+ - run: pip install -r requirements.txt
77
+ - language: yaml
78
+ label: "Use exact version to avoid manifest fetch entirely (uses toolcache)"
79
+ code: |
80
+ steps:
81
+ - uses: actions/setup-python@v5
82
+ with:
83
+ python-version: "3.11.9" # exact version — uses pre-cached toolcache
84
+ cache: pip # no manifest fetch needed for exact match
85
+ - run: python --version
86
+ - run: pip install -r requirements.txt
87
+ - language: yaml
88
+ label: "Use .python-version file for explicit pinning"
89
+ code: |
90
+ # .python-version file: 3.12.7
91
+ steps:
92
+ - uses: actions/setup-python@v5
93
+ with:
94
+ python-version-file: .python-version # exact pin, no manifest range fetch
95
+ cache: pip
96
+ - run: python --version
97
+ prevention:
98
+ - "Always add a python --version verification step after setup-python to surface silent failures immediately."
99
+ - "Pin to an exact Python version (e.g., '3.11.9') rather than a range to use the pre-cached toolcache and avoid manifest fetches."
100
+ - "Use a .python-version file for reproducible, exact pinning that also works with pyenv locally."
101
+ - "Monitor for the symptom pattern: setup-python exits 0 + 'evaluating 0 versions' + downstream python-not-found."
102
+ - "If using version ranges, run setup-python with cache: false first in a debug context to isolate manifest vs. cache failures."
103
+ docs:
104
+ - url: "https://github.com/actions/setup-python/issues/1318"
105
+ label: "actions/setup-python#1318: setup-python silently exits 0 on truncated versions-manifest.json"
106
+ - url: "https://github.com/actions/python-versions"
107
+ label: "actions/python-versions: Source of versions-manifest.json"
108
+ - url: "https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#specifying-a-python-version"
109
+ label: "GitHub Docs: Specifying a Python version"
110
+ - url: "https://github.com/actions/setup-python/blob/main/docs/advanced-usage.md"
111
+ label: "setup-python: Advanced Usage"