@htekdev/actions-debugger 1.0.42 → 1.0.44
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/upload-artifact-v4-duplicate-name-hard-error.yml +114 -0
- package/errors/known-unsolved/environment-matrix-one-review-per-job.yml +100 -0
- package/errors/permissions-auth/attest-build-provenance-missing-attestations-write.yml +100 -0
- package/errors/permissions-auth/job-level-permissions-replaces-workflow-level.yml +123 -0
- package/errors/runner-environment/setup-python-version-range-resolves-to-313-distutils-removed.yml +107 -0
- package/errors/silent-failures/composite-action-outputs-not-propagated.yml +99 -0
- package/errors/silent-failures/github-output-heredoc-delimiter-collision.yml +83 -0
- package/errors/triggers/workflow-run-name-mismatch-silent-never-triggers.yml +96 -0
- package/package.json +1 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
id: caching-artifacts-033
|
|
2
|
+
title: 'upload-artifact@v4 requires unique artifact names per run — duplicate name is a hard error'
|
|
3
|
+
category: caching-artifacts
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- upload-artifact
|
|
7
|
+
- v4
|
|
8
|
+
- duplicate-name
|
|
9
|
+
- breaking-change
|
|
10
|
+
- matrix
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'An artifact with this name already exists on the workflow run'
|
|
13
|
+
flags: 'i'
|
|
14
|
+
- regex: 'Failed to CreateArtifact.*already exists'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
error_messages:
|
|
17
|
+
- 'An artifact with this name already exists on the workflow run'
|
|
18
|
+
- 'Failed to CreateArtifact: Artifact already exists'
|
|
19
|
+
root_cause: |
|
|
20
|
+
actions/upload-artifact@v4 changed artifact name uniqueness enforcement from v3:
|
|
21
|
+
|
|
22
|
+
v3 behavior: uploading with a duplicate name silently merged the new files
|
|
23
|
+
into the existing artifact, potentially overwriting same-named files.
|
|
24
|
+
|
|
25
|
+
v4 behavior: uploading with a name that already exists in the same workflow
|
|
26
|
+
run is a hard error. The step fails immediately with:
|
|
27
|
+
"An artifact with this name already exists on the workflow run"
|
|
28
|
+
|
|
29
|
+
Common triggers:
|
|
30
|
+
1. Matrix jobs all writing to a fixed artifact name (e.g., name: build-output)
|
|
31
|
+
without including a matrix dimension in the name.
|
|
32
|
+
2. Multiple upload-artifact steps in the same job with the same name: value.
|
|
33
|
+
3. Reusable workflows invoked multiple times in one run using identical names.
|
|
34
|
+
4. Two upload steps with no name: parameter — both default to "artifact".
|
|
35
|
+
|
|
36
|
+
Workflows that relied on v3's merge behavior and were silently uploading
|
|
37
|
+
duplicate names will fail immediately after upgrading to v4.
|
|
38
|
+
fix: |
|
|
39
|
+
Include a unique identifier in the artifact name for each upload step.
|
|
40
|
+
For matrix jobs, include a matrix dimension value. For independent parallel
|
|
41
|
+
jobs, include the job name or a specific run-scoped identifier.
|
|
42
|
+
|
|
43
|
+
If you need to consolidate artifacts from multiple sources, have each job
|
|
44
|
+
upload with a unique name, then use a final consolidation job that downloads
|
|
45
|
+
all artifacts and re-uploads a merged set.
|
|
46
|
+
fix_code:
|
|
47
|
+
- language: yaml
|
|
48
|
+
label: 'Matrix jobs — include matrix dimension in artifact name'
|
|
49
|
+
code: |
|
|
50
|
+
strategy:
|
|
51
|
+
matrix:
|
|
52
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
53
|
+
|
|
54
|
+
steps:
|
|
55
|
+
- name: Build
|
|
56
|
+
run: make build
|
|
57
|
+
|
|
58
|
+
- uses: actions/upload-artifact@v4
|
|
59
|
+
with:
|
|
60
|
+
name: build-output-${{ matrix.os }} # Unique per matrix cell
|
|
61
|
+
path: dist/
|
|
62
|
+
- language: yaml
|
|
63
|
+
label: 'Multiple upload steps — use distinct explicit names'
|
|
64
|
+
code: |
|
|
65
|
+
steps:
|
|
66
|
+
- uses: actions/upload-artifact@v4
|
|
67
|
+
with:
|
|
68
|
+
name: test-results # Distinct name
|
|
69
|
+
path: test-output/
|
|
70
|
+
|
|
71
|
+
- uses: actions/upload-artifact@v4
|
|
72
|
+
with:
|
|
73
|
+
name: coverage-report # Different name — no conflict
|
|
74
|
+
path: coverage/
|
|
75
|
+
- language: yaml
|
|
76
|
+
label: 'Merge artifacts across matrix jobs in a downstream job'
|
|
77
|
+
code: |
|
|
78
|
+
jobs:
|
|
79
|
+
build:
|
|
80
|
+
strategy:
|
|
81
|
+
matrix:
|
|
82
|
+
os: [ubuntu-latest, windows-latest]
|
|
83
|
+
steps:
|
|
84
|
+
- uses: actions/upload-artifact@v4
|
|
85
|
+
with:
|
|
86
|
+
name: dist-${{ matrix.os }}
|
|
87
|
+
path: dist/
|
|
88
|
+
|
|
89
|
+
package:
|
|
90
|
+
needs: build
|
|
91
|
+
runs-on: ubuntu-latest
|
|
92
|
+
steps:
|
|
93
|
+
- uses: actions/download-artifact@v4
|
|
94
|
+
with:
|
|
95
|
+
pattern: dist-*
|
|
96
|
+
merge-multiple: true
|
|
97
|
+
path: all-dist/
|
|
98
|
+
|
|
99
|
+
- uses: actions/upload-artifact@v4
|
|
100
|
+
with:
|
|
101
|
+
name: final-package
|
|
102
|
+
path: all-dist/
|
|
103
|
+
prevention:
|
|
104
|
+
- 'Always specify an explicit name: for each upload-artifact step rather than relying on the default "artifact"'
|
|
105
|
+
- 'For matrix jobs, include at least one matrix variable in the artifact name'
|
|
106
|
+
- 'Audit workflows being migrated from v3 to v4 for any step that omits name: or uses the same name twice'
|
|
107
|
+
- 'Two steps with no name: both default to "artifact" and will always conflict in v4'
|
|
108
|
+
docs:
|
|
109
|
+
- url: 'https://github.com/actions/upload-artifact/blob/main/docs/MIGRATION.md'
|
|
110
|
+
label: 'upload-artifact v3 to v4 migration guide'
|
|
111
|
+
- url: 'https://github.com/actions/upload-artifact'
|
|
112
|
+
label: 'actions/upload-artifact repository'
|
|
113
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/storing-workflow-data-as-artifacts'
|
|
114
|
+
label: 'GitHub Docs — Storing workflow data as artifacts'
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
id: known-unsolved-034
|
|
2
|
+
title: 'environment deployment protection with required reviewers creates one review request per matrix job — no batch approval'
|
|
3
|
+
category: known-unsolved
|
|
4
|
+
severity: limitation
|
|
5
|
+
tags:
|
|
6
|
+
- environment
|
|
7
|
+
- matrix
|
|
8
|
+
- deployment
|
|
9
|
+
- required-reviewers
|
|
10
|
+
- approvals
|
|
11
|
+
- no-fix
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'Waiting for.*review'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'Review required before this job runs'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
error_messages:
|
|
18
|
+
- 'Waiting for a reviewer'
|
|
19
|
+
- 'Review required before this job runs'
|
|
20
|
+
root_cause: |
|
|
21
|
+
GitHub Actions environments with required reviewers enforce approval at the
|
|
22
|
+
individual job level. When a job using environment: with required reviewers
|
|
23
|
+
also uses strategy: matrix, each matrix cell creates a separate deployment
|
|
24
|
+
instance requiring its own approval.
|
|
25
|
+
|
|
26
|
+
A 3x3 matrix (os x environment) produces 9 separate "Waiting for reviewer"
|
|
27
|
+
prompts in the GitHub Actions UI — one for each matrix combination. Each
|
|
28
|
+
must be approved individually; there is no "approve all" button for
|
|
29
|
+
matrix deployments.
|
|
30
|
+
|
|
31
|
+
This behavior stems from GitHub's deployment model: each job run creates a
|
|
32
|
+
discrete deployment record in the repository's deployment history. Matrix
|
|
33
|
+
jobs are independent job runs, so each creates its own deployment record
|
|
34
|
+
and independently triggers the environment protection review gate.
|
|
35
|
+
|
|
36
|
+
This is confirmed expected behavior per GitHub staff in community discussions.
|
|
37
|
+
There is no configuration option to batch or group matrix job deployment approvals.
|
|
38
|
+
fix: |
|
|
39
|
+
There is no supported way to batch-approve matrix jobs targeting a protected
|
|
40
|
+
environment. The workaround is architectural: separate the build/test matrix
|
|
41
|
+
from the deployment job, using a single non-matrix deploy job that depends
|
|
42
|
+
on all matrix results via needs:.
|
|
43
|
+
|
|
44
|
+
This "build in matrix, deploy once" pattern also aligns with security best
|
|
45
|
+
practice — production deployments should be a single auditable event.
|
|
46
|
+
fix_code:
|
|
47
|
+
- language: yaml
|
|
48
|
+
label: 'Anti-pattern — matrix job with protected environment (creates N review requests)'
|
|
49
|
+
code: |
|
|
50
|
+
jobs:
|
|
51
|
+
deploy:
|
|
52
|
+
strategy:
|
|
53
|
+
matrix:
|
|
54
|
+
region: [us-east-1, eu-west-1, ap-southeast-1]
|
|
55
|
+
environment: production # 3 separate review requests
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
steps:
|
|
58
|
+
- run: echo "deploying to ${{ matrix.region }}"
|
|
59
|
+
- language: yaml
|
|
60
|
+
label: 'Workaround — single non-matrix deploy job collects matrix artifacts and deploys once'
|
|
61
|
+
code: |
|
|
62
|
+
jobs:
|
|
63
|
+
build:
|
|
64
|
+
strategy:
|
|
65
|
+
matrix:
|
|
66
|
+
region: [us-east-1, eu-west-1, ap-southeast-1]
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@v4
|
|
70
|
+
- name: Build for region
|
|
71
|
+
run: make build REGION=${{ matrix.region }}
|
|
72
|
+
- uses: actions/upload-artifact@v4
|
|
73
|
+
with:
|
|
74
|
+
name: build-${{ matrix.region }}
|
|
75
|
+
path: dist/
|
|
76
|
+
|
|
77
|
+
deploy:
|
|
78
|
+
needs: build
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
environment: production # Single review request for all regions
|
|
81
|
+
steps:
|
|
82
|
+
- uses: actions/download-artifact@v4
|
|
83
|
+
with:
|
|
84
|
+
pattern: build-*
|
|
85
|
+
merge-multiple: true
|
|
86
|
+
path: all-dist/
|
|
87
|
+
- name: Deploy all regions
|
|
88
|
+
run: make deploy-all ARTIFACTS_DIR=all-dist/
|
|
89
|
+
prevention:
|
|
90
|
+
- 'Design deployment workflows so the job with environment: protection is never a matrix job'
|
|
91
|
+
- 'Use build-in-matrix, deploy-once pattern: matrix for build/test, single serial job for protected deploy'
|
|
92
|
+
- 'If per-region deployments must be parallel and require environment protection, accept the N-approvals UX'
|
|
93
|
+
- 'Document this limitation in team runbooks before adopting matrix + environment patterns in production pipelines'
|
|
94
|
+
docs:
|
|
95
|
+
- url: 'https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-deployments/managing-environments-for-deployment'
|
|
96
|
+
label: 'GitHub Docs — Managing environments for deployment'
|
|
97
|
+
- url: 'https://github.com/orgs/community/discussions/15690'
|
|
98
|
+
label: 'GitHub Community — Matrix deployment creates multiple approval requests'
|
|
99
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/using-a-matrix-for-your-workflow'
|
|
100
|
+
label: 'GitHub Docs — Using a matrix for your workflow'
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
id: permissions-auth-035
|
|
2
|
+
title: 'actions/attest-build-provenance fails with 403 — missing attestations: write permission'
|
|
3
|
+
category: permissions-auth
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- attestations
|
|
7
|
+
- attest-build-provenance
|
|
8
|
+
- GITHUB_TOKEN
|
|
9
|
+
- permissions
|
|
10
|
+
- 403
|
|
11
|
+
- supply-chain
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'HttpError.*403.*attestation'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'Resource not accessible by integration'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: 'Failed to create attestation'
|
|
18
|
+
flags: 'i'
|
|
19
|
+
error_messages:
|
|
20
|
+
- 'HttpError: 403 — Resource not accessible by integration'
|
|
21
|
+
- 'Failed to create attestation'
|
|
22
|
+
- 'Error: Resource not accessible by integration'
|
|
23
|
+
root_cause: |
|
|
24
|
+
actions/attest-build-provenance (introduced GitHub Changelog, May 2024) requires
|
|
25
|
+
the GITHUB_TOKEN to have the attestations: write scope. This permission did not
|
|
26
|
+
exist before the attestations feature was released and is NOT included in the
|
|
27
|
+
GitHub Actions default token permissions, nor in commonly used broad permission
|
|
28
|
+
sets like contents: write or id-token: write.
|
|
29
|
+
|
|
30
|
+
When the workflow omits attestations: write from its permissions block, the
|
|
31
|
+
action fails with a 403 "Resource not accessible by integration" error. The
|
|
32
|
+
error message does not explicitly mention "attestations: write" as the missing
|
|
33
|
+
scope, making the root cause difficult to identify.
|
|
34
|
+
|
|
35
|
+
Common mistake: developers copy the attest-build-provenance action from
|
|
36
|
+
documentation examples or third-party tutorials that may not include the full
|
|
37
|
+
permissions block, or they use a minimal permissions block that covers other
|
|
38
|
+
needs (contents: read, packages: write) without adding attestations: write.
|
|
39
|
+
|
|
40
|
+
Organization policy note: if the organization has disabled the attestations
|
|
41
|
+
feature, even a correctly-permissioned workflow will fail. Check org-level
|
|
42
|
+
Actions settings under Settings > Actions > General.
|
|
43
|
+
fix: |
|
|
44
|
+
Add attestations: write to the permissions block of the job (or workflow)
|
|
45
|
+
that runs actions/attest-build-provenance. If using OIDC for cloud auth,
|
|
46
|
+
id-token: write is also required for the attestation signature.
|
|
47
|
+
fix_code:
|
|
48
|
+
- language: yaml
|
|
49
|
+
label: 'Add attestations: write to job permissions'
|
|
50
|
+
code: |
|
|
51
|
+
jobs:
|
|
52
|
+
build:
|
|
53
|
+
runs-on: ubuntu-latest
|
|
54
|
+
permissions:
|
|
55
|
+
contents: read
|
|
56
|
+
attestations: write # Required for attest-build-provenance
|
|
57
|
+
id-token: write # Required for OIDC-based attestation signing
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@v4
|
|
60
|
+
|
|
61
|
+
- name: Build artifact
|
|
62
|
+
run: make build
|
|
63
|
+
|
|
64
|
+
- uses: actions/attest-build-provenance@v2
|
|
65
|
+
with:
|
|
66
|
+
subject-path: dist/my-artifact
|
|
67
|
+
- language: yaml
|
|
68
|
+
label: 'Container registry publish with attestation'
|
|
69
|
+
code: |
|
|
70
|
+
jobs:
|
|
71
|
+
publish:
|
|
72
|
+
runs-on: ubuntu-latest
|
|
73
|
+
permissions:
|
|
74
|
+
contents: read
|
|
75
|
+
packages: write
|
|
76
|
+
attestations: write # Required
|
|
77
|
+
id-token: write # Required
|
|
78
|
+
steps:
|
|
79
|
+
- uses: actions/checkout@v4
|
|
80
|
+
- uses: docker/build-push-action@v6
|
|
81
|
+
id: push
|
|
82
|
+
with:
|
|
83
|
+
push: true
|
|
84
|
+
tags: ghcr.io/${{ github.repository }}:latest
|
|
85
|
+
- uses: actions/attest-build-provenance@v2
|
|
86
|
+
with:
|
|
87
|
+
subject-name: ghcr.io/${{ github.repository }}
|
|
88
|
+
subject-digest: ${{ steps.push.outputs.digest }}
|
|
89
|
+
prevention:
|
|
90
|
+
- 'Always include both attestations: write and id-token: write when using attest-build-provenance'
|
|
91
|
+
- 'Check action release notes when adding actions that use newer GitHub platform features'
|
|
92
|
+
- 'The missing scope is not always named in 403 error messages — cross-reference the action docs for required permissions'
|
|
93
|
+
- 'Enable required_workflows or org-level policies to verify attestation is permitted before deploying'
|
|
94
|
+
docs:
|
|
95
|
+
- url: 'https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds'
|
|
96
|
+
label: 'GitHub Docs — Using artifact attestations to establish provenance'
|
|
97
|
+
- url: 'https://github.com/actions/attest-build-provenance'
|
|
98
|
+
label: 'actions/attest-build-provenance repository'
|
|
99
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token'
|
|
100
|
+
label: 'GitHub Docs — Controlling permissions for GITHUB_TOKEN'
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
id: permissions-auth-034
|
|
2
|
+
title: 'Job-level permissions: block replaces workflow-level permissions — undeclared scopes are silently removed'
|
|
3
|
+
category: permissions-auth
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- permissions
|
|
7
|
+
- GITHUB_TOKEN
|
|
8
|
+
- job-level
|
|
9
|
+
- workflow-level
|
|
10
|
+
- 403
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'Resource not accessible by integration'
|
|
13
|
+
flags: 'i'
|
|
14
|
+
- regex: 'HttpError.*403'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
error_messages:
|
|
17
|
+
- 'Resource not accessible by integration'
|
|
18
|
+
- 'HttpError: Resource not accessible by integration'
|
|
19
|
+
- '403 Forbidden'
|
|
20
|
+
root_cause: |
|
|
21
|
+
The permissions: block in GitHub Actions is a REPLACEMENT at the scope where
|
|
22
|
+
it is applied — it does NOT inherit or merge with permissions defined at a
|
|
23
|
+
parent scope.
|
|
24
|
+
|
|
25
|
+
Example: if a workflow defines top-level permissions:
|
|
26
|
+
permissions:
|
|
27
|
+
contents: write
|
|
28
|
+
issues: write
|
|
29
|
+
pull-requests: write
|
|
30
|
+
|
|
31
|
+
And a job within that workflow also defines permissions:
|
|
32
|
+
permissions:
|
|
33
|
+
deployments: write
|
|
34
|
+
|
|
35
|
+
Then that job's GITHUB_TOKEN has ONLY deployments: write. The
|
|
36
|
+
contents: write, issues: write, and pull-requests: write scopes are
|
|
37
|
+
completely dropped for that job.
|
|
38
|
+
|
|
39
|
+
Developers expect job-level permissions to be ADDITIVE (adding new
|
|
40
|
+
permissions on top of the workflow-level set). The actual behavior is the
|
|
41
|
+
opposite: job-level permissions creates an entirely new permission set for
|
|
42
|
+
that job, discarding all workflow-level grants not re-declared.
|
|
43
|
+
|
|
44
|
+
The failure is silent — no warning is emitted about the permission reduction.
|
|
45
|
+
Steps produce 403 or "Resource not accessible by integration" only when
|
|
46
|
+
they actually attempt to use the silently-removed permission.
|
|
47
|
+
fix: |
|
|
48
|
+
When using a job-level permissions: block, re-declare ALL permissions
|
|
49
|
+
that the job needs — not just the new ones you want to add.
|
|
50
|
+
|
|
51
|
+
Alternatively, if all jobs in the workflow need the same permission set,
|
|
52
|
+
set permissions only at the workflow level and omit job-level overrides.
|
|
53
|
+
|
|
54
|
+
Best practice: prefer job-level permissions over workflow-level for the
|
|
55
|
+
principle of least privilege — each job explicitly declares only what it
|
|
56
|
+
needs, with no inheritance confusion.
|
|
57
|
+
fix_code:
|
|
58
|
+
- language: yaml
|
|
59
|
+
label: 'Wrong: job-level block silently drops workflow-level grants'
|
|
60
|
+
code: |
|
|
61
|
+
# Workflow level
|
|
62
|
+
permissions:
|
|
63
|
+
contents: write
|
|
64
|
+
issues: write
|
|
65
|
+
|
|
66
|
+
jobs:
|
|
67
|
+
deploy:
|
|
68
|
+
permissions:
|
|
69
|
+
deployments: write # This REPLACES the above — contents and issues are now GONE
|
|
70
|
+
steps:
|
|
71
|
+
- name: Comment on issue
|
|
72
|
+
uses: actions/github-script@v7
|
|
73
|
+
with:
|
|
74
|
+
script: |
|
|
75
|
+
# This will 403 — issues: write was silently removed
|
|
76
|
+
await github.rest.issues.createComment({ issue_number: 1, body: 'deployed' })
|
|
77
|
+
- language: yaml
|
|
78
|
+
label: 'Correct: re-declare all needed permissions at job level'
|
|
79
|
+
code: |
|
|
80
|
+
# No workflow-level permissions block needed when using job-level
|
|
81
|
+
|
|
82
|
+
jobs:
|
|
83
|
+
deploy:
|
|
84
|
+
permissions:
|
|
85
|
+
contents: write # Re-declared (was at workflow level)
|
|
86
|
+
issues: write # Re-declared (was at workflow level)
|
|
87
|
+
deployments: write # New permission added
|
|
88
|
+
steps:
|
|
89
|
+
- name: Comment on issue
|
|
90
|
+
uses: actions/github-script@v7
|
|
91
|
+
with:
|
|
92
|
+
script: |
|
|
93
|
+
await github.rest.issues.createComment({ issue_number: 1, body: 'deployed' })
|
|
94
|
+
- language: yaml
|
|
95
|
+
label: 'Minimal job permissions — each job declares only what it needs'
|
|
96
|
+
code: |
|
|
97
|
+
# No workflow-level permissions block — all scoped to jobs
|
|
98
|
+
|
|
99
|
+
jobs:
|
|
100
|
+
test:
|
|
101
|
+
permissions:
|
|
102
|
+
checks: write
|
|
103
|
+
contents: read
|
|
104
|
+
steps:
|
|
105
|
+
- uses: actions/checkout@v4
|
|
106
|
+
|
|
107
|
+
deploy:
|
|
108
|
+
permissions:
|
|
109
|
+
contents: read
|
|
110
|
+
deployments: write
|
|
111
|
+
id-token: write
|
|
112
|
+
steps:
|
|
113
|
+
- run: echo "deploying"
|
|
114
|
+
prevention:
|
|
115
|
+
- 'When adding a job-level permissions block, start by listing every permission the job needs from scratch'
|
|
116
|
+
- 'Do not assume any permissions flow down from the workflow level when a job block is present'
|
|
117
|
+
- 'Prefer defining all permissions at the job level (not workflow level) to make the permission set explicit'
|
|
118
|
+
- 'The GitHub Docs explicitly state: permissions at the job level override the workflow-level setting'
|
|
119
|
+
docs:
|
|
120
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token'
|
|
121
|
+
label: 'GitHub Docs — Controlling permissions for GITHUB_TOKEN'
|
|
122
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idpermissions'
|
|
123
|
+
label: 'GitHub Docs — jobs.<job_id>.permissions syntax'
|
package/errors/runner-environment/setup-python-version-range-resolves-to-313-distutils-removed.yml
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
id: runner-environment-099
|
|
2
|
+
title: "setup-python python-version '3' resolves to Python 3.13 — distutils and other removed modules cause ImportError"
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- setup-python
|
|
7
|
+
- python-3-13
|
|
8
|
+
- distutils
|
|
9
|
+
- breaking-change
|
|
10
|
+
- version-pinning
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'ModuleNotFoundError.*distutils'
|
|
13
|
+
flags: 'i'
|
|
14
|
+
- regex: 'No module named .distutils.'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'ImportError.*distutils'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
error_messages:
|
|
19
|
+
- "ModuleNotFoundError: No module named 'distutils'"
|
|
20
|
+
- "No module named 'distutils'"
|
|
21
|
+
- "error: can't find distutils"
|
|
22
|
+
root_cause: |
|
|
23
|
+
Python 3.12 moved distutils into setuptools (no longer stdlib), and Python 3.13
|
|
24
|
+
fully removed it from the standard library (PEP 632, deprecated since 3.10).
|
|
25
|
+
|
|
26
|
+
GitHub Actions workflows using a floating python-version constraint:
|
|
27
|
+
python-version: '3'
|
|
28
|
+
python-version: '3.x'
|
|
29
|
+
python-version: 'latest'
|
|
30
|
+
...resolved to Python 3.13 when it became the latest stable release (October 2024).
|
|
31
|
+
Runner images updated to include 3.13 as the available version for these constraints.
|
|
32
|
+
|
|
33
|
+
Any project that imports distutils directly (setup.py, older NumPy, Cython, some
|
|
34
|
+
SWIG bindings) or tools that internally import it will fail with:
|
|
35
|
+
ModuleNotFoundError: No module named 'distutils'
|
|
36
|
+
|
|
37
|
+
Additional modules removed in Python 3.12-3.13 that break CI:
|
|
38
|
+
- cgi, imghdr (removed 3.13)
|
|
39
|
+
- aifc, sunau, chunk, crypt (removed 3.13)
|
|
40
|
+
- imp module (removed 3.12)
|
|
41
|
+
- asynchat, asyncore (removed 3.12)
|
|
42
|
+
|
|
43
|
+
The failure is from the floating version constraint resolving higher than intended,
|
|
44
|
+
not from the runner image itself. Pinned workflows on 3.11 or 3.12 are unaffected.
|
|
45
|
+
fix: |
|
|
46
|
+
Pin python-version to a specific minor version instead of using a floating
|
|
47
|
+
constraint. If distutils is required, use the setuptools-provided shim.
|
|
48
|
+
|
|
49
|
+
Migration options for distutils usage:
|
|
50
|
+
- Replace distutils.core.setup with setuptools.setup
|
|
51
|
+
- Replace distutils.util.strtobool with a custom bool parser
|
|
52
|
+
- Replace distutils.version.LooseVersion with packaging.version.Version
|
|
53
|
+
- Install setuptools on Python 3.13 to restore the distutils shim
|
|
54
|
+
fix_code:
|
|
55
|
+
- language: yaml
|
|
56
|
+
label: 'Pin to specific minor version to avoid 3.13+ resolution'
|
|
57
|
+
code: |
|
|
58
|
+
- uses: actions/setup-python@v5
|
|
59
|
+
with:
|
|
60
|
+
python-version: '3.11' # Pinned — won't resolve to 3.13+
|
|
61
|
+
# OR: '3.12' (distutils still available via setuptools shim)
|
|
62
|
+
- language: yaml
|
|
63
|
+
label: 'Use setuptools shim on Python 3.13'
|
|
64
|
+
code: |
|
|
65
|
+
- uses: actions/setup-python@v5
|
|
66
|
+
with:
|
|
67
|
+
python-version: '3.13'
|
|
68
|
+
- name: Install setuptools for distutils compatibility
|
|
69
|
+
run: pip install setuptools # Restores distutils shim on 3.13+
|
|
70
|
+
- language: yaml
|
|
71
|
+
label: 'Pin version via .python-version file'
|
|
72
|
+
code: |
|
|
73
|
+
# .python-version file in repo root:
|
|
74
|
+
# 3.11.9
|
|
75
|
+
|
|
76
|
+
- uses: actions/setup-python@v5
|
|
77
|
+
with:
|
|
78
|
+
python-version-file: '.python-version' # Reads from repo file
|
|
79
|
+
- language: yaml
|
|
80
|
+
label: 'Matrix across versions to catch breakage early'
|
|
81
|
+
code: |
|
|
82
|
+
jobs:
|
|
83
|
+
test:
|
|
84
|
+
strategy:
|
|
85
|
+
matrix:
|
|
86
|
+
python-version: ['3.11', '3.12', '3.13']
|
|
87
|
+
steps:
|
|
88
|
+
- uses: actions/setup-python@v5
|
|
89
|
+
with:
|
|
90
|
+
python-version: ${{ matrix.python-version }}
|
|
91
|
+
- run: pip install setuptools # Shim for 3.13
|
|
92
|
+
- run: pip install -e .
|
|
93
|
+
- run: pytest
|
|
94
|
+
prevention:
|
|
95
|
+
- 'Never use python-version: 3 or python-version: 3.x in production workflows without testing each new minor release'
|
|
96
|
+
- 'Pin to a specific minor version (3.11, 3.12) or use a .python-version file in the repo'
|
|
97
|
+
- 'Run CI on a matrix of python versions to catch version-specific breakage early'
|
|
98
|
+
- 'Audit setup.py for direct distutils imports and replace with setuptools equivalents before upgrading to 3.13'
|
|
99
|
+
docs:
|
|
100
|
+
- url: 'https://docs.python.org/3/whatsnew/3.13.html#removed-modules'
|
|
101
|
+
label: 'Python 3.13 — Removed Modules'
|
|
102
|
+
- url: 'https://peps.python.org/pep-0632/'
|
|
103
|
+
label: 'PEP 632 — Deprecate distutils'
|
|
104
|
+
- url: 'https://github.com/actions/setup-python'
|
|
105
|
+
label: 'actions/setup-python repository'
|
|
106
|
+
- url: 'https://docs.github.com/en/actions/use-cases-and-examples/building-and-testing/building-and-testing-python'
|
|
107
|
+
label: 'GitHub Docs — Building and testing Python'
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
id: silent-failures-048
|
|
2
|
+
title: 'Composite action outputs not propagated — outputs: declaration required in action.yml'
|
|
3
|
+
category: silent-failures
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- composite
|
|
7
|
+
- outputs
|
|
8
|
+
- action.yml
|
|
9
|
+
- step-outputs
|
|
10
|
+
- empty-string
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'steps\.\w+\.outputs\.'
|
|
13
|
+
flags: 'i'
|
|
14
|
+
error_messages: []
|
|
15
|
+
root_cause: |
|
|
16
|
+
In composite actions, step outputs from internal steps are NOT automatically
|
|
17
|
+
visible to the action's callers. The composite action's action.yml must
|
|
18
|
+
declare an outputs: block that explicitly maps each output name to a value
|
|
19
|
+
expression referencing an internal step's output:
|
|
20
|
+
|
|
21
|
+
outputs:
|
|
22
|
+
my-result:
|
|
23
|
+
description: "The result"
|
|
24
|
+
value: ${{ steps.build.outputs.result }}
|
|
25
|
+
|
|
26
|
+
Without this declaration, ${{ steps.my-action.outputs.my-result }} in the
|
|
27
|
+
calling workflow evaluates to empty string with no error or warning.
|
|
28
|
+
|
|
29
|
+
This is different from regular workflow jobs, where step outputs are
|
|
30
|
+
accessible within the same job via steps.<id>.outputs.<name> without any
|
|
31
|
+
explicit mapping. Composite actions require explicit wiring because the
|
|
32
|
+
action boundary creates an isolation layer — internal step IDs are not
|
|
33
|
+
exposed to callers.
|
|
34
|
+
|
|
35
|
+
Common mistake pattern: developer tests the composite action, sees that
|
|
36
|
+
internal steps set outputs correctly, but the caller always receives "".
|
|
37
|
+
The action.yml outputs: block is missing or references a wrong step id.
|
|
38
|
+
fix: |
|
|
39
|
+
1. Open the composite action's action.yml file.
|
|
40
|
+
2. Add an outputs: block (after the inputs: block if present).
|
|
41
|
+
3. For each output you need to expose, add an entry with:
|
|
42
|
+
value: ${{ steps.<internal-step-id>.outputs.<output-name> }}
|
|
43
|
+
4. Ensure the referenced internal step has a matching id: field.
|
|
44
|
+
5. Ensure the internal step writes outputs via GITHUB_OUTPUT:
|
|
45
|
+
echo "result=value" >> $GITHUB_OUTPUT
|
|
46
|
+
fix_code:
|
|
47
|
+
- language: yaml
|
|
48
|
+
label: 'action.yml — declare outputs with value expressions'
|
|
49
|
+
code: |
|
|
50
|
+
# .github/actions/my-build/action.yml
|
|
51
|
+
name: 'My Build Action'
|
|
52
|
+
description: 'Builds the project and returns the version'
|
|
53
|
+
|
|
54
|
+
outputs:
|
|
55
|
+
build-version:
|
|
56
|
+
description: 'The version that was built'
|
|
57
|
+
value: ${{ steps.get-version.outputs.version }}
|
|
58
|
+
artifact-path:
|
|
59
|
+
description: 'Path to the built artifact'
|
|
60
|
+
value: ${{ steps.build.outputs.artifact }}
|
|
61
|
+
|
|
62
|
+
runs:
|
|
63
|
+
using: composite
|
|
64
|
+
steps:
|
|
65
|
+
- id: get-version
|
|
66
|
+
shell: bash
|
|
67
|
+
run: echo "version=$(cat version.txt)" >> $GITHUB_OUTPUT
|
|
68
|
+
|
|
69
|
+
- id: build
|
|
70
|
+
shell: bash
|
|
71
|
+
run: |
|
|
72
|
+
make build
|
|
73
|
+
echo "artifact=dist/app.tar.gz" >> $GITHUB_OUTPUT
|
|
74
|
+
- language: yaml
|
|
75
|
+
label: 'Calling workflow — accessing composite action outputs'
|
|
76
|
+
code: |
|
|
77
|
+
jobs:
|
|
78
|
+
release:
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
steps:
|
|
81
|
+
- uses: actions/checkout@v4
|
|
82
|
+
|
|
83
|
+
- id: build
|
|
84
|
+
uses: ./.github/actions/my-build
|
|
85
|
+
|
|
86
|
+
- name: Use outputs
|
|
87
|
+
run: |
|
|
88
|
+
echo "Version: ${{ steps.build.outputs.build-version }}"
|
|
89
|
+
echo "Artifact: ${{ steps.build.outputs.artifact-path }}"
|
|
90
|
+
prevention:
|
|
91
|
+
- 'Every composite action output must have a corresponding entry in the outputs: block of action.yml'
|
|
92
|
+
- 'Internal steps must have an id: field for the outputs value: expression to reference'
|
|
93
|
+
- 'The step id in the value: expression must exactly match the internal step id: value'
|
|
94
|
+
- 'Add a debug step in the action to print $GITHUB_OUTPUT contents when troubleshooting'
|
|
95
|
+
docs:
|
|
96
|
+
- url: 'https://docs.github.com/en/actions/sharing-automations/creating-actions/metadata-syntax-for-github-actions#outputs-for-composite-actions'
|
|
97
|
+
label: 'GitHub Docs — Outputs for composite actions'
|
|
98
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/passing-information-between-jobs'
|
|
99
|
+
label: 'GitHub Docs — Passing information between jobs'
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
id: silent-failures-049
|
|
2
|
+
title: 'GITHUB_OUTPUT multiline heredoc value silently truncated when content contains the delimiter string'
|
|
3
|
+
category: silent-failures
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- GITHUB_OUTPUT
|
|
7
|
+
- multiline
|
|
8
|
+
- heredoc
|
|
9
|
+
- delimiter-collision
|
|
10
|
+
- environment-files
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'echo\s+\"\w+<<EOF\"'
|
|
13
|
+
flags: 'i'
|
|
14
|
+
error_messages: []
|
|
15
|
+
root_cause: |
|
|
16
|
+
GitHub Actions environment files (GITHUB_OUTPUT, GITHUB_ENV, GITHUB_STEP_SUMMARY)
|
|
17
|
+
use a heredoc-style syntax for multiline values:
|
|
18
|
+
|
|
19
|
+
echo "BODY<<EOF" >> $GITHUB_OUTPUT
|
|
20
|
+
echo "first line" >> $GITHUB_OUTPUT
|
|
21
|
+
echo "second line" >> $GITHUB_OUTPUT
|
|
22
|
+
echo "EOF" >> $GITHUB_OUTPUT
|
|
23
|
+
|
|
24
|
+
If the multiline content itself contains the exact delimiter string ("EOF" in
|
|
25
|
+
the example above) on a line by itself, the runner stops reading at that point
|
|
26
|
+
and silently truncates the value. No error is raised and the step exits 0.
|
|
27
|
+
|
|
28
|
+
Common scenarios:
|
|
29
|
+
1. A release body or commit message that happens to contain "EOF" on its own line.
|
|
30
|
+
2. A generated file that includes shell script snippets (which often use EOF).
|
|
31
|
+
3. A changelog that uses EOF as a delimiter in a code example.
|
|
32
|
+
|
|
33
|
+
The delimiter collision causes the output variable to contain only the content
|
|
34
|
+
up to (but not including) the first occurrence of the delimiter string, with
|
|
35
|
+
no indication that truncation occurred.
|
|
36
|
+
fix: |
|
|
37
|
+
Use a randomly-generated or sufficiently unique delimiter that will not
|
|
38
|
+
appear in the content. Common approaches:
|
|
39
|
+
|
|
40
|
+
1. Generate a UUID or random hex string at runtime and use it as the delimiter.
|
|
41
|
+
2. Use a very long, unusual string that is unlikely to appear in content.
|
|
42
|
+
|
|
43
|
+
The GitHub documentation explicitly recommends a random delimiter to avoid
|
|
44
|
+
this collision:
|
|
45
|
+
https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#multiline-strings
|
|
46
|
+
fix_code:
|
|
47
|
+
- language: yaml
|
|
48
|
+
label: 'Unsafe — static delimiter may collide with content'
|
|
49
|
+
code: |
|
|
50
|
+
- name: Set multiline output (unsafe)
|
|
51
|
+
run: |
|
|
52
|
+
echo "BODY<<EOF" >> $GITHUB_OUTPUT
|
|
53
|
+
echo "${{ steps.notes.outputs.content }}" >> $GITHUB_OUTPUT
|
|
54
|
+
echo "EOF" >> $GITHUB_OUTPUT
|
|
55
|
+
- language: yaml
|
|
56
|
+
label: 'Safe — random delimiter prevents collision'
|
|
57
|
+
code: |
|
|
58
|
+
- name: Set multiline output (safe random delimiter)
|
|
59
|
+
run: |
|
|
60
|
+
DELIM="ghadelim_$(head -c 16 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | head -c 16)"
|
|
61
|
+
echo "BODY<<${DELIM}" >> $GITHUB_OUTPUT
|
|
62
|
+
echo "${{ steps.notes.outputs.content }}" >> $GITHUB_OUTPUT
|
|
63
|
+
echo "${DELIM}" >> $GITHUB_OUTPUT
|
|
64
|
+
- language: yaml
|
|
65
|
+
label: 'Windows — PowerShell random delimiter'
|
|
66
|
+
code: |
|
|
67
|
+
- name: Set multiline output (PowerShell)
|
|
68
|
+
shell: pwsh
|
|
69
|
+
run: |
|
|
70
|
+
$delim = "ghadelim_$([System.Guid]::NewGuid().ToString('N').Substring(0, 16))"
|
|
71
|
+
"BODY<<$delim" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
|
|
72
|
+
$releaseNotes | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
|
|
73
|
+
$delim | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
|
|
74
|
+
prevention:
|
|
75
|
+
- 'Never use a simple static delimiter like EOF, END, or DONE for multiline GITHUB_OUTPUT values'
|
|
76
|
+
- 'Always use a random or UUID-based delimiter when the content could be dynamic or user-provided'
|
|
77
|
+
- 'Test multiline output steps with content that deliberately contains common delimiter strings'
|
|
78
|
+
- 'GitHub docs recommend randomly generated delimiters for all multiline environment file writes'
|
|
79
|
+
docs:
|
|
80
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#multiline-strings'
|
|
81
|
+
label: 'GitHub Docs — Workflow commands: multiline strings'
|
|
82
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables'
|
|
83
|
+
label: 'GitHub Docs — Store information in variables'
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
id: triggers-032
|
|
2
|
+
title: 'on.workflow_run.workflows matches name: field not filename — mismatch silently never triggers'
|
|
3
|
+
category: triggers
|
|
4
|
+
severity: warning
|
|
5
|
+
tags:
|
|
6
|
+
- workflow_run
|
|
7
|
+
- trigger
|
|
8
|
+
- name-mismatch
|
|
9
|
+
- silent
|
|
10
|
+
- filename
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: 'workflow_run'
|
|
13
|
+
flags: ''
|
|
14
|
+
error_messages: []
|
|
15
|
+
root_cause: |
|
|
16
|
+
The on.workflow_run.workflows: array matches against the target workflow's
|
|
17
|
+
top-level name: field — NOT the workflow's filename.
|
|
18
|
+
|
|
19
|
+
If the target workflow contains:
|
|
20
|
+
name: CI Pipeline
|
|
21
|
+
|
|
22
|
+
then the triggering workflow must specify:
|
|
23
|
+
on:
|
|
24
|
+
workflow_run:
|
|
25
|
+
workflows: ["CI Pipeline"]
|
|
26
|
+
|
|
27
|
+
Using the filename ("build.yml", "ci.yml", or ".github/workflows/ci.yml")
|
|
28
|
+
never matches when a name: field is present. The comparison is case-sensitive:
|
|
29
|
+
"CI" != "ci" != "Ci".
|
|
30
|
+
|
|
31
|
+
Secondary rule: if the target workflow has no name: field, GitHub uses the
|
|
32
|
+
workflow file path relative to the repo root as the match string (e.g.,
|
|
33
|
+
".github/workflows/build.yml").
|
|
34
|
+
|
|
35
|
+
No error or warning is produced on mismatch — the triggering workflow
|
|
36
|
+
silently never fires. This is one of the most common workflow_run
|
|
37
|
+
misconfiguration patterns on Stack Overflow.
|
|
38
|
+
fix: |
|
|
39
|
+
1. Open the target workflow file.
|
|
40
|
+
2. Find the top-level name: field. If absent, note the repo-relative path.
|
|
41
|
+
3. Use that exact string (case-sensitive) in the workflows: array.
|
|
42
|
+
4. Merge/deploy the triggering workflow to the default branch — workflow_run
|
|
43
|
+
only fires when the trigger configuration itself is on the default branch.
|
|
44
|
+
fix_code:
|
|
45
|
+
- language: yaml
|
|
46
|
+
label: 'Correct: match the target workflow name: field exactly'
|
|
47
|
+
code: |
|
|
48
|
+
# Target workflow file: .github/workflows/ci.yml
|
|
49
|
+
name: CI Pipeline # <-- this is what workflow_run matches on
|
|
50
|
+
|
|
51
|
+
on: [push]
|
|
52
|
+
jobs:
|
|
53
|
+
build:
|
|
54
|
+
runs-on: ubuntu-latest
|
|
55
|
+
steps:
|
|
56
|
+
- run: echo "building"
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
# Triggering workflow file: .github/workflows/deploy.yml
|
|
60
|
+
on:
|
|
61
|
+
workflow_run:
|
|
62
|
+
workflows: ["CI Pipeline"] # Must match name: exactly (not "ci.yml")
|
|
63
|
+
types: [completed]
|
|
64
|
+
jobs:
|
|
65
|
+
deploy:
|
|
66
|
+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
steps:
|
|
69
|
+
- run: echo "deploying"
|
|
70
|
+
- language: yaml
|
|
71
|
+
label: 'When target workflow has no name: field, use the file path'
|
|
72
|
+
code: |
|
|
73
|
+
# Target workflow has no name: field at .github/workflows/build.yml
|
|
74
|
+
on: [push]
|
|
75
|
+
jobs:
|
|
76
|
+
build:
|
|
77
|
+
runs-on: ubuntu-latest
|
|
78
|
+
steps:
|
|
79
|
+
- run: echo "building"
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
# Triggering workflow must use the repo-relative path
|
|
83
|
+
on:
|
|
84
|
+
workflow_run:
|
|
85
|
+
workflows: [".github/workflows/build.yml"]
|
|
86
|
+
types: [completed]
|
|
87
|
+
prevention:
|
|
88
|
+
- 'Always add a name: field to every workflow you intend to reference in workflow_run'
|
|
89
|
+
- 'Copy the name: value exactly (including capitalization and spaces) into workflows:'
|
|
90
|
+
- 'Add a comment in the triggering workflow citing which file the name came from'
|
|
91
|
+
- 'workflow_run silently never fires on name mismatches — no diagnostic is emitted'
|
|
92
|
+
docs:
|
|
93
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_run'
|
|
94
|
+
label: 'GitHub Docs — workflow_run trigger'
|
|
95
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#name'
|
|
96
|
+
label: 'GitHub Docs — Workflow name: field'
|
package/package.json
CHANGED