@htekdev/actions-debugger 1.0.66 → 1.0.68
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/errors/caching-artifacts/artifact-retention-days-silently-capped-org-maximum.yml +69 -0
- package/errors/concurrency-timing/cancel-in-progress-deployment-environment-review-loop.yml +76 -0
- package/errors/concurrency-timing/concurrency-group-missing-ref-cross-branch-cancellation.yml +62 -0
- package/errors/known-unsolved/self-hosted-runner-stuck-queued-no-timeout.yml +73 -0
- package/errors/silent-failures/actions-runner-debug-must-be-secret-not-variable.yml +62 -0
- package/errors/silent-failures/working-directory-ignored-on-uses-steps.yml +80 -0
- package/errors/triggers/pull-request-ready-for-review-type-missing.yml +58 -0
- package/errors/yaml-syntax/run-block-scalar-folded-gt-collapses-newlines.yml +76 -0
- package/package.json +1 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
id: caching-artifacts-043
|
|
2
|
+
title: "upload-artifact retention-days silently capped at organization maximum — artifact expires earlier than configured"
|
|
3
|
+
category: caching-artifacts
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- upload-artifact
|
|
7
|
+
- retention-days
|
|
8
|
+
- artifacts
|
|
9
|
+
- organization-policy
|
|
10
|
+
- expiry
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'Artifact will be retained for \d+ days'
|
|
13
|
+
flags: "i"
|
|
14
|
+
error_messages:
|
|
15
|
+
- "Artifact will be retained for"
|
|
16
|
+
root_cause: |
|
|
17
|
+
When actions/upload-artifact is configured with a retention-days value that exceeds the
|
|
18
|
+
organization's or repository's maximum artifact retention setting, GitHub silently caps
|
|
19
|
+
the retention period to the configured maximum without emitting any error or warning.
|
|
20
|
+
The upload step completes successfully, the workflow shows green, and the artifact is
|
|
21
|
+
created — but it expires sooner than the workflow author intended.
|
|
22
|
+
|
|
23
|
+
This is particularly dangerous for:
|
|
24
|
+
- Compliance workflows that retain build artifacts for audits
|
|
25
|
+
- Release workflows where binaries must survive for customer download periods
|
|
26
|
+
- Security scanning workflows that need artifacts for post-incident review
|
|
27
|
+
|
|
28
|
+
The only way to discover the cap is to inspect the artifact's expiration date in the
|
|
29
|
+
repository's Actions UI after upload, or query the REST API. Developers who set
|
|
30
|
+
retention-days: 365 expecting one-year retention will find artifacts disappearing after
|
|
31
|
+
90 days (the default org maximum) with no log evidence of the cap.
|
|
32
|
+
fix: |
|
|
33
|
+
Check your organization's artifact retention maximum under Organization Settings → Actions
|
|
34
|
+
→ General → Artifact and log retention, and ensure retention-days in upload-artifact is
|
|
35
|
+
set to a value at or below this limit. If you need retention beyond the org maximum
|
|
36
|
+
(e.g., for compliance), use GitHub Releases for tagged builds, or an external artifact
|
|
37
|
+
store (S3, Azure Blob, GCS). You can also query the artifact API to assert the actual
|
|
38
|
+
expiry date and fail the workflow if it doesn't match expectations.
|
|
39
|
+
fix_code:
|
|
40
|
+
- language: yaml
|
|
41
|
+
label: "Cap retention-days to org maximum and use GitHub Releases for long-term storage"
|
|
42
|
+
code: |
|
|
43
|
+
- name: Upload build artifact
|
|
44
|
+
uses: actions/upload-artifact@v4
|
|
45
|
+
with:
|
|
46
|
+
name: build-output-${{ github.sha }}
|
|
47
|
+
path: dist/
|
|
48
|
+
# Must be <= your org's maximum retention setting
|
|
49
|
+
# Check: Org Settings → Actions → General → Artifact and log retention
|
|
50
|
+
retention-days: 30
|
|
51
|
+
|
|
52
|
+
# For artifacts requiring retention beyond the org maximum (e.g., release binaries),
|
|
53
|
+
# attach them to a GitHub Release instead:
|
|
54
|
+
- name: Create GitHub Release with artifact
|
|
55
|
+
uses: softprops/action-gh-release@v2
|
|
56
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
57
|
+
with:
|
|
58
|
+
files: dist/**
|
|
59
|
+
# Release assets are NOT subject to the artifact retention policy
|
|
60
|
+
prevention:
|
|
61
|
+
- "Check your organization's artifact retention maximum before setting retention-days in upload-artifact"
|
|
62
|
+
- "For artifacts requiring long-term storage, use GitHub Releases or an external object store (S3, GCS, Azure Blob)"
|
|
63
|
+
- "Add a workflow step that queries the artifact expiry via the REST API and fails if it doesn't match the intended retention"
|
|
64
|
+
- "Document the org retention limit in a comment next to retention-days to alert future editors"
|
|
65
|
+
docs:
|
|
66
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/storing-workflow-data-as-artifacts"
|
|
67
|
+
label: "Storing workflow data as artifacts — GitHub Docs"
|
|
68
|
+
- url: "https://docs.github.com/en/organizations/managing-organization-settings/configuring-the-retention-period-for-github-actions-artifacts-and-logs-in-your-organization"
|
|
69
|
+
label: "Configuring artifact retention period for your organization — GitHub Docs"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
id: concurrency-timing-036
|
|
2
|
+
title: "cancel-in-progress: true cancels pending deployment environment reviews — deployment never completes"
|
|
3
|
+
category: concurrency-timing
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- concurrency
|
|
7
|
+
- deployment
|
|
8
|
+
- environment
|
|
9
|
+
- cancel-in-progress
|
|
10
|
+
- required-reviewers
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'waiting for a required environment'
|
|
13
|
+
flags: "i"
|
|
14
|
+
- regex: 'Deployment to .+ was cancelled'
|
|
15
|
+
flags: "i"
|
|
16
|
+
error_messages:
|
|
17
|
+
- "This workflow run is waiting for a required environment"
|
|
18
|
+
- "Deployment to production was cancelled"
|
|
19
|
+
root_cause: |
|
|
20
|
+
When a deployment job targets an environment with required reviewers (protection rules)
|
|
21
|
+
and cancel-in-progress: true is set on the concurrency group, every new push cancels the
|
|
22
|
+
pending workflow run — including the one awaiting reviewer approval. The reviewer is
|
|
23
|
+
notified, starts the review process, but before they approve a new commit arrives and
|
|
24
|
+
cancels the run. The cycle repeats indefinitely: deployments queue, reviewers are
|
|
25
|
+
interrupted, and nothing ever reaches production. No diagnostic error is surfaced; the
|
|
26
|
+
workflow simply shows "Cancelled" with no indication that a required-reviewer gate was
|
|
27
|
+
involved.
|
|
28
|
+
fix: |
|
|
29
|
+
Remove cancel-in-progress: true from the concurrency group used by the deployment job.
|
|
30
|
+
Use cancel-in-progress: false (the default) so pending approval runs survive new commits.
|
|
31
|
+
To still get fast feedback on CI, split the workflow into two separate files: a fast CI
|
|
32
|
+
workflow with cancel-in-progress: true, and a deployment workflow (triggered on CI success)
|
|
33
|
+
with cancel-in-progress: false so approval gates are preserved.
|
|
34
|
+
fix_code:
|
|
35
|
+
- language: yaml
|
|
36
|
+
label: "Split CI and deploy workflows with separate concurrency policies"
|
|
37
|
+
code: |
|
|
38
|
+
# .github/workflows/ci.yml — cancel old CI runs freely
|
|
39
|
+
on: [push, pull_request]
|
|
40
|
+
concurrency:
|
|
41
|
+
group: ci-${{ github.ref }}
|
|
42
|
+
cancel-in-progress: true
|
|
43
|
+
jobs:
|
|
44
|
+
test:
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v4
|
|
48
|
+
- run: npm test
|
|
49
|
+
|
|
50
|
+
# .github/workflows/deploy.yml — preserve pending deployment approvals
|
|
51
|
+
on:
|
|
52
|
+
workflow_run:
|
|
53
|
+
workflows: [CI]
|
|
54
|
+
types: [completed]
|
|
55
|
+
branches: [main]
|
|
56
|
+
concurrency:
|
|
57
|
+
group: deploy-${{ github.ref }}
|
|
58
|
+
cancel-in-progress: false # preserves pending required-reviewer approval
|
|
59
|
+
jobs:
|
|
60
|
+
deploy:
|
|
61
|
+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
|
62
|
+
environment: production # has required reviewers
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
steps:
|
|
65
|
+
- uses: actions/checkout@v4
|
|
66
|
+
- run: echo "Deploying..."
|
|
67
|
+
prevention:
|
|
68
|
+
- "Never combine cancel-in-progress: true with deployment jobs that have required-reviewer environment protection rules"
|
|
69
|
+
- "Use separate workflow files for CI and deployment to apply different concurrency policies"
|
|
70
|
+
- "Set cancel-in-progress: false (or omit it) on any concurrency group that wraps a deployment environment job"
|
|
71
|
+
- "Test the deployment approval flow explicitly after adding or changing concurrency settings"
|
|
72
|
+
docs:
|
|
73
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/using-concurrency"
|
|
74
|
+
label: "Using concurrency — GitHub Docs"
|
|
75
|
+
- url: "https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-deployments/reviewing-deployments"
|
|
76
|
+
label: "Reviewing deployments — GitHub Docs"
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
id: concurrency-timing-037
|
|
2
|
+
title: "Concurrency group key missing github.ref accidentally cancels runs on other branches"
|
|
3
|
+
category: concurrency-timing
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- concurrency
|
|
7
|
+
- cancel-in-progress
|
|
8
|
+
- github-ref
|
|
9
|
+
- branches
|
|
10
|
+
- cross-branch
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'cancelled because a more recent run with the same concurrency'
|
|
13
|
+
flags: "i"
|
|
14
|
+
- regex: 'This run was cancelled'
|
|
15
|
+
flags: "i"
|
|
16
|
+
error_messages:
|
|
17
|
+
- "This run was cancelled because a more recent run with the same concurrency key is in progress"
|
|
18
|
+
root_cause: |
|
|
19
|
+
When the concurrency group key is set to a static string or uses only github.workflow
|
|
20
|
+
without including github.ref, all branches share the same concurrency slot. A push to
|
|
21
|
+
any feature branch will cancel an in-progress run on main — or vice versa. With
|
|
22
|
+
cancel-in-progress: true, a developer's feature branch push can silently abort a
|
|
23
|
+
production branch deployment or a release CI run. The cancellation message ("This run
|
|
24
|
+
was cancelled because a more recent run with the same concurrency key is in progress")
|
|
25
|
+
gives no indication that the runs are on completely different branches. This is among the
|
|
26
|
+
most common misconfiguration in copy-pasted concurrency examples that omit github.ref.
|
|
27
|
+
fix: |
|
|
28
|
+
Always include github.ref (or github.head_ref for pull_request events) in the concurrency
|
|
29
|
+
group key so each branch maintains its own independent concurrency slot. For pull requests,
|
|
30
|
+
use github.event.pull_request.number to prevent conflicts between simultaneously open PRs
|
|
31
|
+
targeting the same branch. For scheduled or manual workflows where github.ref is always
|
|
32
|
+
the same, use github.run_id to allow parallel runs.
|
|
33
|
+
fix_code:
|
|
34
|
+
- language: yaml
|
|
35
|
+
label: "Include github.ref in the concurrency key to isolate each branch"
|
|
36
|
+
code: |
|
|
37
|
+
# WRONG — all branches share one concurrency slot, pushes to any branch
|
|
38
|
+
# cancel runs on all other branches
|
|
39
|
+
# concurrency:
|
|
40
|
+
# group: ${{ github.workflow }}
|
|
41
|
+
# cancel-in-progress: true
|
|
42
|
+
|
|
43
|
+
# CORRECT — each branch has its own independent concurrency slot
|
|
44
|
+
concurrency:
|
|
45
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
46
|
+
cancel-in-progress: true
|
|
47
|
+
|
|
48
|
+
# For pull_request events, scope to the PR number for extra precision
|
|
49
|
+
# (prevents PR-A and PR-B from cancelling each other when both target main)
|
|
50
|
+
concurrency:
|
|
51
|
+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
52
|
+
cancel-in-progress: true
|
|
53
|
+
prevention:
|
|
54
|
+
- "Always include github.ref or github.head_ref in the concurrency group key"
|
|
55
|
+
- "For pull_request workflows, use github.event.pull_request.number || github.ref to scope to individual PRs"
|
|
56
|
+
- "Audit all workflow concurrency keys whenever enabling cancel-in-progress: true"
|
|
57
|
+
- "Use a unique prefix per workflow type (ci-, deploy-, lint-) to prevent cross-workflow collisions even when github.ref is included"
|
|
58
|
+
docs:
|
|
59
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/using-concurrency"
|
|
60
|
+
label: "Using concurrency — GitHub Docs"
|
|
61
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#concurrency"
|
|
62
|
+
label: "Concurrency syntax — GitHub Docs"
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
id: known-unsolved-042
|
|
2
|
+
title: 'Job queues indefinitely when no self-hosted runner matches labels — no automatic queue-wait timeout'
|
|
3
|
+
category: known-unsolved
|
|
4
|
+
severity: limitation
|
|
5
|
+
tags:
|
|
6
|
+
- self-hosted
|
|
7
|
+
- queued
|
|
8
|
+
- runner-labels
|
|
9
|
+
- timeout
|
|
10
|
+
- stuck-job
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'Waiting for a runner to pick up this job'
|
|
13
|
+
flags: 'i'
|
|
14
|
+
- regex: 'Job is waiting for a hosted runner to come online'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
error_messages:
|
|
17
|
+
- 'Waiting for a runner to pick up this job'
|
|
18
|
+
- 'Job is waiting for a hosted runner to come online'
|
|
19
|
+
root_cause: |
|
|
20
|
+
When a job specifies runs-on: self-hosted (or a label array containing self-hosted),
|
|
21
|
+
GitHub places the job in a queue and waits for a matching runner to become available.
|
|
22
|
+
If no registered runner matches all required labels — because the runner is offline,
|
|
23
|
+
deregistered, at capacity, or the labels are mistyped — the job remains in "Queued"
|
|
24
|
+
state indefinitely with the message "Waiting for a runner to pick up this job."
|
|
25
|
+
|
|
26
|
+
GitHub does not apply an automatic queue-wait timeout. The only enforced limit is the
|
|
27
|
+
overall workflow timeout-minutes (default 360 minutes, maximum 35 days for self-hosted
|
|
28
|
+
runners). Runner labels are matched case-sensitively, so [self-hosted, Linux] does not
|
|
29
|
+
match a runner registered as [self-hosted, linux].
|
|
30
|
+
|
|
31
|
+
This is a recurring GitHub Community request: developers frequently discover queued jobs
|
|
32
|
+
hours or days later after expecting fast CI feedback.
|
|
33
|
+
fix: |
|
|
34
|
+
There is no GitHub-native queue-wait timeout distinct from job runtime. Mitigations:
|
|
35
|
+
1. Add timeout-minutes at the job level to cap total job time including queue wait
|
|
36
|
+
2. Verify runner label spellings exactly match labels registered on the runner
|
|
37
|
+
(Settings → Actions → Runners shows registered labels)
|
|
38
|
+
3. Ensure at least one runner with all required labels is online and idle
|
|
39
|
+
4. Use ephemeral (JIT) runners with auto-scaling to prevent capacity exhaustion
|
|
40
|
+
fix_code:
|
|
41
|
+
- language: yaml
|
|
42
|
+
label: 'Add timeout-minutes to fail fast when no runner is available'
|
|
43
|
+
code: |
|
|
44
|
+
jobs:
|
|
45
|
+
build:
|
|
46
|
+
runs-on: [self-hosted, linux, x64]
|
|
47
|
+
timeout-minutes: 30 # job fails if no runner picks it up within 30 minutes
|
|
48
|
+
steps:
|
|
49
|
+
- uses: actions/checkout@v4
|
|
50
|
+
- run: make build
|
|
51
|
+
- language: yaml
|
|
52
|
+
label: 'Fallback to GitHub-hosted runner when self-hosted is unavailable'
|
|
53
|
+
code: |
|
|
54
|
+
jobs:
|
|
55
|
+
build:
|
|
56
|
+
runs-on: ${{ vars.USE_SELF_HOSTED == 'true' && fromJSON('["self-hosted","linux","x64"]') || 'ubuntu-latest' }}
|
|
57
|
+
timeout-minutes: 60
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@v4
|
|
60
|
+
- run: make build
|
|
61
|
+
prevention:
|
|
62
|
+
- 'Always set timeout-minutes on self-hosted runner jobs to prevent indefinite queuing'
|
|
63
|
+
- 'Verify runner labels match exactly — labels are case-sensitive (Linux vs linux)'
|
|
64
|
+
- 'Monitor runner pool health at Settings → Actions → Runners and alert on all-offline conditions'
|
|
65
|
+
- 'Use ephemeral (JIT) runners with auto-scaling to ensure available capacity on demand'
|
|
66
|
+
- 'Consider GitHub-hosted runner fallback for critical workflows'
|
|
67
|
+
docs:
|
|
68
|
+
- url: 'https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners#self-hosted-runner-labels'
|
|
69
|
+
label: 'Self-hosted runner labels — GitHub Docs'
|
|
70
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes'
|
|
71
|
+
label: 'jobs.<job>.timeout-minutes — GitHub Docs'
|
|
72
|
+
- url: 'https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/autoscaling-with-self-hosted-runners'
|
|
73
|
+
label: 'Autoscaling with self-hosted runners — GitHub Docs'
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
id: silent-failures-066
|
|
2
|
+
title: 'ACTIONS_RUNNER_DEBUG and ACTIONS_STEP_DEBUG must be repository secrets, not variables'
|
|
3
|
+
category: silent-failures
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- debug-logging
|
|
7
|
+
- ACTIONS_RUNNER_DEBUG
|
|
8
|
+
- ACTIONS_STEP_DEBUG
|
|
9
|
+
- secrets
|
|
10
|
+
- variables
|
|
11
|
+
- troubleshooting
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'ACTIONS_RUNNER_DEBUG|ACTIONS_STEP_DEBUG'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
error_messages:
|
|
16
|
+
- 'No additional debug output despite ACTIONS_RUNNER_DEBUG=true'
|
|
17
|
+
- 'Debug logging not enabled even though variable is set to true'
|
|
18
|
+
root_cause: |
|
|
19
|
+
GitHub Actions checks ACTIONS_RUNNER_DEBUG and ACTIONS_STEP_DEBUG only when they are
|
|
20
|
+
set as repository or organization secrets. Setting them as repository variables
|
|
21
|
+
(Settings → Secrets and variables → Actions → Variables tab) has no effect whatsoever.
|
|
22
|
+
The runner bootstrap reads debug flags from the secrets store before variable contexts
|
|
23
|
+
are available, so a vars.ACTIONS_RUNNER_DEBUG reference inside the workflow YAML is
|
|
24
|
+
also ineffective. No warning is emitted when the variable exists but the corresponding
|
|
25
|
+
secret does not — the runner simply operates in non-debug mode silently.
|
|
26
|
+
fix: |
|
|
27
|
+
Set ACTIONS_RUNNER_DEBUG and/or ACTIONS_STEP_DEBUG as repository secrets (not variables)
|
|
28
|
+
with the value "true":
|
|
29
|
+
|
|
30
|
+
Settings → Secrets and variables → Actions → Secrets tab → New repository secret
|
|
31
|
+
Name: ACTIONS_RUNNER_DEBUG
|
|
32
|
+
Value: true
|
|
33
|
+
|
|
34
|
+
Alternatively, use the "Re-run jobs" UI button and check "Enable debug logging" for a
|
|
35
|
+
one-time debug run without creating a permanent secret.
|
|
36
|
+
fix_code:
|
|
37
|
+
- language: yaml
|
|
38
|
+
label: 'Debug flags require repository secrets — no workflow YAML change needed'
|
|
39
|
+
code: |
|
|
40
|
+
# Create these as repository SECRETS (not Variables):
|
|
41
|
+
# ACTIONS_RUNNER_DEBUG = true (verbose runner diagnostic logs)
|
|
42
|
+
# ACTIONS_STEP_DEBUG = true (verbose step-level output including set-output calls)
|
|
43
|
+
#
|
|
44
|
+
# Setting them under the Variables tab has NO effect.
|
|
45
|
+
# For one-off debugging use "Re-run jobs" → check "Enable debug logging".
|
|
46
|
+
|
|
47
|
+
jobs:
|
|
48
|
+
build:
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
steps:
|
|
51
|
+
- uses: actions/checkout@v4
|
|
52
|
+
- run: echo "Runner debug active when ACTIONS_RUNNER_DEBUG secret = true"
|
|
53
|
+
prevention:
|
|
54
|
+
- 'Set ACTIONS_RUNNER_DEBUG and ACTIONS_STEP_DEBUG as Secrets, not Variables'
|
|
55
|
+
- 'Use the Re-run with debug logging checkbox for temporary one-off debugging'
|
|
56
|
+
- 'Check the Secrets tab — not the Variables tab — under Settings → Secrets and variables → Actions'
|
|
57
|
+
- 'Remember: debug flags are read during runner bootstrap before the vars context is available'
|
|
58
|
+
docs:
|
|
59
|
+
- url: 'https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/troubleshooting-workflows/enabling-debug-logging'
|
|
60
|
+
label: 'Enabling debug logging — GitHub Docs'
|
|
61
|
+
- url: 'https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions'
|
|
62
|
+
label: 'Using secrets in GitHub Actions — GitHub Docs'
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
id: silent-failures-067
|
|
2
|
+
title: 'working-directory on a uses: step is silently ignored — only applies to run: steps'
|
|
3
|
+
category: silent-failures
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- working-directory
|
|
7
|
+
- uses
|
|
8
|
+
- composite-action
|
|
9
|
+
- run
|
|
10
|
+
- path
|
|
11
|
+
- configuration
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'Error.*ENOENT.*no such file or directory'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'No such file or directory'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
error_messages:
|
|
18
|
+
- 'Action runs from workspace root instead of specified working-directory'
|
|
19
|
+
- 'ENOENT: no such file or directory — action ignoring working-directory set on uses: step'
|
|
20
|
+
root_cause: |
|
|
21
|
+
The step-level working-directory property only affects run: steps that execute shell
|
|
22
|
+
commands. Steps that use the uses: keyword to invoke an action — whether a JavaScript
|
|
23
|
+
action, Docker action, or composite action — silently ignore working-directory. The
|
|
24
|
+
property is discarded with no warning logged. The action runs from GITHUB_WORKSPACE
|
|
25
|
+
(the repository root) or from the action's own directory, not the directory specified
|
|
26
|
+
on the step.
|
|
27
|
+
|
|
28
|
+
This is a documented GitHub Actions limitation that surprises many developers who expect
|
|
29
|
+
working-directory to behave like a cd command applied to the entire step, regardless of
|
|
30
|
+
step type. It is one of the most common "action runs in wrong directory" reports on GitHub
|
|
31
|
+
Community Discussions.
|
|
32
|
+
fix: |
|
|
33
|
+
Pass the desired directory as an explicit input to the action. For run: steps in the same
|
|
34
|
+
job, use defaults.run.working-directory at the job level. Do not set working-directory on
|
|
35
|
+
uses: steps — it is silently discarded.
|
|
36
|
+
fix_code:
|
|
37
|
+
- language: yaml
|
|
38
|
+
label: 'Use job-level defaults.run for run steps; pass input for uses steps'
|
|
39
|
+
code: |
|
|
40
|
+
jobs:
|
|
41
|
+
build:
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
defaults:
|
|
44
|
+
run:
|
|
45
|
+
working-directory: ./packages/my-app # applies to all run: steps only
|
|
46
|
+
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@v4
|
|
49
|
+
|
|
50
|
+
- run: npm install # runs in ./packages/my-app ✓
|
|
51
|
+
|
|
52
|
+
# For uses: steps, pass the directory as an explicit action input:
|
|
53
|
+
- uses: ./.github/actions/my-action
|
|
54
|
+
with:
|
|
55
|
+
working-directory: ./packages/my-app # action must accept this input
|
|
56
|
+
- language: yaml
|
|
57
|
+
label: 'Composite action: declare working-directory as an input'
|
|
58
|
+
code: |
|
|
59
|
+
# In .github/actions/my-action/action.yml:
|
|
60
|
+
inputs:
|
|
61
|
+
working-directory:
|
|
62
|
+
description: 'Directory to run in'
|
|
63
|
+
default: '.'
|
|
64
|
+
runs:
|
|
65
|
+
using: composite
|
|
66
|
+
steps:
|
|
67
|
+
- run: npm test
|
|
68
|
+
shell: bash
|
|
69
|
+
working-directory: ${{ inputs.working-directory }}
|
|
70
|
+
prevention:
|
|
71
|
+
- 'Never set working-directory on steps that use uses: — it is silently ignored'
|
|
72
|
+
- 'For composite actions that need a target directory, declare an explicit working-directory input'
|
|
73
|
+
- 'Use defaults.run.working-directory at job level to apply a directory to all run: steps'
|
|
74
|
+
docs:
|
|
75
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsworking-directory'
|
|
76
|
+
label: 'steps[*].working-directory — GitHub Docs'
|
|
77
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#defaultsrun'
|
|
78
|
+
label: 'defaults.run — GitHub Docs'
|
|
79
|
+
- url: 'https://docs.github.com/en/actions/sharing-automations/creating-actions/creating-a-composite-action'
|
|
80
|
+
label: 'Creating a composite action — GitHub Docs'
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
id: triggers-047
|
|
2
|
+
title: 'pull_request default types exclude ready_for_review — draft-to-ready conversion skips CI'
|
|
3
|
+
category: triggers
|
|
4
|
+
severity: warning
|
|
5
|
+
tags:
|
|
6
|
+
- pull_request
|
|
7
|
+
- draft
|
|
8
|
+
- ready_for_review
|
|
9
|
+
- types
|
|
10
|
+
- required-status-checks
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'on:\s*\n\s*pull_request\s*:'
|
|
13
|
+
flags: 'im'
|
|
14
|
+
- regex: 'pull_request\s*:\s*\n(?!\s*types)'
|
|
15
|
+
flags: 'im'
|
|
16
|
+
error_messages:
|
|
17
|
+
- 'CI not triggered after converting draft pull request to ready for review'
|
|
18
|
+
- 'Required status check never ran after marking PR ready — branch protection blocking merge'
|
|
19
|
+
root_cause: |
|
|
20
|
+
The pull_request event with no explicit types: list defaults to the activity types
|
|
21
|
+
[opened, synchronize, reopened]. When a contributor converts a draft PR to ready
|
|
22
|
+
for review, GitHub fires the ready_for_review activity type, which is absent from
|
|
23
|
+
the default set. The workflow never executes for this state transition, leaving the
|
|
24
|
+
PR without the required CI status checks. Branch protection rules then block merging
|
|
25
|
+
until the next push re-triggers CI.
|
|
26
|
+
|
|
27
|
+
This is one of the most frequently reported CI surprises in GitHub Community discussions,
|
|
28
|
+
particularly for teams that rely on draft PRs for work-in-progress reviews.
|
|
29
|
+
fix: |
|
|
30
|
+
Explicitly declare the types list on the pull_request trigger and add ready_for_review:
|
|
31
|
+
fix_code:
|
|
32
|
+
- language: yaml
|
|
33
|
+
label: 'Add ready_for_review to pull_request types'
|
|
34
|
+
code: |
|
|
35
|
+
on:
|
|
36
|
+
pull_request:
|
|
37
|
+
types:
|
|
38
|
+
- opened
|
|
39
|
+
- synchronize
|
|
40
|
+
- reopened
|
|
41
|
+
- ready_for_review # fires when a draft PR is marked ready for review
|
|
42
|
+
|
|
43
|
+
jobs:
|
|
44
|
+
ci:
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v4
|
|
48
|
+
- run: npm test
|
|
49
|
+
prevention:
|
|
50
|
+
- 'Always explicitly list pull_request types when your team uses draft PRs'
|
|
51
|
+
- 'Add ready_for_review when branch protection requires CI to pass before merge'
|
|
52
|
+
- 'Include converted_to_draft to re-trigger (or block) CI when PRs return to draft'
|
|
53
|
+
- 'Review required status check names after adding new trigger types to confirm they register'
|
|
54
|
+
docs:
|
|
55
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request'
|
|
56
|
+
label: 'pull_request event types — GitHub Docs'
|
|
57
|
+
- url: 'https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request'
|
|
58
|
+
label: 'Changing the stage of a pull request — GitHub Docs'
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
id: yaml-syntax-044
|
|
2
|
+
title: "run: > (folded block scalar) collapses newlines to spaces — multi-line shell scripts break silently"
|
|
3
|
+
category: yaml-syntax
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- yaml
|
|
7
|
+
- run
|
|
8
|
+
- block-scalar
|
|
9
|
+
- multiline
|
|
10
|
+
- shell
|
|
11
|
+
- folded
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'syntax error near unexpected token'
|
|
14
|
+
flags: "i"
|
|
15
|
+
- regex: 'command not found'
|
|
16
|
+
flags: "i"
|
|
17
|
+
- regex: 'unexpected EOF while looking for matching'
|
|
18
|
+
flags: "i"
|
|
19
|
+
error_messages:
|
|
20
|
+
- "syntax error near unexpected token"
|
|
21
|
+
- "command not found"
|
|
22
|
+
- "unexpected EOF while looking for matching `\"'"
|
|
23
|
+
root_cause: |
|
|
24
|
+
YAML has two block scalar indicators: | (literal) preserves newlines exactly, while >
|
|
25
|
+
(folded) collapses newlines between non-empty lines into a single space. When a GitHub
|
|
26
|
+
Actions run: block uses > instead of |, every line break in the shell script becomes a
|
|
27
|
+
space. Multi-line scripts are silently concatenated into a single command that the shell
|
|
28
|
+
cannot parse, producing confusing errors like "syntax error near unexpected token" or
|
|
29
|
+
"command not found" pointing to the wrong line.
|
|
30
|
+
|
|
31
|
+
This is especially common when:
|
|
32
|
+
- Developers copy YAML examples from documentation that use > for prose (not scripts)
|
|
33
|
+
- IDEs or formatters suggest > to reduce visual indentation
|
|
34
|
+
- Developers confuse > (folded) and | (literal) because both produce multi-line blocks
|
|
35
|
+
|
|
36
|
+
Example: a three-line script becomes one run-together line:
|
|
37
|
+
# With run: > becomes: echo "start" VAR=hello echo "$VAR"
|
|
38
|
+
# With run: | becomes: echo "start" \n VAR=hello \n echo "$VAR" (correct)
|
|
39
|
+
fix: |
|
|
40
|
+
Always use | (pipe / literal block scalar) for run: steps that contain shell scripts.
|
|
41
|
+
The | indicator preserves newlines exactly as written. The > indicator should only be
|
|
42
|
+
used for prose strings (e.g., long error messages or descriptions) where newline
|
|
43
|
+
collapsing is intentional.
|
|
44
|
+
fix_code:
|
|
45
|
+
- language: yaml
|
|
46
|
+
label: "Use | (literal) not > (folded) for run: shell scripts"
|
|
47
|
+
code: |
|
|
48
|
+
jobs:
|
|
49
|
+
build:
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
steps:
|
|
52
|
+
# WRONG — > folds newlines into spaces, script becomes one broken command
|
|
53
|
+
# - name: Build
|
|
54
|
+
# run: >
|
|
55
|
+
# echo "Starting build"
|
|
56
|
+
# npm install
|
|
57
|
+
# npm run build
|
|
58
|
+
|
|
59
|
+
# CORRECT — | preserves newlines, each command runs on its own line
|
|
60
|
+
- name: Build
|
|
61
|
+
run: |
|
|
62
|
+
echo "Starting build"
|
|
63
|
+
npm install
|
|
64
|
+
npm run build
|
|
65
|
+
prevention:
|
|
66
|
+
- "Always use | (literal block scalar) for run: blocks containing shell scripts"
|
|
67
|
+
- "Reserve > (folded block scalar) for non-executable prose strings only"
|
|
68
|
+
- "Enable a YAML linter (e.g., actionlint, yamllint) in pre-commit hooks to catch > in run: blocks"
|
|
69
|
+
- "When in doubt: | keeps lines as lines; > joins lines with spaces"
|
|
70
|
+
docs:
|
|
71
|
+
- url: "https://yaml.org/spec/1.2.2/#chapter-8-block-style-productions"
|
|
72
|
+
label: "YAML block scalar styles — YAML spec"
|
|
73
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun"
|
|
74
|
+
label: "jobs.<id>.steps[*].run — GitHub Docs"
|
|
75
|
+
- url: "https://rhysd.github.io/actionlint/"
|
|
76
|
+
label: "actionlint — static checker for GitHub Actions workflow files"
|
package/package.json
CHANGED