@htekdev/actions-debugger 1.0.13 → 1.0.15
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/dist/db/search.js +3 -1
- package/dist/db/search.js.map +1 -1
- package/dist/tools/suggest-fix.d.ts.map +1 -1
- package/dist/tools/suggest-fix.js +5 -1
- package/dist/tools/suggest-fix.js.map +1 -1
- package/errors/caching-artifacts/cache-key-too-long.yml +93 -0
- package/errors/caching-artifacts/cache-path-not-exist-skipped.yml +152 -0
- package/errors/caching-artifacts/docker-buildx-gha-cache-capacity.yml +107 -0
- package/errors/caching-artifacts/setup-ruby-bundler-ephemeral-workdir-cache-miss.yml +147 -0
- package/errors/caching-artifacts/upload-artifact-v3-retirement-blocked.yml +123 -0
- package/errors/concurrency-timing/always-cleanup-5min-forced-kill.yml +140 -0
- package/errors/concurrency-timing/concurrency-group-env-context-undefined.yml +99 -0
- package/errors/concurrency-timing/required-check-pending-path-filter-skip.yml +160 -0
- package/errors/concurrency-timing/wait-timer-cancel-in-progress-starvation.yml +125 -0
- package/errors/known-unsolved/composite-action-step-timeout-minutes-ignored.yml +146 -0
- package/errors/known-unsolved/reusable-workflow-no-composite-action-call.yml +116 -0
- package/errors/known-unsolved/schedule-trigger-default-branch-only.yml +113 -0
- package/errors/known-unsolved/secrets-not-allowed-in-if-conditions.yml +149 -0
- package/errors/permissions-auth/dependabot-pr-secrets-unavailable.yml +133 -0
- package/errors/permissions-auth/fine-grained-pat-deployment-write-required.yml +146 -0
- package/errors/permissions-auth/github-app-installation-token-new-format.yml +124 -0
- package/errors/permissions-auth/github-packages-read-requires-packages-permission.yml +128 -0
- package/errors/permissions-auth/oidc-id-token-write-permission-missing.yml +169 -0
- package/errors/permissions-auth/permissions-empty-block-removes-contents-read.yml +97 -0
- package/errors/permissions-auth/reusable-workflow-permissions-not-inherited.yml +114 -0
- package/errors/runner-environment/az-powershell-14-to-15-breaking.yml +108 -0
- package/errors/runner-environment/checkout-windows-ebusy-lock.yml +124 -0
- package/errors/runner-environment/deprecated-action-version-auto-rejected.yml +89 -0
- package/errors/runner-environment/github-hosted-runner-disk-space-full.yml +85 -0
- package/errors/runner-environment/github-path-same-step-not-found.yml +114 -0
- package/errors/runner-environment/github-script-v6-octokit-rest-actions-not-function.yml +87 -0
- package/errors/runner-environment/macos-15-mono-nuget-removed.yml +151 -0
- package/errors/runner-environment/macos-15-xcode-simulator-sdk-policy.yml +141 -0
- package/errors/runner-environment/runner-oom-exit-code-137.yml +117 -0
- package/errors/runner-environment/setup-go-go123-telemetry-cache-failure.yml +92 -0
- package/errors/runner-environment/setup-java-distribution-required.yml +108 -0
- package/errors/runner-environment/ubuntu-2204-precached-docker-removed.yml +110 -0
- package/errors/runner-environment/windows-latest-d-drive-removed.yml +104 -0
- package/errors/runner-environment/windows-msvc-ltcg-mixed-image-versions.yml +112 -0
- package/errors/runner-environment/windows-vs2026-cuda-host-compiler-unsupported.yml +145 -0
- package/errors/silent-failures/app-store-ios26-sdk-required.yml +113 -0
- package/errors/silent-failures/event-commits-empty-on-workflow-dispatch.yml +110 -0
- package/errors/silent-failures/fetch-tags-depth-one-silent-no-op.yml +77 -0
- package/errors/silent-failures/github-env-multiline-value-truncated.yml +127 -0
- package/errors/silent-failures/github-sha-pr-merge-commit-not-head.yml +150 -0
- package/errors/silent-failures/job-output-masked-as-secret-empty.yml +147 -0
- package/errors/silent-failures/upload-artifact-permissions-stripped.yml +98 -0
- package/errors/triggers/pull-request-branches-filter-matches-base-not-head.yml +140 -0
- package/errors/triggers/push-event-fires-on-branch-delete.yml +129 -0
- package/errors/triggers/push-first-commit-before-sha-zeros.yml +160 -0
- package/errors/yaml-syntax/fromjson-empty-string-crash.yml +99 -0
- package/errors/yaml-syntax/if-bang-negation-yaml-tag.yml +145 -0
- package/errors/yaml-syntax/local-action-path-always-top-level.yml +142 -0
- package/package.json +1 -1
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
id: silent-failures-017
|
|
2
|
+
title: "iOS App Store Upload Fails Silently — macOS-latest Uses Xcode 16.4 but Apple Requires iOS 26 SDK"
|
|
3
|
+
category: silent-failures
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- macos
|
|
7
|
+
- xcode
|
|
8
|
+
- ios
|
|
9
|
+
- app-store
|
|
10
|
+
- sdk
|
|
11
|
+
- silent-failure
|
|
12
|
+
- apple
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: "built with the iOS (?:18|17|16)\\.\\d SDK"
|
|
15
|
+
flags: "i"
|
|
16
|
+
- regex: "must be built with the iOS 26 SDK or later.*App Store"
|
|
17
|
+
flags: "i"
|
|
18
|
+
- regex: "Invalid Toolchain.*iOS.*SDK.*required"
|
|
19
|
+
flags: "i"
|
|
20
|
+
- regex: "ITMS-90725|ITMS-90206"
|
|
21
|
+
flags: "i"
|
|
22
|
+
error_messages:
|
|
23
|
+
- "This app was built with the iOS 18.5 SDK. All iOS and iPadOS apps must be built with the iOS 26 SDK or later in order to be uploaded to App Store Connect."
|
|
24
|
+
- "ERROR ITMS-90725: SDK Version Issue - This app was built with the iOS 18.5 SDK"
|
|
25
|
+
- "Invalid Toolchain. New apps and app updates must be built with the public iOS 26 SDK or later"
|
|
26
|
+
root_cause: |
|
|
27
|
+
Apple requires that all new iOS/iPadOS App Store submissions be built with the
|
|
28
|
+
iOS 26 SDK or later (enforced starting mid-2026). However, `macos-latest` currently
|
|
29
|
+
points to macOS 15 (until the macOS 26 migration completes in July 2026), and
|
|
30
|
+
macOS 15 runner images ship with Xcode 16.4 as the default — which includes the
|
|
31
|
+
iOS 18.5 SDK, NOT the iOS 26 SDK.
|
|
32
|
+
|
|
33
|
+
The failure is a classic silent-failure pattern:
|
|
34
|
+
- The build step SUCCEEDS with zero errors or warnings.
|
|
35
|
+
- The archive step SUCCEEDS.
|
|
36
|
+
- The upload/export to App Store Connect FAILS with the SDK version error.
|
|
37
|
+
- Because the failure occurs at the distribution stage (not compilation), it
|
|
38
|
+
can be misdiagnosed as a signing, provisioning, or network issue.
|
|
39
|
+
|
|
40
|
+
Workflows that use `uses: maxim-lobanov/setup-xcode` with an explicit 16.x version,
|
|
41
|
+
or that rely on `macos-latest` defaults without explicit Xcode pinning, will
|
|
42
|
+
silently produce an .ipa or .xcarchive that cannot be submitted to App Store Connect.
|
|
43
|
+
|
|
44
|
+
After the `macos-latest` migration to macOS 26 completes (July 15, 2026), the default
|
|
45
|
+
Xcode will be 26.4.1+, which includes the iOS 26 SDK and resolves this issue.
|
|
46
|
+
Until then, explicit Xcode pinning is required.
|
|
47
|
+
|
|
48
|
+
Source: actions/runner-images#14165
|
|
49
|
+
fix: |
|
|
50
|
+
**Immediate fix**: Pin Xcode to 26.x explicitly using `maxim-lobanov/setup-xcode`
|
|
51
|
+
before any build or archive steps. Use `macos-26` as the runner to ensure Xcode 26
|
|
52
|
+
is available.
|
|
53
|
+
|
|
54
|
+
**For teams not ready to migrate to Xcode 26**: Use `macos-26` and pin to Xcode 26.4.1
|
|
55
|
+
or later — this is required by Apple regardless of code changes.
|
|
56
|
+
|
|
57
|
+
**Verify the SDK in use** by adding `xcodebuild -showsdks` before the build step.
|
|
58
|
+
fix_code:
|
|
59
|
+
- language: yaml
|
|
60
|
+
label: "Pin to macOS 26 + Xcode 26 for App Store submissions"
|
|
61
|
+
code: |
|
|
62
|
+
jobs:
|
|
63
|
+
release:
|
|
64
|
+
runs-on: macos-26 # Explicit: don't rely on macos-latest during transition
|
|
65
|
+
steps:
|
|
66
|
+
- uses: actions/checkout@v4
|
|
67
|
+
|
|
68
|
+
# Explicitly select Xcode 26 (includes iOS 26 SDK required by App Store)
|
|
69
|
+
- uses: maxim-lobanov/setup-xcode@v1
|
|
70
|
+
with:
|
|
71
|
+
xcode-version: '26.4' # or '26.5' once generally available
|
|
72
|
+
|
|
73
|
+
- name: Verify SDK
|
|
74
|
+
run: xcodebuild -showsdks | grep -i iphoneos
|
|
75
|
+
|
|
76
|
+
- name: Archive
|
|
77
|
+
run: |
|
|
78
|
+
xcodebuild archive \
|
|
79
|
+
-scheme MyApp \
|
|
80
|
+
-archivePath $RUNNER_TEMP/MyApp.xcarchive \
|
|
81
|
+
-destination generic/platform=iOS
|
|
82
|
+
|
|
83
|
+
- name: Export for App Store
|
|
84
|
+
run: |
|
|
85
|
+
xcodebuild -exportArchive \
|
|
86
|
+
-archivePath $RUNNER_TEMP/MyApp.xcarchive \
|
|
87
|
+
-exportOptionsPlist ExportOptions.plist \
|
|
88
|
+
-exportPath $RUNNER_TEMP/MyApp.ipa
|
|
89
|
+
- language: yaml
|
|
90
|
+
label: "Check installed Xcode versions and default SDK (diagnosis)"
|
|
91
|
+
code: |
|
|
92
|
+
- name: Diagnose Xcode and SDK versions
|
|
93
|
+
run: |
|
|
94
|
+
echo "=== Default Xcode ==="
|
|
95
|
+
xcode-select -p
|
|
96
|
+
xcodebuild -version
|
|
97
|
+
echo "=== Available SDKs ==="
|
|
98
|
+
xcodebuild -showsdks | grep -i iphone
|
|
99
|
+
prevention:
|
|
100
|
+
- "Never rely on `macos-latest` default Xcode for App Store release builds — always pin the Xcode version explicitly."
|
|
101
|
+
- "Use `xcodebuild -showsdks` as an early workflow step to emit the active iOS SDK version to logs."
|
|
102
|
+
- "Run a smoke test of the App Store export (not just the build) in CI to catch SDK requirement errors before manual submission."
|
|
103
|
+
- "Subscribe to Apple Developer news for SDK requirement enforcement dates and plan runner image migrations in advance."
|
|
104
|
+
- "Pin `runs-on: macos-26` explicitly rather than `macos-latest` for release workflows during the macOS version transition period."
|
|
105
|
+
docs:
|
|
106
|
+
- url: "https://github.com/actions/runner-images/issues/14165"
|
|
107
|
+
label: "runner-images#14165 — macOS-latest Xcode 16.4 breaks App Store submissions"
|
|
108
|
+
- url: "https://github.com/actions/runner-images/issues/14167"
|
|
109
|
+
label: "runner-images#14167 — macos-latest will use macos-26 in June 2026"
|
|
110
|
+
- url: "https://github.com/maxim-lobanov/setup-xcode"
|
|
111
|
+
label: "maxim-lobanov/setup-xcode — Pin Xcode version in workflows"
|
|
112
|
+
- url: "https://developer.apple.com/news/releases/"
|
|
113
|
+
label: "Apple Developer News — SDK requirement announcements"
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
id: silent-failures-018
|
|
2
|
+
title: "github.event.commits and github.event.head_commit Are Null/Empty on Non-Push Triggers"
|
|
3
|
+
category: silent-failures
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- github-context
|
|
7
|
+
- workflow-dispatch
|
|
8
|
+
- schedule
|
|
9
|
+
- commits
|
|
10
|
+
- null-access
|
|
11
|
+
- push-event
|
|
12
|
+
- expression
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: "github\\.event\\.commits\\[0\\]"
|
|
15
|
+
flags: "i"
|
|
16
|
+
- regex: "github\\.event\\.head_commit\\.(message|id|author)"
|
|
17
|
+
flags: "i"
|
|
18
|
+
- regex: "github\\.event\\.commits is not iterable|Cannot read.*commits"
|
|
19
|
+
flags: "i"
|
|
20
|
+
error_messages:
|
|
21
|
+
- "Error: Cannot read properties of undefined (reading 'message')"
|
|
22
|
+
- "Error: github.event.commits[0] is undefined"
|
|
23
|
+
root_cause: |
|
|
24
|
+
The `github.event.commits` array and `github.event.head_commit` object are ONLY populated
|
|
25
|
+
for `push` webhook events. They are absent (null / empty array) for all other trigger types:
|
|
26
|
+
|
|
27
|
+
- `workflow_dispatch` — manual UI or API trigger, no commit context
|
|
28
|
+
- `schedule` — cron-triggered run, no specific push associated
|
|
29
|
+
- `pull_request` / `pull_request_target` — uses github.event.pull_request instead
|
|
30
|
+
- `workflow_call` — reusable workflow invocation, no commit array
|
|
31
|
+
- `repository_dispatch` — uses github.event.client_payload, no commits key
|
|
32
|
+
- `release` — uses github.event.release, no commits array
|
|
33
|
+
|
|
34
|
+
When a workflow is triggered on both `push` and `workflow_dispatch` (a common pattern),
|
|
35
|
+
expressions like:
|
|
36
|
+
${{ github.event.commits[0].message }}
|
|
37
|
+
${{ github.event.head_commit.id }}
|
|
38
|
+
|
|
39
|
+
silently evaluate to empty string ('') on non-push triggers rather than raising an error.
|
|
40
|
+
GitHub Actions treats missing context properties as empty string, so the step runs but
|
|
41
|
+
with blank or wrong data — the workflow shows green while producing incorrect output.
|
|
42
|
+
|
|
43
|
+
This is a silent failure because there is no error in the logs when the empty string is
|
|
44
|
+
used in a step (e.g., an echo, a tag, a release title). The problem only becomes visible
|
|
45
|
+
when the downstream artifact or message is inspected.
|
|
46
|
+
fix: |
|
|
47
|
+
Use git directly to extract commit information — it works reliably across all trigger types
|
|
48
|
+
(as long as fetch-depth is not 1 / uses default full clone or depth >= 2):
|
|
49
|
+
|
|
50
|
+
git log --format=%s -1 # subject line
|
|
51
|
+
git log --format=%H -1 # full SHA
|
|
52
|
+
git log --format=%ae -1 # author email
|
|
53
|
+
|
|
54
|
+
Alternatively, guard commit-context access with an event_name check, or use the
|
|
55
|
+
github.sha context (which IS available on all triggers) when a commit SHA is needed.
|
|
56
|
+
fix_code:
|
|
57
|
+
- language: yaml
|
|
58
|
+
label: "Portable commit message extraction via git (works on all triggers)"
|
|
59
|
+
code: |
|
|
60
|
+
jobs:
|
|
61
|
+
release:
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
steps:
|
|
64
|
+
- uses: actions/checkout@v4
|
|
65
|
+
with:
|
|
66
|
+
fetch-depth: 2 # depth >= 2 required for git log on non-push
|
|
67
|
+
|
|
68
|
+
- name: Get commit message (safe for push, workflow_dispatch, schedule)
|
|
69
|
+
id: meta
|
|
70
|
+
run: |
|
|
71
|
+
echo "sha=${{ github.sha }}" >> $GITHUB_OUTPUT
|
|
72
|
+
echo "message=$(git log --format=%s -1 ${{ github.sha }})" >> $GITHUB_OUTPUT
|
|
73
|
+
echo "author=$(git log --format=%ae -1 ${{ github.sha }})" >> $GITHUB_OUTPUT
|
|
74
|
+
|
|
75
|
+
- name: Use commit metadata
|
|
76
|
+
run: |
|
|
77
|
+
echo "SHA: ${{ steps.meta.outputs.sha }}"
|
|
78
|
+
echo "Message: ${{ steps.meta.outputs.message }}"
|
|
79
|
+
- language: yaml
|
|
80
|
+
label: "Guard push-only context with event_name check"
|
|
81
|
+
code: |
|
|
82
|
+
- name: Get commit message (push only)
|
|
83
|
+
if: github.event_name == 'push' && github.event.commits[0] != null
|
|
84
|
+
run: |
|
|
85
|
+
echo "COMMIT_MSG=${{ github.event.commits[0].message }}" >> $GITHUB_ENV
|
|
86
|
+
|
|
87
|
+
- name: Fallback for non-push triggers
|
|
88
|
+
if: github.event_name != 'push'
|
|
89
|
+
run: |
|
|
90
|
+
echo "COMMIT_MSG=$(git log --format=%s -1)" >> $GITHUB_ENV
|
|
91
|
+
- language: yaml
|
|
92
|
+
label: "Debug: dump full event payload to understand what is available"
|
|
93
|
+
code: |
|
|
94
|
+
- name: Debug — dump event context
|
|
95
|
+
run: echo '${{ toJSON(github.event) }}'
|
|
96
|
+
prevention:
|
|
97
|
+
- "Never access github.event.commits or github.event.head_commit without first checking github.event_name == 'push'."
|
|
98
|
+
- "Use `git log --format=%s -1 ${{ github.sha }}` for commit message extraction — it works on all trigger types."
|
|
99
|
+
- "Note that github.sha IS available on all triggers and points to the relevant commit; use it as a portable substitute for github.event.head_commit.id."
|
|
100
|
+
- "Add a debug step early in development to dump `${{ toJSON(github.event) }}` so you can see exactly what context is available for each trigger type."
|
|
101
|
+
- "Test workflows by triggering them manually via workflow_dispatch to catch push-only context assumptions before they hit production."
|
|
102
|
+
docs:
|
|
103
|
+
- url: "https://docs.github.com/en/webhooks/webhook-events-and-payloads#push"
|
|
104
|
+
label: "GitHub docs — push event payload (includes commits array)"
|
|
105
|
+
- url: "https://docs.github.com/en/webhooks/webhook-events-and-payloads#workflow_dispatch"
|
|
106
|
+
label: "GitHub docs — workflow_dispatch event payload (no commits array)"
|
|
107
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/accessing-contextual-information-about-workflow-runs#github-context"
|
|
108
|
+
label: "GitHub docs — github context reference"
|
|
109
|
+
- url: "https://github.com/orgs/community/discussions/27058"
|
|
110
|
+
label: "Community discussion — github.event.commits undefined on workflow_dispatch"
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
id: silent-failures-022
|
|
2
|
+
title: "fetch-tags: true Silently Fetches No Tags When fetch-depth Is 1"
|
|
3
|
+
category: silent-failures
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- checkout
|
|
7
|
+
- fetch-tags
|
|
8
|
+
- shallow-clone
|
|
9
|
+
- fetch-depth
|
|
10
|
+
- git-tags
|
|
11
|
+
- versioning
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: "No tags found|no tags found"
|
|
14
|
+
flags: "i"
|
|
15
|
+
- regex: "fatal: No names found, cannot describe anything"
|
|
16
|
+
flags: "i"
|
|
17
|
+
- regex: "CHANGELOG.*No tag found"
|
|
18
|
+
flags: "i"
|
|
19
|
+
error_messages:
|
|
20
|
+
- "fatal: No names found, cannot describe anything"
|
|
21
|
+
- "No tags found. Try unshallowing the repository"
|
|
22
|
+
- "CHANGELOG ERROR: No tag found on HEAD"
|
|
23
|
+
- "Error: No tags matching '*' found, exiting"
|
|
24
|
+
root_cause: |
|
|
25
|
+
The `fetch-tags: true` option in `actions/checkout` was introduced in v3.6.0 to restore tag
|
|
26
|
+
fetching after `--no-tags` was made the default for shallow clones. However, when `fetch-depth`
|
|
27
|
+
remains at its default value of `1` (shallow clone), the tag fetch silently produces no results.
|
|
28
|
+
|
|
29
|
+
With a shallow clone, git only downloads a single commit. Tags are only present if they point
|
|
30
|
+
directly to that one commit — i.e., the workflow was triggered by a tag push. In all other
|
|
31
|
+
cases, `fetch-tags: true` appears to succeed (no error, no warning) but `git tag -l` returns
|
|
32
|
+
empty results.
|
|
33
|
+
|
|
34
|
+
This silently breaks tools that depend on git tags for versioning: semantic-release,
|
|
35
|
+
commitizen, standard-version, cargo-smart-release, setuptools-scm, and any script using
|
|
36
|
+
`git describe --tags`. Builds succeed but produce wrong version numbers (often 0.0.0 or
|
|
37
|
+
commit-hash-only versions).
|
|
38
|
+
fix: |
|
|
39
|
+
Pair `fetch-tags: true` with `fetch-depth: 0` to fetch the full history including all tags.
|
|
40
|
+
On very large repositories, use `filter: tree:0` for a blobless partial clone that still
|
|
41
|
+
includes complete tag history. As a targeted workaround, add a second step to fetch only
|
|
42
|
+
tags after a shallow checkout.
|
|
43
|
+
fix_code:
|
|
44
|
+
- language: yaml
|
|
45
|
+
label: "Recommended: full history with all tags"
|
|
46
|
+
code: |
|
|
47
|
+
- uses: actions/checkout@v4
|
|
48
|
+
with:
|
|
49
|
+
fetch-depth: 0 # full history required for tags
|
|
50
|
+
fetch-tags: true # fetch all tags
|
|
51
|
+
- language: yaml
|
|
52
|
+
label: "Large repos: blobless filter (faster, still includes tags)"
|
|
53
|
+
code: |
|
|
54
|
+
- uses: actions/checkout@v4
|
|
55
|
+
with:
|
|
56
|
+
fetch-depth: 0
|
|
57
|
+
filter: tree:0 # blobless clone — avoids downloading file blobs
|
|
58
|
+
fetch-tags: true
|
|
59
|
+
- language: yaml
|
|
60
|
+
label: "Workaround: shallow checkout + separate tag fetch step"
|
|
61
|
+
code: |
|
|
62
|
+
- uses: actions/checkout@v4
|
|
63
|
+
with:
|
|
64
|
+
fetch-depth: 1
|
|
65
|
+
- name: Fetch all tags
|
|
66
|
+
run: git fetch --prune --unshallow --tags
|
|
67
|
+
prevention:
|
|
68
|
+
- "Always pair `fetch-tags: true` with `fetch-depth: 0` unless the workflow is only triggered by tag pushes"
|
|
69
|
+
- "Add `git tag -l` as a debug step in release workflows to verify tags are present after checkout"
|
|
70
|
+
- "If using semantic-release or similar, test your version script locally with a shallow clone to catch this early"
|
|
71
|
+
docs:
|
|
72
|
+
- url: "https://github.com/actions/checkout/issues/1471"
|
|
73
|
+
label: "actions/checkout#1471 — fetch-tags: true doesn't actually fetch any tags (126 reactions)"
|
|
74
|
+
- url: "https://github.com/actions/checkout/issues/1467"
|
|
75
|
+
label: "actions/checkout#1467 — related: no-tags default behavior"
|
|
76
|
+
- url: "https://github.com/actions/checkout#usage"
|
|
77
|
+
label: "actions/checkout — fetch-tags and fetch-depth inputs documentation"
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
id: silent-failures-019
|
|
2
|
+
title: "GITHUB_ENV Multiline Values Silently Truncate Without Heredoc Delimiter Format"
|
|
3
|
+
category: silent-failures
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- GITHUB_ENV
|
|
7
|
+
- environment-variable
|
|
8
|
+
- multiline
|
|
9
|
+
- heredoc
|
|
10
|
+
- truncation
|
|
11
|
+
- env-file
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: "GITHUB_ENV.*multiline|multiline.*GITHUB_ENV"
|
|
14
|
+
flags: "i"
|
|
15
|
+
- regex: "Invalid format '.*\\n'"
|
|
16
|
+
flags: "i"
|
|
17
|
+
- regex: "Error: Failed to parse environment file"
|
|
18
|
+
flags: "i"
|
|
19
|
+
error_messages:
|
|
20
|
+
- "Error: Failed to parse environment file"
|
|
21
|
+
- "Invalid format 'MY_VAR=line1\nline2'"
|
|
22
|
+
- "Warning: Environment file exporting failed"
|
|
23
|
+
root_cause: |
|
|
24
|
+
When setting an environment variable with `$GITHUB_ENV` that contains **newline
|
|
25
|
+
characters**, naïvely echoing the value produces an invalid environment file entry
|
|
26
|
+
that is silently truncated or causes a parse error.
|
|
27
|
+
|
|
28
|
+
The environment file format used by GitHub Actions expects single-line `KEY=VALUE`
|
|
29
|
+
entries. If a value contains a literal newline, the runner cannot parse it and
|
|
30
|
+
typically:
|
|
31
|
+
- Silently truncates the value at the first newline (the variable gets only the
|
|
32
|
+
first line)
|
|
33
|
+
- In strict runner versions: fails with "Error: Failed to parse environment file"
|
|
34
|
+
|
|
35
|
+
**Common incorrect pattern:**
|
|
36
|
+
```yaml
|
|
37
|
+
run: echo "MY_CERT=${{ secrets.CERT }}" >> $GITHUB_ENV
|
|
38
|
+
# If CERT contains newlines, the env file entry is broken
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Why it's a silent failure:**
|
|
42
|
+
- The step succeeds with exit code 0
|
|
43
|
+
- No obvious error message appears in the logs
|
|
44
|
+
- Downstream steps see a truncated, incomplete variable value
|
|
45
|
+
- Certificate/JSON/SSH key values are commonly multi-line and hit this silently
|
|
46
|
+
|
|
47
|
+
This is separate from the `$GITHUB_OUTPUT` multiline issue (which uses the same
|
|
48
|
+
heredoc syntax fix) — the root cause and pattern are identical but the environment
|
|
49
|
+
file (`GITHUB_ENV`) is a distinct file from the output file (`GITHUB_OUTPUT`).
|
|
50
|
+
|
|
51
|
+
Sources: GitHub Community #160171, GitHub Docs workflow commands
|
|
52
|
+
fix: |
|
|
53
|
+
Use the **heredoc delimiter format** for multiline values in `$GITHUB_ENV`:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
KEY<<DELIMITER
|
|
57
|
+
value-line-1
|
|
58
|
+
value-line-2
|
|
59
|
+
DELIMITER
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The delimiter can be any string that does not appear in the value. `EOF` is the
|
|
63
|
+
conventional choice. The delimiter must appear on its own line both as the opening
|
|
64
|
+
marker and the closing marker.
|
|
65
|
+
|
|
66
|
+
This same pattern applies to `$GITHUB_OUTPUT` for multiline step outputs.
|
|
67
|
+
fix_code:
|
|
68
|
+
- language: yaml
|
|
69
|
+
label: "Broken — newline in value breaks the env file silently"
|
|
70
|
+
code: |
|
|
71
|
+
# ❌ BROKEN: Secret or cert value with newlines truncates silently
|
|
72
|
+
- name: Set multiline env var
|
|
73
|
+
run: echo "MY_CERT=${{ secrets.TLS_CERT }}" >> $GITHUB_ENV
|
|
74
|
+
# Result: MY_CERT contains only the first line of the certificate
|
|
75
|
+
- language: yaml
|
|
76
|
+
label: "Fixed — heredoc delimiter format for multiline GITHUB_ENV values"
|
|
77
|
+
code: |
|
|
78
|
+
# ✅ FIXED: Use heredoc delimiter syntax
|
|
79
|
+
- name: Set multiline env var
|
|
80
|
+
run: |
|
|
81
|
+
echo "MY_CERT<<EOF" >> $GITHUB_ENV
|
|
82
|
+
echo "${{ secrets.TLS_CERT }}" >> $GITHUB_ENV
|
|
83
|
+
echo "EOF" >> $GITHUB_ENV
|
|
84
|
+
- language: yaml
|
|
85
|
+
label: "Fixed — multiline JSON body in GITHUB_ENV"
|
|
86
|
+
code: |
|
|
87
|
+
# ✅ FIXED: Multi-line JSON stored as env var using heredoc format
|
|
88
|
+
- name: Set JSON config variable
|
|
89
|
+
run: |
|
|
90
|
+
echo "APP_CONFIG<<EOF" >> $GITHUB_ENV
|
|
91
|
+
cat config/settings.json >> $GITHUB_ENV
|
|
92
|
+
echo "EOF" >> $GITHUB_ENV
|
|
93
|
+
- language: yaml
|
|
94
|
+
label: "Fixed — same pattern applies to GITHUB_OUTPUT for multiline outputs"
|
|
95
|
+
code: |
|
|
96
|
+
# ✅ SAME PATTERN for step outputs (GITHUB_OUTPUT)
|
|
97
|
+
- name: Set multiline output
|
|
98
|
+
id: generate
|
|
99
|
+
run: |
|
|
100
|
+
echo "report<<EOF" >> $GITHUB_OUTPUT
|
|
101
|
+
cat test-results.txt >> $GITHUB_OUTPUT
|
|
102
|
+
echo "EOF" >> $GITHUB_OUTPUT
|
|
103
|
+
- language: yaml
|
|
104
|
+
label: "Fixed — PowerShell equivalent for Windows runners"
|
|
105
|
+
code: |
|
|
106
|
+
# ✅ FIXED (Windows/PowerShell): Use Out-File -Append with heredoc-style writes
|
|
107
|
+
- name: Set multiline env var on Windows
|
|
108
|
+
shell: pwsh
|
|
109
|
+
run: |
|
|
110
|
+
@"
|
|
111
|
+
MY_CERT<<EOF
|
|
112
|
+
${{ secrets.TLS_CERT }}
|
|
113
|
+
EOF
|
|
114
|
+
"@ | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
|
115
|
+
prevention:
|
|
116
|
+
- "Always use the `KEY<<DELIMITER ... DELIMITER` heredoc format for any env var value that may contain newlines (certs, JWTs, JSON, SSH keys)."
|
|
117
|
+
- "Never use a single `echo KEY=VALUE >> $GITHUB_ENV` for values sourced from secrets or file contents — they are likely to contain newlines."
|
|
118
|
+
- "The same heredoc pattern applies to `$GITHUB_OUTPUT` — treat them identically for multiline values."
|
|
119
|
+
- "Validate that downstream steps receive the full value: `run: echo \"MY_CERT=$MY_CERT\"` — a truncated cert will be obviously short."
|
|
120
|
+
- "Use `echo 'key<<EOF' >> $GITHUB_ENV` (single quotes around key<<EOF) to avoid accidental shell expansion of the delimiter line."
|
|
121
|
+
docs:
|
|
122
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#multiline-strings"
|
|
123
|
+
label: "GitHub Docs: Workflow commands — Multiline strings in environment files"
|
|
124
|
+
- url: "https://github.com/orgs/community/discussions/160171"
|
|
125
|
+
label: "GitHub Community #160171 — GITHUB_ENV multiline values"
|
|
126
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-environment-variable"
|
|
127
|
+
label: "GitHub Docs: Setting an environment variable (GITHUB_ENV format)"
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
id: silent-failures-021
|
|
2
|
+
title: "GITHUB_SHA on pull_request Is the Synthetic Merge Commit — Not the PR Head Commit"
|
|
3
|
+
category: silent-failures
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- pull_request
|
|
7
|
+
- github-sha
|
|
8
|
+
- GITHUB_SHA
|
|
9
|
+
- merge-commit
|
|
10
|
+
- head-sha
|
|
11
|
+
- docker-tag
|
|
12
|
+
- commit-lookup
|
|
13
|
+
- git-show
|
|
14
|
+
patterns:
|
|
15
|
+
- regex: "github\\.sha"
|
|
16
|
+
flags: "i"
|
|
17
|
+
- regex: "GITHUB_SHA"
|
|
18
|
+
flags: ""
|
|
19
|
+
- regex: "git show \\$\\{\\{\\s*github\\.sha\\s*\\}\\}"
|
|
20
|
+
flags: "i"
|
|
21
|
+
- regex: "commit.*not found|unknown revision or path not in the working tree"
|
|
22
|
+
flags: "i"
|
|
23
|
+
error_messages:
|
|
24
|
+
- "fatal: ambiguous argument 'abc1234ef56': unknown revision or path not in the working tree"
|
|
25
|
+
- "Error: An object named 'abc1234' is not in the repository"
|
|
26
|
+
- "error: pathspec 'abc1234ef56' did not match any file(s) known to git"
|
|
27
|
+
- "commit not found: abc1234ef5678"
|
|
28
|
+
root_cause: |
|
|
29
|
+
When a workflow is triggered by the `pull_request` (or `pull_request_target`) event,
|
|
30
|
+
`github.sha` and `GITHUB_SHA` do NOT contain the SHA of the PR author's latest commit.
|
|
31
|
+
Instead, they contain the SHA of a **synthetic merge commit** — a prospective merge of
|
|
32
|
+
the PR head branch into the target branch, created by GitHub on the fly as
|
|
33
|
+
`refs/pull/<number>/merge`.
|
|
34
|
+
|
|
35
|
+
This merge commit:
|
|
36
|
+
- Exists only as a special GitHub ref, not as a real commit in the repo's history
|
|
37
|
+
- Is NOT returned by `git log` on the PR branch
|
|
38
|
+
- Cannot be resolved by `git show <sha>` after a shallow fetch-depth:1 checkout
|
|
39
|
+
- Has a different SHA than the PR author's actual commit
|
|
40
|
+
|
|
41
|
+
This silently breaks common patterns:
|
|
42
|
+
- Docker image tagging: `docker build -t myimage:${{ github.sha }}` then looking up
|
|
43
|
+
that SHA in CI/CD systems finds nothing in the actual branch history
|
|
44
|
+
- Commit status APIs: posting status to `github.sha` may fail or post to an
|
|
45
|
+
unexpected ref
|
|
46
|
+
- Manual `git log --pretty=format:'%H' | grep ${{ github.sha }}` returns nothing
|
|
47
|
+
- `git show ${{ github.sha }}` after shallow clone fails with "unknown revision"
|
|
48
|
+
|
|
49
|
+
The correct variable to get the PR author's head commit SHA is:
|
|
50
|
+
`github.event.pull_request.head.sha`
|
|
51
|
+
|
|
52
|
+
For `workflow_run` events, use:
|
|
53
|
+
`github.event.workflow_run.head_sha`
|
|
54
|
+
|
|
55
|
+
This behavior is documented in the GitHub environment variables reference but not
|
|
56
|
+
prominently called out, leading to widespread confusion.
|
|
57
|
+
Source: github/docs#15302 — "GITHUB_SHA on PRs refers to the merge commit"
|
|
58
|
+
Source: github/docs#17767 — "github.sha description is misleading for pull_request"
|
|
59
|
+
Source: github/docs#30093 — equivalent of github.sha for other events
|
|
60
|
+
fix: |
|
|
61
|
+
Replace `github.sha` with `github.event.pull_request.head.sha` whenever you need
|
|
62
|
+
the actual PR author's commit SHA in a `pull_request`-triggered workflow.
|
|
63
|
+
|
|
64
|
+
For `workflow_run`, use `github.event.workflow_run.head_sha`.
|
|
65
|
+
For `push` events, `github.sha` is correct (it IS the pushed commit's SHA).
|
|
66
|
+
|
|
67
|
+
If your workflow must be compatible with multiple event types, add a step to compute
|
|
68
|
+
the correct SHA once and expose it via `GITHUB_OUTPUT`:
|
|
69
|
+
```
|
|
70
|
+
COMMIT_SHA=${{ github.event.pull_request.head.sha || github.sha }}
|
|
71
|
+
```
|
|
72
|
+
Note: The `||` expression operator works in GitHub Actions expressions —
|
|
73
|
+
`github.event.pull_request.head.sha` is empty for non-PR events, so `github.sha`
|
|
74
|
+
becomes the fallback.
|
|
75
|
+
fix_code:
|
|
76
|
+
- language: yaml
|
|
77
|
+
label: "Fix: use github.event.pull_request.head.sha for PR head commit"
|
|
78
|
+
code: |
|
|
79
|
+
on: pull_request
|
|
80
|
+
|
|
81
|
+
jobs:
|
|
82
|
+
build:
|
|
83
|
+
runs-on: ubuntu-latest
|
|
84
|
+
steps:
|
|
85
|
+
- uses: actions/checkout@v4
|
|
86
|
+
|
|
87
|
+
# ❌ WRONG: github.sha is the merge commit SHA, not the PR head commit
|
|
88
|
+
- name: Tag Docker image (wrong SHA)
|
|
89
|
+
run: docker build -t myimage:${{ github.sha }} .
|
|
90
|
+
|
|
91
|
+
# ✅ CORRECT: use the PR head commit SHA
|
|
92
|
+
- name: Tag Docker image (correct SHA)
|
|
93
|
+
run: docker build -t myimage:${{ github.event.pull_request.head.sha }} .
|
|
94
|
+
|
|
95
|
+
- language: yaml
|
|
96
|
+
label: "Cross-event SHA: works for both push and pull_request"
|
|
97
|
+
code: |
|
|
98
|
+
on:
|
|
99
|
+
push:
|
|
100
|
+
pull_request:
|
|
101
|
+
|
|
102
|
+
jobs:
|
|
103
|
+
build:
|
|
104
|
+
runs-on: ubuntu-latest
|
|
105
|
+
steps:
|
|
106
|
+
- uses: actions/checkout@v4
|
|
107
|
+
|
|
108
|
+
- name: Resolve correct commit SHA
|
|
109
|
+
id: sha
|
|
110
|
+
run: |
|
|
111
|
+
# For pull_request: use head.sha; for push: fall back to github.sha
|
|
112
|
+
COMMIT_SHA="${{ github.event.pull_request.head.sha || github.sha }}"
|
|
113
|
+
echo "commit_sha=$COMMIT_SHA" >> "$GITHUB_OUTPUT"
|
|
114
|
+
|
|
115
|
+
- name: Use resolved SHA
|
|
116
|
+
run: docker build -t myimage:${{ steps.sha.outputs.commit_sha }} .
|
|
117
|
+
|
|
118
|
+
- language: yaml
|
|
119
|
+
label: "workflow_run: use head_sha from the triggering workflow"
|
|
120
|
+
code: |
|
|
121
|
+
on:
|
|
122
|
+
workflow_run:
|
|
123
|
+
workflows: [CI]
|
|
124
|
+
types: [completed]
|
|
125
|
+
|
|
126
|
+
jobs:
|
|
127
|
+
deploy:
|
|
128
|
+
runs-on: ubuntu-latest
|
|
129
|
+
steps:
|
|
130
|
+
# ❌ WRONG: github.sha on workflow_run is the default branch SHA
|
|
131
|
+
- run: echo "Wrong SHA: ${{ github.sha }}"
|
|
132
|
+
|
|
133
|
+
# ✅ CORRECT: head_sha is the SHA of the commit that triggered the upstream workflow
|
|
134
|
+
- run: echo "Correct SHA: ${{ github.event.workflow_run.head_sha }}"
|
|
135
|
+
|
|
136
|
+
prevention:
|
|
137
|
+
- "Never use `github.sha` directly in `pull_request` workflows — always use `github.event.pull_request.head.sha`."
|
|
138
|
+
- "Add a comment in your workflow YAML calling out which SHA variable to use for which event."
|
|
139
|
+
- "For Docker tagging and commit status APIs in PR workflows, always derive the SHA from the event payload."
|
|
140
|
+
- "Add a debug step printing both `github.sha` and `github.event.pull_request.head.sha` when troubleshooting."
|
|
141
|
+
- "For `workflow_run` events, use `github.event.workflow_run.head_sha` not `github.sha`."
|
|
142
|
+
docs:
|
|
143
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#github-context"
|
|
144
|
+
label: "GitHub Docs: github context — github.sha"
|
|
145
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request"
|
|
146
|
+
label: "GitHub Docs: pull_request event (GITHUB_SHA value)"
|
|
147
|
+
- url: "https://github.com/github/docs/issues/15302"
|
|
148
|
+
label: "github/docs#15302: GITHUB_SHA on PRs refers to the merge commit"
|
|
149
|
+
- url: "https://github.com/github/docs/issues/17767"
|
|
150
|
+
label: "github/docs#17767: github.sha description is misleading for pull_request"
|