@htekdev/actions-debugger 1.0.23 → 1.0.24
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-minimum-retention-one-day.yml +153 -0
- package/errors/caching-artifacts/cache-api-propagation-delay-post-save.yml +128 -0
- package/errors/caching-artifacts/cache-backend-internal-error-skipped.yml +75 -0
- package/errors/caching-artifacts/cache-hit-step-id-case-sensitive-mismatch.yml +95 -0
- package/errors/caching-artifacts/cache-save-post-step-skipped-on-failure.yml +114 -0
- package/errors/concurrency-timing/deploy-pages-in-progress-deployment-wedged.yml +70 -0
- package/errors/concurrency-timing/deployment-review-timeout-expired.yml +88 -0
- package/errors/concurrency-timing/job-concurrency-scope-per-run-not-global.yml +81 -0
- package/errors/concurrency-timing/merge-queue-concurrency-cancel-blocks-all.yml +86 -0
- package/errors/concurrency-timing/reusable-workflow-github-workflow-context-cancel.yml +124 -0
- package/errors/concurrency-timing/runner-scale-set-jobs-never-start.yml +123 -0
- package/errors/concurrency-timing/runner-temp-dir-race-concurrent-workers.yml +90 -0
- package/errors/known-unsolved/artifact-download-url-unauthenticated-404.yml +98 -0
- package/errors/known-unsolved/checkout-v6-credentials-docker-run-manual.yml +105 -0
- package/errors/known-unsolved/concurrency-groups-repo-scoped-only.yml +138 -0
- package/errors/known-unsolved/matrix-256-job-limit.yml +142 -0
- package/errors/known-unsolved/merge-group-paths-filter-not-supported.yml +137 -0
- package/errors/known-unsolved/no-job-allow-failure.yml +73 -0
- package/errors/known-unsolved/schedule-cron-hours-long-queue-drift.yml +101 -0
- package/errors/permissions-auth/checkout-persist-credentials-token-write.yml +90 -0
- package/errors/permissions-auth/create-github-app-token-cross-job-token-revoked.yml +95 -0
- package/errors/permissions-auth/github-token-contents-write-missing-git-push.yml +117 -0
- package/errors/permissions-auth/org-actions-policy-blocks-unapproved-action.yml +106 -0
- package/errors/runner-environment/codeql-action-v2-deprecated.yml +110 -0
- package/errors/runner-environment/macos-26-openssl-3-system-library-breaking.yml +114 -0
- package/errors/runner-environment/macos-26-ruby-34-default-upgrade.yml +114 -0
- package/errors/runner-environment/macos-26-xcode-default-265-pin-required.yml +99 -0
- package/errors/runner-environment/macos-latest-label-switches-to-macos26.yml +127 -0
- package/errors/runner-environment/node20-removed-toolcache-default-node22.yml +104 -0
- package/errors/runner-environment/powershell-74-76-threadjob-module-rename.yml +124 -0
- package/errors/runner-environment/self-hosted-runner-not-found.yml +134 -0
- package/errors/runner-environment/self-hosted-runner-selinux-service-exec-failure.yml +116 -0
- package/errors/runner-environment/service-container-no-healthcheck.yml +158 -0
- package/errors/runner-environment/setup-node-v5-corepack-pnpm-not-found.yml +101 -0
- package/errors/runner-environment/setup-node-yarn-not-installed-self-hosted.yml +76 -0
- package/errors/runner-environment/setup-python-externally-managed-env-error.yml +95 -0
- package/errors/runner-environment/windows-2019-runner-retired-june2025.yml +118 -0
- package/errors/runner-environment/windows-2022-docker-daemon-not-started.yml +108 -0
- package/errors/silent-failures/cache-hit-output-string-not-boolean.yml +96 -0
- package/errors/silent-failures/checkout-lfs-pointer-not-content.yml +105 -0
- package/errors/silent-failures/reusable-workflow-output-skipped-contains-secret.yml +115 -0
- package/errors/silent-failures/setup-node-silent-download-exit-zero.yml +105 -0
- package/errors/silent-failures/setup-python-truncated-manifest-silent-exit.yml +111 -0
- package/errors/silent-failures/undefined-env-expression-empty-string-silent.yml +115 -0
- package/errors/silent-failures/windows-powershell-github-output-bash-syntax.yml +118 -0
- package/errors/triggers/fork-pr-first-time-contributor-approval-required.yml +142 -0
- package/errors/triggers/on-push-branches-glob-star-no-slash-match.yml +78 -0
- package/errors/triggers/pull-request-target-env-protection-default-branch-eval.yml +117 -0
- package/errors/triggers/required-status-check-renamed-never-passes.yml +87 -0
- package/errors/triggers/schedule-cron-self-hosted-runner-not-triggered.yml +107 -0
- package/errors/yaml-syntax/composite-action-run-shell-missing.yml +90 -0
- package/errors/yaml-syntax/composite-action-secrets-context-unavailable.yml +99 -0
- package/errors/yaml-syntax/github-script-octokit-renamed-to-github.yml +130 -0
- package/errors/yaml-syntax/labeler-v5-config-format-breaking.yml +67 -0
- package/errors/yaml-syntax/runs-on-expression-array-syntax-error.yml +121 -0
- package/errors/yaml-syntax/setup-go-matrix-version-float-coercion.yml +69 -0
- package/package.json +1 -1
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
id: known-unsolved-026
|
|
2
|
+
title: "No Native allow-failure Mechanism for Jobs"
|
|
3
|
+
category: known-unsolved
|
|
4
|
+
severity: limitation
|
|
5
|
+
tags:
|
|
6
|
+
- continue-on-error
|
|
7
|
+
- allow-failure
|
|
8
|
+
- job-status
|
|
9
|
+
- pr-checks
|
|
10
|
+
- known-limitation
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: "allow.?failure"
|
|
13
|
+
flags: "i"
|
|
14
|
+
- regex: "continue-on-error.*(still|marked).*(fail|error)"
|
|
15
|
+
flags: "i"
|
|
16
|
+
error_messages:
|
|
17
|
+
- "allow-failure is not a valid key for jobs"
|
|
18
|
+
- "Job failed but continue-on-error is set — result is still 'failure'"
|
|
19
|
+
root_cause: |
|
|
20
|
+
GitHub Actions has no native `allow-failure` key for jobs (unlike GitLab CI's `allow_failure`).
|
|
21
|
+
Adding `allow-failure: true` to a job produces a YAML validation error or is silently ignored
|
|
22
|
+
because it is not a recognized field.
|
|
23
|
+
|
|
24
|
+
The closest equivalent is `continue-on-error: true`, but this has different semantics:
|
|
25
|
+
- The job still shows as failed in the workflow run summary (yellow warning icon, not green check).
|
|
26
|
+
- If the job is listed as a required status check in branch protection, the PR is still blocked.
|
|
27
|
+
- The overall workflow conclusion becomes "success" but the individual job result remains "failure".
|
|
28
|
+
- Downstream jobs using `needs.<job>.result == 'success'` will not execute.
|
|
29
|
+
|
|
30
|
+
This is a long-standing platform gap with 1,571 GitHub reactions (actions/runner#2347) and a
|
|
31
|
+
community discussion with broad support (orgs/community/discussions/15452).
|
|
32
|
+
fix: |
|
|
33
|
+
There is no perfect equivalent to allow-failure. The recommended workaround is `continue-on-error: true`
|
|
34
|
+
on the optional job, combined with a separate "gate" job that aggregates results and is made the
|
|
35
|
+
required status check in branch protection instead.
|
|
36
|
+
|
|
37
|
+
1. Add `continue-on-error: true` to the optional job.
|
|
38
|
+
2. Add a gate job with `needs: [optional-job]` and `if: always()`.
|
|
39
|
+
3. The gate job always succeeds — make it the required branch-protection check.
|
|
40
|
+
4. Downstream jobs check `needs.optional-job.result` explicitly if needed.
|
|
41
|
+
fix_code:
|
|
42
|
+
- language: yaml
|
|
43
|
+
label: "Workaround: gate job pattern for allow-failure equivalent"
|
|
44
|
+
code: |
|
|
45
|
+
jobs:
|
|
46
|
+
optional-flaky:
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
continue-on-error: true # job can fail without blocking workflow
|
|
49
|
+
steps:
|
|
50
|
+
- run: ./run-flaky-tests.sh
|
|
51
|
+
|
|
52
|
+
required-gate:
|
|
53
|
+
runs-on: ubuntu-latest
|
|
54
|
+
needs: [optional-flaky]
|
|
55
|
+
if: always() # always runs regardless of optional-flaky result
|
|
56
|
+
steps:
|
|
57
|
+
- name: Report optional job outcome
|
|
58
|
+
run: |
|
|
59
|
+
echo "Optional job result: ${{ needs.optional-flaky.result }}"
|
|
60
|
+
# This step always exits 0 — make required-gate the branch protection check
|
|
61
|
+
exit 0
|
|
62
|
+
prevention:
|
|
63
|
+
- "Do not add allow-failure: true to jobs — it is not a recognized Actions field and causes a workflow validation error."
|
|
64
|
+
- "Use continue-on-error: true as the closest equivalent but understand its PR check implications."
|
|
65
|
+
- "For required status checks, use the gate/aggregator job pattern — never the optional job itself."
|
|
66
|
+
- "Track orgs/community/discussions/15452 for official platform support of allow-failure."
|
|
67
|
+
docs:
|
|
68
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/using-jobs-in-a-workflow"
|
|
69
|
+
label: "GitHub Actions — Using jobs in a workflow (continue-on-error)"
|
|
70
|
+
- url: "https://github.com/actions/runner/issues/2347"
|
|
71
|
+
label: "actions/runner #2347 — allow-failure support request (1571 reactions)"
|
|
72
|
+
- url: "https://github.com/orgs/community/discussions/15452"
|
|
73
|
+
label: "Community discussion #15452 — allow-failure for jobs"
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
id: known-unsolved-025
|
|
2
|
+
title: "Scheduled Workflow Queue Drift Exceeds Hours and Worsens Over Time"
|
|
3
|
+
category: known-unsolved
|
|
4
|
+
severity: limitation
|
|
5
|
+
tags:
|
|
6
|
+
- cron
|
|
7
|
+
- schedule
|
|
8
|
+
- drift
|
|
9
|
+
- queue-delay
|
|
10
|
+
- best-effort
|
|
11
|
+
- platform-load
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: "schedule"
|
|
14
|
+
flags: "i"
|
|
15
|
+
error_messages:
|
|
16
|
+
- "Scheduled workflows can be delayed during periods of high loads of GitHub Actions workflow runs."
|
|
17
|
+
root_cause: |
|
|
18
|
+
GitHub Actions scheduled workflows use a best-effort queue. GitHub does not guarantee
|
|
19
|
+
that a schedule: trigger fires at the exact cron time. During periods of high platform
|
|
20
|
+
load, workflows are queued and the dispatch delay can reach multiple hours.
|
|
21
|
+
|
|
22
|
+
Since 2025, average delays have been growing on the GitHub-hosted infrastructure:
|
|
23
|
+
workflows that previously started within 10-20 minutes now commonly wait 1-4+ hours.
|
|
24
|
+
The drift is not constant — it varies by time of day and platform load and compounds
|
|
25
|
+
over months for daily/nightly jobs.
|
|
26
|
+
|
|
27
|
+
Key contributing factors:
|
|
28
|
+
- Growth in GitHub's user base means more repositories with scheduled workflows compete
|
|
29
|
+
for the same dispatch queue infrastructure.
|
|
30
|
+
- The midnight UTC window is severely congested; nearby times face similar load.
|
|
31
|
+
- GitHub dispatches schedule events in batches; individual repos have no dispatch priority.
|
|
32
|
+
- Repositories with no activity for 60+ days have their schedules disabled entirely.
|
|
33
|
+
- GitHub's documentation explicitly states schedules are best-effort with no SLA.
|
|
34
|
+
|
|
35
|
+
This is a known platform-capacity limitation, not a bug. No fix or workaround guarantees
|
|
36
|
+
on-time execution from within GitHub's scheduler.
|
|
37
|
+
Reported in actions/runner#4468 (open Jun 2026); discussed in community/196910.
|
|
38
|
+
fix: |
|
|
39
|
+
There is no way to guarantee on-time execution of a scheduled GitHub Actions workflow.
|
|
40
|
+
Mitigation strategies depend on how time-sensitive the job is.
|
|
41
|
+
|
|
42
|
+
Mitigation 1: Schedule away from congestion windows.
|
|
43
|
+
Avoid exact hours and midnight UTC. Use irregular minutes and off-peak hours
|
|
44
|
+
(e.g., 23 14 * * * instead of 0 0 * * *).
|
|
45
|
+
|
|
46
|
+
Mitigation 2: Use an external cron service with workflow_dispatch.
|
|
47
|
+
Remove the on: schedule trigger and replace it with workflow_dispatch. An external
|
|
48
|
+
scheduler (cloud function, server cron, GitHub App) calls the GitHub REST API dispatches
|
|
49
|
+
endpoint on time. The workflow starts immediately because workflow_dispatch jobs are not
|
|
50
|
+
subject to the schedule queue.
|
|
51
|
+
|
|
52
|
+
Mitigation 3: Accept the delay and build tolerance.
|
|
53
|
+
For non-time-critical automations (nightly builds, maintenance tasks), build tolerance
|
|
54
|
+
into downstream systems rather than fighting the delay.
|
|
55
|
+
|
|
56
|
+
Mitigation 4: Self-hosted runners with external scheduling.
|
|
57
|
+
For strict timing requirements, combine self-hosted runners with an external trigger so
|
|
58
|
+
the job bypasses GitHub hosted-runner queuing entirely.
|
|
59
|
+
fix_code:
|
|
60
|
+
- language: yaml
|
|
61
|
+
label: "Use irregular schedule time to avoid peak congestion"
|
|
62
|
+
code: |
|
|
63
|
+
on:
|
|
64
|
+
schedule:
|
|
65
|
+
# Avoid :00, :15, :30, :45 and midnight UTC — use irregular off-peak times
|
|
66
|
+
- cron: '23 14 * * *' # 2:23 PM UTC
|
|
67
|
+
workflow_dispatch: {} # Manual fallback for missed or delayed runs
|
|
68
|
+
- language: yaml
|
|
69
|
+
label: "External cron dispatch via GitHub API (reliable timing)"
|
|
70
|
+
code: |
|
|
71
|
+
# External scheduler (Lambda, cron job, GitHub App) calls:
|
|
72
|
+
# curl -X POST \
|
|
73
|
+
# -H "Authorization: Bearer $GH_TOKEN" \
|
|
74
|
+
# https://api.github.com/repos/OWNER/REPO/actions/workflows/nightly.yml/dispatches \
|
|
75
|
+
# -d '{"ref":"main"}'
|
|
76
|
+
#
|
|
77
|
+
# Your workflow — no on: schedule needed:
|
|
78
|
+
on:
|
|
79
|
+
workflow_dispatch: {}
|
|
80
|
+
|
|
81
|
+
jobs:
|
|
82
|
+
nightly:
|
|
83
|
+
runs-on: ubuntu-latest
|
|
84
|
+
steps:
|
|
85
|
+
- uses: actions/checkout@v4
|
|
86
|
+
- run: ./scripts/nightly-build.sh
|
|
87
|
+
prevention:
|
|
88
|
+
- "Never build SLAs or downstream dependencies that assume a scheduled workflow starts within minutes of its cron time."
|
|
89
|
+
- "Always add workflow_dispatch: alongside schedule: so delayed or missed runs can be manually triggered from the Actions UI."
|
|
90
|
+
- "Use non-round-number cron minutes (17, 23, 41, etc.) to avoid the most congested slots."
|
|
91
|
+
- "For time-critical jobs, use an external scheduler that calls the GitHub API rather than relying on GitHub scheduler queue."
|
|
92
|
+
- "Track repository activity — GitHub disables scheduled workflows on repos inactive for 60+ days."
|
|
93
|
+
docs:
|
|
94
|
+
- url: "https://github.com/actions/runner/issues/4468"
|
|
95
|
+
label: "actions/runner#4468 — Continuously increasing schedule drift (Jun 2026)"
|
|
96
|
+
- url: "https://github.com/orgs/community/discussions/196910"
|
|
97
|
+
label: "Community discussion: schedule drift increasing over time"
|
|
98
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#schedule"
|
|
99
|
+
label: "schedule event — best-effort documentation"
|
|
100
|
+
- url: "https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-workflow-runs/disabling-and-enabling-a-workflow"
|
|
101
|
+
label: "Scheduled workflow disabled after 60 days inactivity"
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
id: permissions-auth-028
|
|
2
|
+
title: "checkout persist-credentials:true Default Stores GITHUB_TOKEN in .git/config"
|
|
3
|
+
category: permissions-auth
|
|
4
|
+
severity: warning
|
|
5
|
+
tags:
|
|
6
|
+
- checkout
|
|
7
|
+
- persist-credentials
|
|
8
|
+
- github-token
|
|
9
|
+
- security
|
|
10
|
+
- credential-helper
|
|
11
|
+
patterns:
|
|
12
|
+
- regex: "persist.credentials.*(true|default)|persist-credentials.*not.*false"
|
|
13
|
+
flags: "i"
|
|
14
|
+
- regex: "\\.git.config.*token|credential.*helper.*store.*github"
|
|
15
|
+
flags: "i"
|
|
16
|
+
error_messages:
|
|
17
|
+
- "GITHUB_TOKEN persisted in .git/config by actions/checkout"
|
|
18
|
+
- "Unexpected repository write from a non-commit step"
|
|
19
|
+
root_cause: |
|
|
20
|
+
`actions/checkout` defaults to `persist-credentials: true`. When enabled, the action configures
|
|
21
|
+
a credential helper that stores the GITHUB_TOKEN in the repository local `.git/config`.
|
|
22
|
+
Every repository operation in subsequent steps automatically uses this token for authentication,
|
|
23
|
+
without any explicit credential setup in those steps.
|
|
24
|
+
|
|
25
|
+
Consequences:
|
|
26
|
+
- Any step that invokes the source control client (directly or via tools that do so internally)
|
|
27
|
+
inherits repository write access if the job holds `contents: write` permission.
|
|
28
|
+
- Third-party tools that call the source control client internally (Docker buildx, dependency
|
|
29
|
+
managers reading version tags, build tools) receive unintended repository access.
|
|
30
|
+
- In fork PR workflows (`pull_request_target`), checking out a fork ref with persisted
|
|
31
|
+
credentials gives forked code implicit access to secrets via subsequent repository operations.
|
|
32
|
+
- Unintended repository writes can occur from any step that invokes write-mode operations.
|
|
33
|
+
|
|
34
|
+
The default remains `true` for backward compatibility, but silently increases attack surface
|
|
35
|
+
for every job that does not need post-checkout write access.
|
|
36
|
+
|
|
37
|
+
167 reactions on actions/checkout#485 (open since 2021).
|
|
38
|
+
fix: |
|
|
39
|
+
Set `persist-credentials: false` on all checkout steps that do not require authenticated
|
|
40
|
+
repository operations in later steps. Jobs that do need to write back to the repo should
|
|
41
|
+
use a scoped credential pattern or a dedicated auto-commit action that manages credentials
|
|
42
|
+
explicitly in its own isolated context.
|
|
43
|
+
fix_code:
|
|
44
|
+
- language: yaml
|
|
45
|
+
label: "Recommended: disable persist-credentials for read-only jobs (build, lint, test)"
|
|
46
|
+
code: |
|
|
47
|
+
steps:
|
|
48
|
+
# Token NOT stored in .git/config — safe for read-only jobs
|
|
49
|
+
- uses: actions/checkout@v4
|
|
50
|
+
with:
|
|
51
|
+
persist-credentials: false
|
|
52
|
+
|
|
53
|
+
- name: Build and test
|
|
54
|
+
run: npm ci && npm test
|
|
55
|
+
|
|
56
|
+
- language: yaml
|
|
57
|
+
label: "Scoped: only persist credentials for jobs that explicitly write back to repo"
|
|
58
|
+
code: |
|
|
59
|
+
jobs:
|
|
60
|
+
read-only-analysis:
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
steps:
|
|
63
|
+
- uses: actions/checkout@v4
|
|
64
|
+
with:
|
|
65
|
+
persist-credentials: false # no ambient write access
|
|
66
|
+
|
|
67
|
+
write-back:
|
|
68
|
+
runs-on: ubuntu-latest
|
|
69
|
+
permissions:
|
|
70
|
+
contents: write
|
|
71
|
+
steps:
|
|
72
|
+
# persist-credentials: true (default) only where write is explicitly intended
|
|
73
|
+
- uses: actions/checkout@v4
|
|
74
|
+
|
|
75
|
+
- name: Generate and commit output
|
|
76
|
+
uses: stefanzweifel/auto-commit-action@v5
|
|
77
|
+
with:
|
|
78
|
+
commit_message: "chore: auto-generated output"
|
|
79
|
+
prevention:
|
|
80
|
+
- "Default to persist-credentials: false — only omit (use default true) when authenticated repository operations are explicitly needed in later steps."
|
|
81
|
+
- "Audit jobs that rely on the implicit default and also hold contents:write permission."
|
|
82
|
+
- "In pull_request_target workflows, always set persist-credentials: false when checking out fork refs."
|
|
83
|
+
- "Review third-party tools in the job that invoke the source control client internally."
|
|
84
|
+
docs:
|
|
85
|
+
- url: "https://github.com/actions/checkout/issues/485"
|
|
86
|
+
label: "actions/checkout #485 — Remove persist-credentials or change default (167 reactions)"
|
|
87
|
+
- url: "https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions"
|
|
88
|
+
label: "GitHub Security Hardening for GitHub Actions"
|
|
89
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs"
|
|
90
|
+
label: "GitHub Actions — GITHUB_TOKEN permissions"
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
id: permissions-auth-027
|
|
2
|
+
title: "create-github-app-token token auto-revoked in post step — cannot pass to downstream jobs"
|
|
3
|
+
category: permissions-auth
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- create-github-app-token
|
|
7
|
+
- github-app
|
|
8
|
+
- token-revocation
|
|
9
|
+
- cross-job
|
|
10
|
+
- job-outputs
|
|
11
|
+
- masked-secrets
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: "HttpError.*401.*Bad credentials"
|
|
14
|
+
flags: "i"
|
|
15
|
+
- regex: "Token has been revoked"
|
|
16
|
+
flags: "i"
|
|
17
|
+
- regex: "RequestError.*401"
|
|
18
|
+
flags: "i"
|
|
19
|
+
error_messages:
|
|
20
|
+
- "HttpError: Bad credentials"
|
|
21
|
+
- "Error: 401 Bad credentials"
|
|
22
|
+
- "RequestError: 401 Unauthorized"
|
|
23
|
+
root_cause: |
|
|
24
|
+
actions/create-github-app-token automatically revokes the generated installation token
|
|
25
|
+
in the action's post step (after the job completes). This means a token generated in
|
|
26
|
+
job A and passed as a job output to job B will already be revoked by the time job B
|
|
27
|
+
runs. Additionally, GitHub Actions automatically masks any value that looks like a
|
|
28
|
+
token (matching the ghp_, ghs_, ghu_, github_pat_, etc. prefixes). Masked values
|
|
29
|
+
cannot be passed through job outputs — the runner replaces them with "***" in outputs,
|
|
30
|
+
so the downstream job receives a masked/empty string rather than the actual token value.
|
|
31
|
+
Setting skip-token-revoke: true is necessary but not sufficient: the masking mechanism
|
|
32
|
+
still prevents the token from appearing as a job output.
|
|
33
|
+
fix: |
|
|
34
|
+
Recreate the token in each job that needs it by calling actions/create-github-app-token
|
|
35
|
+
as a step within each dependent job. This is the recommended pattern from the action
|
|
36
|
+
maintainers. Do not attempt to pass the token through job outputs.
|
|
37
|
+
fix_code:
|
|
38
|
+
- language: yaml
|
|
39
|
+
label: "Wrong: token passed through job output (always fails)"
|
|
40
|
+
code: |
|
|
41
|
+
jobs:
|
|
42
|
+
get-token:
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
outputs:
|
|
45
|
+
token: ${{ steps.app-token.outputs.token }} # BROKEN: masked, will be ***
|
|
46
|
+
steps:
|
|
47
|
+
- id: app-token
|
|
48
|
+
uses: actions/create-github-app-token@v1
|
|
49
|
+
with:
|
|
50
|
+
app-id: ${{ vars.APP_ID }}
|
|
51
|
+
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
|
52
|
+
use-token:
|
|
53
|
+
needs: get-token
|
|
54
|
+
runs-on: ubuntu-latest
|
|
55
|
+
steps:
|
|
56
|
+
- run: echo "token is ${{ needs.get-token.outputs.token }}"
|
|
57
|
+
# Always prints "***" — token unusable
|
|
58
|
+
- language: yaml
|
|
59
|
+
label: "Correct: recreate token in each job that needs it"
|
|
60
|
+
code: |
|
|
61
|
+
jobs:
|
|
62
|
+
build:
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
steps:
|
|
65
|
+
- id: app-token
|
|
66
|
+
uses: actions/create-github-app-token@v1
|
|
67
|
+
with:
|
|
68
|
+
app-id: ${{ vars.APP_ID }}
|
|
69
|
+
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
|
70
|
+
- uses: actions/checkout@v4
|
|
71
|
+
with:
|
|
72
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
73
|
+
deploy:
|
|
74
|
+
runs-on: ubuntu-latest
|
|
75
|
+
steps:
|
|
76
|
+
- id: app-token # recreate — do not reuse from build job
|
|
77
|
+
uses: actions/create-github-app-token@v1
|
|
78
|
+
with:
|
|
79
|
+
app-id: ${{ vars.APP_ID }}
|
|
80
|
+
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
|
81
|
+
- run: ./deploy.sh
|
|
82
|
+
env:
|
|
83
|
+
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
|
84
|
+
prevention:
|
|
85
|
+
- "Never pass GitHub App tokens through job outputs — the token is masked and will be empty"
|
|
86
|
+
- "Recreate the token in every job that needs it using a dedicated create-github-app-token step"
|
|
87
|
+
- "Store APP_ID as a repository variable (vars.APP_ID) and private key as a secret"
|
|
88
|
+
- "Consider using a GitHub App with fine-grained permissions to minimize the blast radius of token exposure"
|
|
89
|
+
docs:
|
|
90
|
+
- url: "https://github.com/actions/create-github-app-token/issues/66"
|
|
91
|
+
label: "actions/create-github-app-token#66: output token cannot be used across jobs"
|
|
92
|
+
- url: "https://github.com/actions/create-github-app-token#usage"
|
|
93
|
+
label: "actions/create-github-app-token: Usage documentation"
|
|
94
|
+
- url: "https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-to-access-secrets"
|
|
95
|
+
label: "GitHub Docs: Security hardening — intermediate environment for secrets"
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
id: permissions-auth-025
|
|
2
|
+
title: "GITHUB_TOKEN Missing contents:write — git push Returns 403 Write Access Not Granted"
|
|
3
|
+
category: permissions-auth
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- github-token
|
|
7
|
+
- contents-write
|
|
8
|
+
- git-push
|
|
9
|
+
- 403
|
|
10
|
+
- permissions-block
|
|
11
|
+
- auto-commit
|
|
12
|
+
- write-access
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: "remote: Write access to repository not granted"
|
|
15
|
+
flags: "i"
|
|
16
|
+
- regex: "error: failed to push some refs"
|
|
17
|
+
flags: "i"
|
|
18
|
+
- regex: "refusing to allow.*GitHub Actions.*to create or update workflow"
|
|
19
|
+
flags: "i"
|
|
20
|
+
- regex: "HttpError: Resource not accessible by integration"
|
|
21
|
+
flags: "i"
|
|
22
|
+
error_messages:
|
|
23
|
+
- "remote: Write access to repository not granted."
|
|
24
|
+
- "error: failed to push some refs to 'https://github.com/owner/repo.git'"
|
|
25
|
+
- "fatal: unable to access 'https://github.com/owner/repo.git/': The requested URL returned error: 403"
|
|
26
|
+
- "Resource not accessible by integration"
|
|
27
|
+
root_cause: |
|
|
28
|
+
The GITHUB_TOKEN is scoped by the `permissions:` block on the workflow or job. When any
|
|
29
|
+
`permissions:` block is present, all unspecified permissions are set to `none` (not to their
|
|
30
|
+
defaults). If `contents: write` is not explicitly granted, any `git push`, `git commit`, or
|
|
31
|
+
REST API call that writes to the repository will be rejected with HTTP 403 "Write access to
|
|
32
|
+
repository not granted."
|
|
33
|
+
|
|
34
|
+
Three common situations:
|
|
35
|
+
|
|
36
|
+
1. **Minimal permissions block** — the workflow declares `permissions: read-all` or lists
|
|
37
|
+
specific permissions (e.g., `pull-requests: write`) but omits `contents: write`. Any
|
|
38
|
+
subsequent git push fails with 403.
|
|
39
|
+
|
|
40
|
+
2. **Inherited restrictive org policy** — the organization sets the default token permission
|
|
41
|
+
to "read repository contents" (Settings → Actions → General → Workflow permissions). Without
|
|
42
|
+
an explicit `contents: write` in the workflow, the token cannot push.
|
|
43
|
+
|
|
44
|
+
3. **Fine-grained token in workflow context** — a PAT or GitHub App token is used for checkout
|
|
45
|
+
but the GITHUB_TOKEN (still the effective token for `git push`) lacks write access.
|
|
46
|
+
|
|
47
|
+
This is distinct from `permissions-auth-017` (empty `permissions: {}` block removing
|
|
48
|
+
`contents: read` and breaking checkout). This pattern specifically affects git write operations
|
|
49
|
+
and REST API calls that create or update repository content.
|
|
50
|
+
fix: |
|
|
51
|
+
Add `contents: write` to the permissions block on the job or workflow where the push occurs.
|
|
52
|
+
Grant the narrowest scope needed — prefer job-level `permissions:` over workflow-level to
|
|
53
|
+
limit the blast radius.
|
|
54
|
+
|
|
55
|
+
If the org policy sets the default to "read-only", every workflow that writes to the repo
|
|
56
|
+
must explicitly declare `contents: write`.
|
|
57
|
+
fix_code:
|
|
58
|
+
- language: yaml
|
|
59
|
+
label: "Add contents:write at the job level (preferred — narrowest scope)"
|
|
60
|
+
code: |
|
|
61
|
+
jobs:
|
|
62
|
+
auto-commit:
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
permissions:
|
|
65
|
+
contents: write # ← required for git push / creating commits via API
|
|
66
|
+
steps:
|
|
67
|
+
- uses: actions/checkout@v4
|
|
68
|
+
- name: Bump version and push
|
|
69
|
+
run: |
|
|
70
|
+
git config user.name "github-actions[bot]"
|
|
71
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
72
|
+
npm version patch --no-git-tag-version
|
|
73
|
+
git add package.json
|
|
74
|
+
git commit -m "chore: bump version [skip ci]"
|
|
75
|
+
git push
|
|
76
|
+
- language: yaml
|
|
77
|
+
label: "Org default is read-only — always set explicit contents:write for push workflows"
|
|
78
|
+
code: |
|
|
79
|
+
# When Settings → Actions → General → Workflow permissions = "Read repository contents and packages"
|
|
80
|
+
# EVERY workflow that pushes must declare contents: write:
|
|
81
|
+
|
|
82
|
+
permissions:
|
|
83
|
+
contents: write # required for git push, release creation, branch creation
|
|
84
|
+
pull-requests: write # only if the workflow also comments on PRs
|
|
85
|
+
|
|
86
|
+
jobs:
|
|
87
|
+
release:
|
|
88
|
+
runs-on: ubuntu-latest
|
|
89
|
+
steps:
|
|
90
|
+
- uses: actions/checkout@v4
|
|
91
|
+
- name: Create release
|
|
92
|
+
run: gh release create "${{ github.ref_name }}" --generate-notes
|
|
93
|
+
env:
|
|
94
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
95
|
+
- language: yaml
|
|
96
|
+
label: "Debug: print effective token permissions before failing"
|
|
97
|
+
code: |
|
|
98
|
+
- name: Check token permissions
|
|
99
|
+
run: |
|
|
100
|
+
gh api /repos/${{ github.repository }} --jq '.permissions'
|
|
101
|
+
gh auth status
|
|
102
|
+
env:
|
|
103
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
104
|
+
prevention:
|
|
105
|
+
- "Always add `contents: write` to any job that does `git push`, `git tag`, creates releases, or writes files via the GitHub API."
|
|
106
|
+
- "Set the organization default to 'Read and write' only when necessary; otherwise document that all push workflows must declare `contents: write`."
|
|
107
|
+
- "Use job-level `permissions:` blocks instead of workflow-level to minimize token scope."
|
|
108
|
+
- "Add a permissions comment near the `permissions:` block listing what each grant is needed for, so future maintainers don't accidentally remove it."
|
|
109
|
+
docs:
|
|
110
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token"
|
|
111
|
+
label: "GitHub Docs: Controlling permissions for GITHUB_TOKEN"
|
|
112
|
+
- url: "https://stackoverflow.com/questions/79437803/git-commit-in-github-actions-workflow-failing-write-access-to-repository-not"
|
|
113
|
+
label: "SO#79437803 — git commit failing: Write access to repository not granted, 403"
|
|
114
|
+
- url: "https://stackoverflow.com/questions/79471500/github-actions-authentication-failed-for-pushing-to-repository"
|
|
115
|
+
label: "SO#79471500 — Authentication failed for pushing to repository"
|
|
116
|
+
- url: "https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#setting-the-permissions-of-the-github_token-for-your-repository"
|
|
117
|
+
label: "GitHub Docs: Setting GITHUB_TOKEN default permissions"
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
id: permissions-auth-026
|
|
2
|
+
title: "Org Actions Policy Blocks Workflow — Action Not in Allowlist"
|
|
3
|
+
category: permissions-auth
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- org-policy
|
|
7
|
+
- allowlist
|
|
8
|
+
- action-policy
|
|
9
|
+
- enterprise
|
|
10
|
+
- third-party-actions
|
|
11
|
+
- settings
|
|
12
|
+
- admin
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: "is not allowed to run\\. If you believe this action should be allowed"
|
|
15
|
+
flags: "i"
|
|
16
|
+
- regex: "'[^']+' is not allowed"
|
|
17
|
+
flags: "i"
|
|
18
|
+
- regex: "Action .+ is not allowed by the organization"
|
|
19
|
+
flags: "i"
|
|
20
|
+
- regex: "This action is not allowed"
|
|
21
|
+
flags: "i"
|
|
22
|
+
error_messages:
|
|
23
|
+
- "Error: Action 'actions/setup-node@v4' is not allowed. If you believe this action should be allowed, ask your GitHub org admin to approve it."
|
|
24
|
+
- "'owner/action@v2' is not allowed to run. If you believe this action should be allowed, ask your organization's GitHub Actions admin to allow it."
|
|
25
|
+
- "This action is not allowed because your organization has restricted which actions can be used in workflows."
|
|
26
|
+
root_cause: |
|
|
27
|
+
GitHub organizations and enterprises can restrict which GitHub Actions are permitted
|
|
28
|
+
to run via Settings → Actions → General → "Allow select actions and reusable workflows".
|
|
29
|
+
When this policy is enabled, any workflow referencing an action not on the approved list
|
|
30
|
+
fails immediately at queue time with "is not allowed" — no job steps execute.
|
|
31
|
+
|
|
32
|
+
Three policy modes exist:
|
|
33
|
+
1. **Allow all actions** (default) — no restrictions.
|
|
34
|
+
2. **Allow GitHub-created actions only** — only `actions/*`, `github/*` etc. permitted.
|
|
35
|
+
3. **Allow select actions** — explicit allowlist + optional pattern-matching rules.
|
|
36
|
+
|
|
37
|
+
Common failure scenarios:
|
|
38
|
+
- A developer adds a popular marketplace action (e.g., `slackapi/slack-github-action`)
|
|
39
|
+
that hasn't been pre-approved by the org admin.
|
|
40
|
+
- A new CI requirement introduces a third-party security scanner that isn't allowlisted.
|
|
41
|
+
- An internal action is referenced before the admin adds the pattern to the allowlist.
|
|
42
|
+
- After an org migration, the allowlist from the source org is not reproduced in the
|
|
43
|
+
target org.
|
|
44
|
+
|
|
45
|
+
The error surfaces in the "Set up job" phase, before any workflow steps run, making
|
|
46
|
+
it look like a runner or permissions issue rather than an org policy issue. Developers
|
|
47
|
+
without org admin access cannot fix this themselves.
|
|
48
|
+
fix: |
|
|
49
|
+
An organization admin must update the Actions policy:
|
|
50
|
+
|
|
51
|
+
Settings → Actions → General → "Allow select actions and reusable workflows"
|
|
52
|
+
|
|
53
|
+
Options:
|
|
54
|
+
1. **Allowlist specific actions**: Add the required action pattern (e.g.,
|
|
55
|
+
`slackapi/slack-github-action@*`) to the allowed list.
|
|
56
|
+
2. **Allow GitHub-owned and verified creator actions**: Enables all verified marketplace
|
|
57
|
+
actions without individual approval.
|
|
58
|
+
3. **Allow all actions**: Remove policy restrictions entirely (not recommended for
|
|
59
|
+
security-sensitive orgs).
|
|
60
|
+
|
|
61
|
+
For enterprise-managed repos, the enterprise-level policy may override org-level
|
|
62
|
+
settings — check Settings → Enterprise → Policies → Actions.
|
|
63
|
+
fix_code:
|
|
64
|
+
- language: yaml
|
|
65
|
+
label: "Temporary workaround — pin action SHA to bypass tag-based allowlist patterns"
|
|
66
|
+
code: |
|
|
67
|
+
# If the org allowlist accepts SHA-pinned actions:
|
|
68
|
+
# Replace the version tag with the commit SHA of the same version.
|
|
69
|
+
# (Some org policies allow SHA-pinned actions even if the tag isn't approved.)
|
|
70
|
+
|
|
71
|
+
steps:
|
|
72
|
+
# Instead of: uses: slackapi/slack-github-action@v1.24.0
|
|
73
|
+
- uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.24.0
|
|
74
|
+
with:
|
|
75
|
+
channel-id: 'C12345'
|
|
76
|
+
- language: yaml
|
|
77
|
+
label: "Use a GitHub-owned alternative when allowlist blocks third-party action"
|
|
78
|
+
code: |
|
|
79
|
+
# Example: replace a third-party notification action with curl + GITHUB_TOKEN
|
|
80
|
+
- name: Post to Slack via webhook (no third-party action needed)
|
|
81
|
+
run: |
|
|
82
|
+
curl -X POST "${{ secrets.SLACK_WEBHOOK_URL }}" \
|
|
83
|
+
-H 'Content-type: application/json' \
|
|
84
|
+
--data '{"text":"Deploy finished: ${{ github.run_url }}"}'
|
|
85
|
+
- language: yaml
|
|
86
|
+
label: "Check which actions are permitted before adding new dependencies"
|
|
87
|
+
code: |
|
|
88
|
+
# There is no API to check allowlist programmatically — use the UI:
|
|
89
|
+
# Settings → Actions → General → "Allowed actions and reusable workflows"
|
|
90
|
+
# Or check via REST API (org admins only):
|
|
91
|
+
# GET /orgs/{org}/actions/permissions/selected-actions
|
|
92
|
+
prevention:
|
|
93
|
+
- "Document the org's action allowlist policy in your CONTRIBUTING.md or developer onboarding guide so developers know to request approval before adding new actions."
|
|
94
|
+
- "Use Dependabot for GitHub Actions updates — approved actions stay approved when bumping minor/patch versions if the org uses wildcard patterns (e.g., `slackapi/slack-github-action@*`)."
|
|
95
|
+
- "Prefer GitHub-owned actions (`actions/*`, `github/*`) and verified creator actions to minimize allowlist friction."
|
|
96
|
+
- "Create an internal Slack/Teams channel or GitHub Discussion where developers can request new action approvals from org admins."
|
|
97
|
+
- "Use the GitHub REST API (`GET /orgs/{org}/actions/permissions/selected-actions`) to audit and document the current allowlist for new-member onboarding."
|
|
98
|
+
docs:
|
|
99
|
+
- url: "https://docs.github.com/en/organizations/managing-organization-settings/disabling-or-limiting-github-actions-for-your-organization"
|
|
100
|
+
label: "GitHub Docs: Disabling or limiting GitHub Actions for your organization"
|
|
101
|
+
- url: "https://docs.github.com/en/rest/actions/permissions"
|
|
102
|
+
label: "GitHub REST API: Actions Permissions"
|
|
103
|
+
- url: "https://github.blog/changelog/2026-02-05-github-actions-early-february-2026-updates/"
|
|
104
|
+
label: "GitHub Changelog: Actions early February 2026 updates (action allowlisting)"
|
|
105
|
+
- url: "https://docs.github.com/en/enterprise-cloud@latest/admin/policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-github-actions-in-your-enterprise"
|
|
106
|
+
label: "GitHub Docs: Enforcing GitHub Actions policies in your enterprise"
|