@htekdev/actions-debugger 1.0.14 → 1.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/db/search.js +3 -1
  2. package/dist/db/search.js.map +1 -1
  3. package/dist/tools/suggest-fix.d.ts.map +1 -1
  4. package/dist/tools/suggest-fix.js +5 -1
  5. package/dist/tools/suggest-fix.js.map +1 -1
  6. package/errors/caching-artifacts/cache-key-too-long.yml +93 -0
  7. package/errors/caching-artifacts/cache-path-not-exist-skipped.yml +152 -0
  8. package/errors/caching-artifacts/cache-save-same-key-html-conflict.yml +109 -0
  9. package/errors/caching-artifacts/docker-buildx-gha-cache-capacity.yml +107 -0
  10. package/errors/caching-artifacts/setup-ruby-bundler-ephemeral-workdir-cache-miss.yml +147 -0
  11. package/errors/caching-artifacts/upload-artifact-v3-retirement-blocked.yml +123 -0
  12. package/errors/caching-artifacts/upload-artifact-v4-large-file-macos-hang.yml +111 -0
  13. package/errors/concurrency-timing/always-cleanup-5min-forced-kill.yml +140 -0
  14. package/errors/concurrency-timing/concurrency-group-env-context-undefined.yml +99 -0
  15. package/errors/concurrency-timing/required-check-pending-path-filter-skip.yml +160 -0
  16. package/errors/concurrency-timing/wait-timer-cancel-in-progress-starvation.yml +125 -0
  17. package/errors/known-unsolved/composite-action-step-timeout-minutes-ignored.yml +146 -0
  18. package/errors/known-unsolved/reusable-workflow-no-composite-action-call.yml +116 -0
  19. package/errors/known-unsolved/schedule-trigger-default-branch-only.yml +113 -0
  20. package/errors/known-unsolved/secrets-not-allowed-in-if-conditions.yml +149 -0
  21. package/errors/known-unsolved/workflow-50-rerun-limit.yml +110 -0
  22. package/errors/permissions-auth/check-run-status-modification-blocked.yml +134 -0
  23. package/errors/permissions-auth/dependabot-pr-secrets-unavailable.yml +133 -0
  24. package/errors/permissions-auth/fine-grained-pat-deployment-write-required.yml +146 -0
  25. package/errors/permissions-auth/github-app-installation-token-new-format.yml +124 -0
  26. package/errors/permissions-auth/github-packages-read-requires-packages-permission.yml +128 -0
  27. package/errors/permissions-auth/oidc-id-token-write-permission-missing.yml +169 -0
  28. package/errors/permissions-auth/permissions-empty-block-removes-contents-read.yml +97 -0
  29. package/errors/permissions-auth/reusable-workflow-permissions-not-inherited.yml +114 -0
  30. package/errors/runner-environment/checkout-windows-ebusy-lock.yml +124 -0
  31. package/errors/runner-environment/deprecated-action-version-auto-rejected.yml +89 -0
  32. package/errors/runner-environment/github-hosted-runner-disk-space-full.yml +85 -0
  33. package/errors/runner-environment/github-path-same-step-not-found.yml +114 -0
  34. package/errors/runner-environment/github-script-v6-octokit-rest-actions-not-function.yml +87 -0
  35. package/errors/runner-environment/macos-13-deprecation-brownout.yml +93 -0
  36. package/errors/runner-environment/macos-15-mono-nuget-removed.yml +151 -0
  37. package/errors/runner-environment/macos-15-xcode-simulator-sdk-policy.yml +141 -0
  38. package/errors/runner-environment/multi-runtime-nov2025-removal.yml +120 -0
  39. package/errors/runner-environment/runner-oom-exit-code-137.yml +117 -0
  40. package/errors/runner-environment/setup-go-go123-telemetry-cache-failure.yml +92 -0
  41. package/errors/runner-environment/setup-java-distribution-required.yml +108 -0
  42. package/errors/runner-environment/ubuntu-2004-retirement-brownout.yml +107 -0
  43. package/errors/runner-environment/windows-latest-d-drive-removed.yml +104 -0
  44. package/errors/runner-environment/windows-vs2026-cuda-host-compiler-unsupported.yml +145 -0
  45. package/errors/silent-failures/event-commits-empty-on-workflow-dispatch.yml +110 -0
  46. package/errors/silent-failures/fetch-tags-depth-one-silent-no-op.yml +77 -0
  47. package/errors/silent-failures/github-env-multiline-value-truncated.yml +127 -0
  48. package/errors/silent-failures/github-sha-pr-merge-commit-not-head.yml +150 -0
  49. package/errors/silent-failures/job-output-masked-as-secret-empty.yml +147 -0
  50. package/errors/silent-failures/upload-artifact-permissions-stripped.yml +98 -0
  51. package/errors/triggers/pull-request-branches-filter-matches-base-not-head.yml +140 -0
  52. package/errors/triggers/push-event-fires-on-branch-delete.yml +129 -0
  53. package/errors/triggers/push-first-commit-before-sha-zeros.yml +160 -0
  54. package/errors/yaml-syntax/continue-on-error-env-context-rejected.yml +130 -0
  55. package/errors/yaml-syntax/fromjson-empty-string-crash.yml +99 -0
  56. package/errors/yaml-syntax/if-bang-negation-yaml-tag.yml +145 -0
  57. package/errors/yaml-syntax/local-action-path-always-top-level.yml +142 -0
  58. package/package.json +1 -1
@@ -0,0 +1,124 @@
1
+ id: permissions-auth-014
2
+ title: "GitHub App Installation Tokens New Stateless Format Breaks Length/Regex Validation"
3
+ category: permissions-auth
4
+ severity: error
5
+ tags:
6
+ - github-app
7
+ - installation-token
8
+ - token-format
9
+ - stateless-token
10
+ - breaking-change
11
+ - auth
12
+ patterns:
13
+ - regex: "invalid.*token.*format|token.*validation.*failed"
14
+ flags: "i"
15
+ - regex: "token.*length.*expected|token.*too long"
16
+ flags: "i"
17
+ - regex: "Bad credentials|401.*installation.token"
18
+ flags: "i"
19
+ - regex: "installation.*token.*truncated|column.*too long.*token"
20
+ flags: "i"
21
+ error_messages:
22
+ - "Bad credentials — installation token rejected by downstream validation"
23
+ - "column 'token' is too long for type character varying(40)"
24
+ - "token validation failed: expected length 40, got 520"
25
+ - "ERROR: value too long for type character(40)"
26
+ root_cause: |
27
+ Starting April 27, 2026, GitHub rolled out a **new stateless format** for GitHub App
28
+ installation tokens. The new tokens are approximately **520 characters** long and use
29
+ a new prefix, compared to the previous format which was a fixed **40-character**
30
+ opaque token.
31
+
32
+ **What changed:**
33
+ - Old format: 40-character token (e.g., `ghs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`)
34
+ - New format: ~520-character JWT-like stateless token with a new prefix scheme
35
+
36
+ **What breaks:**
37
+ 1. **Database columns sized at `CHAR(40)` or `VARCHAR(40)`** — any app that stores
38
+ the token in a database field sized for the old format will fail with a column
39
+ truncation or "value too long" database error.
40
+ 2. **Regex/length validation** — code that validates token format or length (e.g.,
41
+ `len(token) == 40`, or regex `^ghs_[a-f0-9]{36}$`) will reject the new tokens.
42
+ 3. **HTTP header size limits** — some reverse proxies or WAFs with conservative
43
+ request header size limits may reject requests with the longer Authorization header.
44
+ 4. **Logging or masking systems** — tools that detect or mask secrets by pattern may
45
+ not recognize the new format, causing tokens to appear in logs unmasked.
46
+
47
+ Source: GitHub Changelog 2026-04-24 — "Notice about upcoming new format for GitHub
48
+ App installation tokens"
49
+ fix: |
50
+ **Treat installation tokens as opaque strings of variable length.** Do not assume
51
+ a specific length, prefix pattern, or character set.
52
+
53
+ 1. **Database**: Expand token storage columns to `VARCHAR(1024)` or use TEXT type
54
+ to future-proof against further format changes.
55
+ 2. **Validation**: Remove length checks and pattern-based validation on token values.
56
+ Validate by making an authenticated API call (e.g., `GET /app/installations`) —
57
+ if it returns 200, the token is valid.
58
+ 3. **HTTP proxy/WAF**: Increase `LargeClientHeader` or equivalent header size limits
59
+ if your infrastructure sits in front of the GitHub API requests.
60
+ 4. **Secret masking**: Update any custom masking patterns to match the new prefix
61
+ or use `add-mask` in workflows rather than pattern-based masking.
62
+ fix_code:
63
+ - language: yaml
64
+ label: "Do not validate token length — use API to verify instead"
65
+ code: |
66
+ jobs:
67
+ setup:
68
+ runs-on: ubuntu-latest
69
+ permissions:
70
+ id-token: write
71
+ steps:
72
+ - name: Generate GitHub App installation token
73
+ id: app-token
74
+ uses: actions/create-github-app-token@v2
75
+ with:
76
+ app-id: ${{ vars.APP_ID }}
77
+ private-key: ${{ secrets.APP_PRIVATE_KEY }}
78
+
79
+ # ❌ Never validate token by length — new format is ~520 chars
80
+ # - run: |
81
+ # TOKEN="${{ steps.app-token.outputs.token }}"
82
+ # [ ${#TOKEN} -eq 40 ] || exit 1 # WILL FAIL with new format
83
+
84
+ # ✅ Verify by making an authenticated API call
85
+ - name: Verify token works
86
+ env:
87
+ GH_TOKEN: ${{ steps.app-token.outputs.token }}
88
+ run: gh api /app --jq '.name'
89
+ - language: yaml
90
+ label: "Mask the full new-format token in logs with add-mask"
91
+ code: |
92
+ jobs:
93
+ deploy:
94
+ runs-on: ubuntu-latest
95
+ steps:
96
+ - name: Generate token
97
+ id: app-token
98
+ uses: actions/create-github-app-token@v2
99
+ with:
100
+ app-id: ${{ vars.APP_ID }}
101
+ private-key: ${{ secrets.APP_PRIVATE_KEY }}
102
+
103
+ # Explicitly mask the token value so it does not appear in logs
104
+ # (pattern-based masking may not catch the new ~520-char format)
105
+ - name: Mask token
106
+ run: echo "::add-mask::${{ steps.app-token.outputs.token }}"
107
+
108
+ - name: Use token
109
+ env:
110
+ GH_TOKEN: ${{ steps.app-token.outputs.token }}
111
+ run: gh api /repos/${{ github.repository }}/releases
112
+ prevention:
113
+ - "Store GitHub App installation tokens in TEXT or VARCHAR(1024)+ columns — never size to the old 40-character format."
114
+ - "Remove any code that validates token length or matches against a fixed token-format regex."
115
+ - "Use `echo '::add-mask::TOKEN'` explicitly in workflows rather than relying on pattern-based log masking for App tokens."
116
+ - "Subscribe to GitHub Changelog token-format notices — https://github.blog/changelog/ — and test format changes in staging before they reach production."
117
+ - "Use `actions/create-github-app-token` (the official action) to generate tokens rather than rolling your own JWT exchange, so the action absorbs format changes automatically."
118
+ docs:
119
+ - url: "https://github.blog/changelog/2026-04-24-notice-about-upcoming-new-format-for-github-app-installation-tokens"
120
+ label: "GitHub Changelog: Notice about upcoming new format for GitHub App installation tokens"
121
+ - url: "https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/authenticating-as-a-github-app-installation"
122
+ label: "GitHub Docs: Authenticating as a GitHub App installation"
123
+ - url: "https://github.com/actions/create-github-app-token"
124
+ label: "actions/create-github-app-token — official token generation action"
@@ -0,0 +1,128 @@
1
+ id: permissions-auth-011
2
+ title: "GITHUB_TOKEN Cannot Pull Private GitHub Packages Without packages: read Permission"
3
+ category: permissions-auth
4
+ severity: error
5
+ tags:
6
+ - github-packages
7
+ - ghcr
8
+ - container-registry
9
+ - packages-read
10
+ - github-token
11
+ - 401
12
+ - npm-packages
13
+ - docker
14
+ patterns:
15
+ - regex: "401 Unauthorized.*(?:ghcr\\.io|npm\\.pkg\\.github\\.com|maven\\.pkg\\.github\\.com)"
16
+ flags: "i"
17
+ - regex: "(?:ghcr\\.io|npm\\.pkg\\.github\\.com).*401 Unauthorized"
18
+ flags: "i"
19
+ - regex: "Error response from daemon.*(?:unauthorized|denied).*ghcr\\.io"
20
+ flags: "i"
21
+ - regex: "npm ERR!\\s+401\\s+Unauthorized.*npm\\.pkg\\.github\\.com"
22
+ flags: "i"
23
+ - regex: "unauthorized: authentication required"
24
+ flags: "i"
25
+ error_messages:
26
+ - "Error response from daemon: pull access denied for ghcr.io/org/image, repository does not exist or may require 'docker login': denied: denied"
27
+ - "npm ERR! 401 Unauthorized - GET https://npm.pkg.github.com/@org%2fpkg/-/pkg-1.0.0.tgz"
28
+ - "unauthorized: authentication required"
29
+ - "Error: The process '/usr/bin/docker' failed with exit code 1"
30
+ root_cause: |
31
+ When a GitHub Actions workflow pulls from the GitHub Container Registry (ghcr.io) or from
32
+ GitHub Packages registries (npm.pkg.github.com, maven.pkg.github.com), the GITHUB_TOKEN
33
+ must have the `packages: read` permission explicitly granted.
34
+
35
+ The GITHUB_TOKEN's default permissions do NOT include `packages: read` unless:
36
+ 1. The repository's default token permissions (Settings → Actions → General) are set to
37
+ "Read and write" at the org or repository level.
38
+ 2. The workflow or job explicitly declares `permissions: packages: read`.
39
+
40
+ Commonly confused behaviors:
41
+ - A public package on ghcr.io from the same org is readable without auth — but a private
42
+ package or a package from a private repository requires authentication.
43
+ - GITHUB_TOKEN is scoped to the CURRENT repository. Pulling packages published from a
44
+ DIFFERENT repository in the same org may require a PAT even with packages: read set,
45
+ because the token only has read access to packages owned by the current repo.
46
+ - When `permissions:` is set at the workflow level (even just `contents: read`), all
47
+ unmentioned permissions are downgraded to 'none' — this silently removes packages: read
48
+ if it was previously implied by repository defaults.
49
+
50
+ This error is particularly common when:
51
+ - A workflow was working until someone added a top-level permissions: block for another
52
+ purpose (e.g., to set id-token: write for OIDC), silently removing packages: read
53
+ - The organization was migrated from packages-on-repo to ghcr.io
54
+ - Running workflows on forks (secrets unavailable, GITHUB_TOKEN scoped differently)
55
+ fix: |
56
+ Add `packages: read` to the workflow-level or job-level permissions block.
57
+
58
+ For cross-repository package pulls where GITHUB_TOKEN is insufficient, create a
59
+ Classic PAT with `read:packages` scope (or a fine-grained PAT with "Packages: read"
60
+ for the source repo) and store it as a repository secret.
61
+ fix_code:
62
+ - language: yaml
63
+ label: "Grant packages: read to pull from ghcr.io"
64
+ code: |
65
+ jobs:
66
+ build:
67
+ runs-on: ubuntu-latest
68
+ permissions:
69
+ contents: read
70
+ packages: read # ← required for ghcr.io and GitHub Packages
71
+ steps:
72
+ - name: Log in to GitHub Container Registry
73
+ uses: docker/login-action@v3
74
+ with:
75
+ registry: ghcr.io
76
+ username: ${{ github.actor }}
77
+ password: ${{ secrets.GITHUB_TOKEN }}
78
+
79
+ - name: Pull image
80
+ run: docker pull ghcr.io/${{ github.repository_owner }}/my-image:latest
81
+ - language: yaml
82
+ label: "Authenticate npm to GitHub Packages with GITHUB_TOKEN"
83
+ code: |
84
+ jobs:
85
+ install:
86
+ runs-on: ubuntu-latest
87
+ permissions:
88
+ contents: read
89
+ packages: read
90
+ steps:
91
+ - uses: actions/checkout@v4
92
+
93
+ - name: Authenticate npm to GitHub Packages
94
+ run: |
95
+ echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" >> ~/.npmrc
96
+ echo "@myorg:registry=https://npm.pkg.github.com" >> ~/.npmrc
97
+
98
+ - run: npm ci
99
+ - language: yaml
100
+ label: "Cross-repo package pull using PAT (when GITHUB_TOKEN is insufficient)"
101
+ code: |
102
+ jobs:
103
+ build:
104
+ runs-on: ubuntu-latest
105
+ steps:
106
+ - name: Log in to ghcr.io with PAT (cross-repo packages)
107
+ uses: docker/login-action@v3
108
+ with:
109
+ registry: ghcr.io
110
+ username: ${{ github.actor }}
111
+ # PAT with read:packages scope stored as repository secret
112
+ password: ${{ secrets.PACKAGES_READ_PAT }}
113
+
114
+ - run: docker pull ghcr.io/other-org/shared-image:latest
115
+ prevention:
116
+ - "Always declare explicit `permissions:` blocks — adding ANY permission key removes all defaults, so list everything your job needs."
117
+ - "Include `packages: read` whenever a job pulls from ghcr.io, npm.pkg.github.com, or maven.pkg.github.com."
118
+ - "Note that GITHUB_TOKEN is scoped to the current repository; cross-repository package pulls may require a PAT with `read:packages` scope."
119
+ - "When adding `id-token: write` for OIDC, simultaneously audit all other permissions your jobs need to avoid accidentally removing packages: read."
120
+ docs:
121
+ - url: "https://docs.github.com/en/packages/managing-github-packages-using-github-actions-workflows/publishing-and-installing-a-package-with-github-actions"
122
+ label: "GitHub docs — Publishing and installing packages with GitHub Actions"
123
+ - url: "https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#permissions-for-the-github_token"
124
+ label: "GitHub docs — GITHUB_TOKEN permissions reference"
125
+ - url: "https://stackoverflow.com/questions/64124831/github-actions-401-unauthorized-when-installing-a-github-package-with-npm-or-yarn"
126
+ label: "Stack Overflow — 401 unauthorized installing GitHub Package with GITHUB_TOKEN"
127
+ - url: "https://github.com/orgs/community/discussions/162859"
128
+ label: "Community discussion #162859 — 401 bad request installing GitHub Packages"
@@ -0,0 +1,169 @@
1
+ id: permissions-auth-016
2
+ title: "OIDC Authentication Fails — id-token: write Missing from Restricted permissions Block"
3
+ category: permissions-auth
4
+ severity: error
5
+ tags:
6
+ - oidc
7
+ - id-token
8
+ - permissions
9
+ - jwt
10
+ - aws
11
+ - azure
12
+ - gcp
13
+ - workload-identity
14
+ - token-request
15
+ patterns:
16
+ - regex: "id-token.*write|id_token.*write"
17
+ flags: "i"
18
+ - regex: "Error:.*OIDC.*provider|No OIDC provider found|OIDC.*not available"
19
+ flags: "i"
20
+ - regex: "RequestError.*GetIdToken|Unable to get OIDC token|getIDToken.*failed"
21
+ flags: "i"
22
+ - regex: "OIDCError|oidc-client.*failed|could not fetch oidc token"
23
+ flags: "i"
24
+ error_messages:
25
+ - "Error: No OIDC provider found. OIDC tokens are not available for this workflow."
26
+ - "RequestError: Unable to get OIDC token from actions ID token endpoint"
27
+ - "Error: getIDToken() failed: Could not get ID token. Input required and not supplied: audience"
28
+ - "OIDCError: Could not fetch OIDC token"
29
+ - "Error: No permission to get id-token"
30
+ - "failed to get credentials: failed to get OIDC token: failed to get ID token: Unable to get ID token"
31
+ root_cause: |
32
+ GitHub Actions OIDC (OpenID Connect) allows workflows to authenticate with cloud
33
+ providers (AWS, Azure, GCP) using short-lived JWT tokens instead of long-lived secrets.
34
+ To request an OIDC token, the workflow job MUST have `id-token: write` permission.
35
+
36
+ When a workflow or job defines a `permissions:` block, it switches from the **default
37
+ permissive** mode to **explicit restrictive** mode. In restrictive mode, any permission
38
+ NOT listed defaults to `none` — including `id-token`.
39
+
40
+ Common mistakes that silently remove `id-token: write`:
41
+
42
+ 1. **Restricting permissions at workflow level without re-granting at job level:**
43
+ ```yaml
44
+ permissions: # Workflow-level restriction
45
+ contents: read # id-token implicitly becomes 'none'
46
+ ```
47
+
48
+ 2. **Adding `permissions: {}` to lock down a workflow:**
49
+ ```yaml
50
+ permissions: {} # All permissions set to none, including id-token
51
+ ```
52
+
53
+ 3. **Following security advice to restrict GITHUB_TOKEN without accounting for OIDC:**
54
+ Security guides recommend restricting permissions, but if the job uses OIDC,
55
+ `id-token: write` must be explicitly added back.
56
+
57
+ 4. **Inheriting a restricted workflow-level permission in a reusable workflow caller:**
58
+ Callers that set restrictive top-level `permissions:` do not automatically grant
59
+ `id-token: write` to reusable workflow jobs that need OIDC.
60
+
61
+ This is a particularly confusing error because:
62
+ - The error message "No OIDC provider found" sounds like a configuration issue
63
+ with the cloud provider, not a GitHub Actions permissions issue
64
+ - The workflow runs successfully in unrestricted mode (when no `permissions:` block
65
+ exists and defaults apply), so the error only appears after tightening security
66
+ Source: GitHub Docs — security hardening OIDC requirements
67
+ Source: GitHub Community — "No OIDC provider found" recurring discussion
68
+ fix: |
69
+ Add `id-token: write` to the `permissions:` block for any job that uses OIDC
70
+ authentication (actions/configure-aws-credentials, azure/login, etc.).
71
+
72
+ If `permissions:` is defined at the workflow level, you can either:
73
+ - Add `id-token: write` to the workflow-level block (grants it to all jobs), or
74
+ - Override permissions at the job level with `id-token: write` just for the job
75
+ that needs it (more secure — principle of least privilege)
76
+
77
+ Also ensure `contents: read` is present if the job uses `actions/checkout`.
78
+ fix_code:
79
+ - language: yaml
80
+ label: "Fix: add id-token: write to the job permissions block"
81
+ code: |
82
+ jobs:
83
+ deploy:
84
+ runs-on: ubuntu-latest
85
+ permissions:
86
+ id-token: write # ✅ Required for OIDC token request
87
+ contents: read # Required for actions/checkout
88
+ steps:
89
+ - uses: actions/checkout@v4
90
+
91
+ - name: Configure AWS credentials via OIDC
92
+ uses: aws-actions/configure-aws-credentials@v4
93
+ with:
94
+ role-to-assume: arn:aws:iam::123456789012:role/my-github-actions-role
95
+ aws-region: us-east-1
96
+
97
+ - name: Deploy
98
+ run: aws s3 sync dist/ s3://my-bucket
99
+
100
+ - language: yaml
101
+ label: "Workflow with restricted top-level permissions and OIDC job"
102
+ code: |
103
+ name: Deploy
104
+
105
+ on:
106
+ push:
107
+ branches: [main]
108
+
109
+ # Restrict default permissions for the whole workflow
110
+ permissions:
111
+ contents: read
112
+
113
+ jobs:
114
+ build:
115
+ runs-on: ubuntu-latest
116
+ # Inherits workflow-level permissions: contents=read, id-token=none
117
+ steps:
118
+ - uses: actions/checkout@v4
119
+ - run: npm ci && npm run build
120
+ - uses: actions/upload-artifact@v4
121
+ with:
122
+ name: build
123
+ path: dist/
124
+
125
+ deploy:
126
+ runs-on: ubuntu-latest
127
+ needs: build
128
+ # ✅ Override permissions at job level to add id-token: write
129
+ permissions:
130
+ id-token: write
131
+ contents: read
132
+ steps:
133
+ - uses: actions/download-artifact@v4
134
+ with:
135
+ name: build
136
+
137
+ - name: Configure Azure login via OIDC
138
+ uses: azure/login@v2
139
+ with:
140
+ client-id: ${{ vars.AZURE_CLIENT_ID }}
141
+ tenant-id: ${{ vars.AZURE_TENANT_ID }}
142
+ subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}
143
+
144
+ - language: yaml
145
+ label: "Reusable workflow: caller must pass id-token write permission"
146
+ code: |
147
+ # Caller workflow (in the calling repo)
148
+ jobs:
149
+ call-deploy:
150
+ uses: org/shared-workflows/.github/workflows/deploy.yml@main
151
+ permissions:
152
+ id-token: write # ✅ Caller must grant this for the reusable workflow
153
+ contents: read
154
+ with:
155
+ environment: production
156
+
157
+ prevention:
158
+ - "Whenever you add a `permissions:` block, explicitly include `id-token: write` for any job using OIDC."
159
+ - "Audit OIDC-dependent jobs after adding or tightening `permissions:` blocks."
160
+ - "Use job-level permissions instead of workflow-level when only some jobs need OIDC — principle of least privilege."
161
+ - "Document `id-token: write` with an inline comment explaining it is required for OIDC authentication."
162
+ - "For reusable workflows using OIDC: callers must explicitly pass `id-token: write` in their job permissions."
163
+ docs:
164
+ - url: "https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/about-security-hardening-with-openid-connect#adding-permissions-settings"
165
+ label: "GitHub Docs: OIDC — Adding permissions settings (id-token: write)"
166
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token#modifying-the-permissions-for-the-github_token"
167
+ label: "GitHub Docs: Controlling permissions for GITHUB_TOKEN"
168
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token#defining-access-for-the-github_token-scopes"
169
+ label: "GitHub Docs: Defining access for GITHUB_TOKEN scopes"
@@ -0,0 +1,97 @@
1
+ id: permissions-auth-017
2
+ title: "Empty permissions: {} Block Removes contents: read, Breaking Checkout on Private Repos"
3
+ category: permissions-auth
4
+ severity: error
5
+ tags:
6
+ - permissions
7
+ - github-token
8
+ - contents-read
9
+ - checkout
10
+ - private-repo
11
+ - security-hardening
12
+ patterns:
13
+ - regex: "Resource not accessible by integration"
14
+ flags: "i"
15
+ - regex: "403.*Resource not accessible"
16
+ flags: "i"
17
+ - regex: "HttpError.*Resource not accessible by integration"
18
+ flags: "i"
19
+ error_messages:
20
+ - "Error: Resource not accessible by integration"
21
+ - "HttpError: Resource not accessible by integration"
22
+ - "remote: Repository not found.\nError: The process '/usr/bin/git' failed with exit code 128"
23
+ - "Error: fatal: repository 'https://github.com/owner/repo/' not found"
24
+ root_cause: |
25
+ GitHub Actions workflows have a default token permission set controlled by the repository's
26
+ settings. When you add a `permissions:` block to a workflow or job, you are making permissions
27
+ EXPLICIT — any scope not listed is set to `none`, even if it was previously granted by default.
28
+
29
+ An empty `permissions: {}` block (or `permissions:` with no sub-keys) silently removes ALL
30
+ permissions including `contents: read`. This causes `actions/checkout` to fail on private
31
+ repositories because the GITHUB_TOKEN no longer has permission to clone the repository.
32
+
33
+ This is counterintuitive because developers often add `permissions: {}` as a security hardening
34
+ step without realizing it removes the read access needed for basic workflow operations like
35
+ checking out code.
36
+
37
+ The failure appears immediately at the checkout step. On public repositories, checkout may
38
+ succeed (public repos allow unauthenticated read) but any write operations, API calls, or
39
+ steps requiring token scopes will silently receive no permissions.
40
+ fix: |
41
+ Always specify the minimum required permissions explicitly. At minimum, include
42
+ `contents: read` to allow `actions/checkout` to clone the repository. Add other scopes
43
+ only as needed for the workflow's specific operations.
44
+ fix_code:
45
+ - language: yaml
46
+ label: "Minimal permissions: checkout only"
47
+ code: |
48
+ permissions:
49
+ contents: read # required for actions/checkout on private repos
50
+
51
+ jobs:
52
+ build:
53
+ runs-on: ubuntu-latest
54
+ steps:
55
+ - uses: actions/checkout@v4
56
+ - language: yaml
57
+ label: "Typical CI workflow permissions"
58
+ code: |
59
+ permissions:
60
+ contents: read # checkout
61
+ pull-requests: write # comment on PRs
62
+ checks: write # report check status
63
+
64
+ jobs:
65
+ test:
66
+ runs-on: ubuntu-latest
67
+ steps:
68
+ - uses: actions/checkout@v4
69
+ # ...
70
+ - language: yaml
71
+ label: "Read-only lockdown (safest baseline)"
72
+ code: |
73
+ # At workflow level: lock down everything to read-only
74
+ permissions:
75
+ contents: read
76
+ packages: read
77
+
78
+ jobs:
79
+ deploy:
80
+ # Override at job level for the job that needs write access
81
+ permissions:
82
+ contents: read
83
+ deployments: write
84
+ id-token: write # OIDC
85
+ runs-on: ubuntu-latest
86
+ steps:
87
+ - uses: actions/checkout@v4
88
+ prevention:
89
+ - "Never use `permissions: {}` — always list scopes explicitly with their required levels"
90
+ - "Include `contents: read` as the minimum permission in every workflow that uses actions/checkout"
91
+ - "Use job-level permissions overrides to grant elevated scopes only where needed, not at the workflow level"
92
+ - "GitHub's security hardening guide recommends workflow-level read-only + job-level write overrides as the safest pattern"
93
+ docs:
94
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token"
95
+ label: "GitHub Docs — Controlling permissions for GITHUB_TOKEN"
96
+ - url: "https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#using-permissions-for-github_token"
97
+ label: "GitHub Docs — Security hardening: using permissions for GITHUB_TOKEN"
@@ -0,0 +1,114 @@
1
+ id: permissions-auth-012
2
+ title: "Reusable Workflow Permissions Not Inherited from Caller — Must Be Granted Explicitly"
3
+ category: permissions-auth
4
+ severity: error
5
+ tags:
6
+ - reusable-workflow
7
+ - permissions
8
+ - github-token
9
+ - caller
10
+ - contents
11
+ patterns:
12
+ - regex: "is requesting '([^']+)', but is only allowed '([^']+)'"
13
+ flags: "i"
14
+ - regex: "The workflow.*is requesting.*but is only allowed"
15
+ flags: "i"
16
+ - regex: "Resource not accessible by integration"
17
+ flags: "i"
18
+ error_messages:
19
+ - "The workflow is not valid. .github/workflows/caller.yml: Error calling workflow 'org/repo/.github/workflows/reusable.yml@main'. The workflow 'org/repo/.github/workflows/reusable.yml@main' is requesting 'contents: read', but is only allowed 'contents: none'."
20
+ - "Resource not accessible by integration"
21
+ root_cause: |
22
+ When a workflow calls a reusable workflow using `jobs.<job>.uses`, the called workflow
23
+ runs with a GITHUB_TOKEN whose permissions are the INTERSECTION of:
24
+ 1. The permissions declared in the caller workflow (or job)
25
+ 2. The permissions the called reusable workflow needs
26
+
27
+ Reusable workflows do NOT automatically inherit the caller's permissions. If the caller
28
+ workflow declares a restrictive permissions block (or relies on repository-default
29
+ read-all), but the reusable workflow declares or needs broader permissions, the call
30
+ fails at validation time with:
31
+
32
+ "The workflow 'X' is requesting 'contents: read', but is only allowed 'contents: none'."
33
+
34
+ This also manifests at runtime as "Resource not accessible by integration" (HTTP 403)
35
+ when the reusable workflow's steps attempt API calls or git operations that require
36
+ permissions not granted by the caller.
37
+
38
+ Common scenarios:
39
+ - Caller explicitly sets `permissions: {}` (no permissions) for security hardening
40
+ - Caller sets only `id-token: write` for OIDC but reusable workflow needs `contents: read`
41
+ - Repository setting "Read and write permissions" is overridden to "Read repository
42
+ contents and packages permissions" at org level, reducing the default token scope
43
+ - Caller passes `secrets: inherit` but forgets to also pass `permissions:`
44
+
45
+ Source: GitHub Community Discussion #52665
46
+ fix: |
47
+ Explicitly grant the required permission scopes in the **caller** workflow, at either
48
+ the workflow level or the specific job level that uses the reusable workflow.
49
+
50
+ To discover which permissions a reusable workflow needs, check its `on.workflow_call`
51
+ declaration or read its steps to see which GitHub API/resource operations it performs.
52
+
53
+ Follow least privilege: grant only what the reusable workflow actually needs, not
54
+ blanket read-all.
55
+ fix_code:
56
+ - language: yaml
57
+ label: "Broken — caller grants no permissions, reusable workflow needs contents"
58
+ code: |
59
+ # ❌ BROKEN: caller sets permissions: {} — reusable workflow inherits none
60
+ name: Release
61
+ on: push
62
+
63
+ permissions: {} # Locks down all permissions — nothing passes through
64
+
65
+ jobs:
66
+ release:
67
+ uses: my-org/shared-workflows/.github/workflows/release.yml@main
68
+ # Error: release.yml requests 'contents: write' but caller allows 'contents: none'
69
+ - language: yaml
70
+ label: "Fixed — grant required scopes explicitly at the job level"
71
+ code: |
72
+ # ✅ FIXED: grant only what the reusable workflow needs
73
+ name: Release
74
+ on: push
75
+
76
+ permissions: {} # Lock down at workflow level for security
77
+
78
+ jobs:
79
+ release:
80
+ permissions:
81
+ contents: write # Required by the reusable workflow for creating releases
82
+ id-token: write # Required for OIDC if the reusable workflow uses it
83
+ uses: my-org/shared-workflows/.github/workflows/release.yml@main
84
+ - language: yaml
85
+ label: "Fixed — grant permissions at workflow level when multiple jobs use reusable workflows"
86
+ code: |
87
+ # ✅ FIXED: grant at workflow level when multiple jobs need the same scopes
88
+ name: CI
89
+ on: [push, pull_request]
90
+
91
+ permissions:
92
+ contents: read # Needed for checkout in reusable workflows
93
+ packages: write # Needed for reusable workflow that publishes packages
94
+ pull-requests: write # Needed for reusable workflow that adds PR comments
95
+
96
+ jobs:
97
+ build:
98
+ uses: my-org/shared-workflows/.github/workflows/build.yml@main
99
+ publish:
100
+ needs: build
101
+ uses: my-org/shared-workflows/.github/workflows/publish.yml@main
102
+ prevention:
103
+ - "Always read the reusable workflow's steps to know which permissions it needs before calling it."
104
+ - "Test reusable workflow calls from a caller with explicit `permissions: {}` first — failures reveal required scopes."
105
+ - "Document required permissions in the reusable workflow's `on.workflow_call` block as comments."
106
+ - "When adding `permissions:` to a caller, remember that declaring ANY permission sets all others to `none` — enumerate every scope you need."
107
+ - "Use job-level `permissions:` rather than workflow-level to apply least-privilege per job."
108
+ docs:
109
+ - url: "https://docs.github.com/en/actions/sharing-automations/reusing-workflows"
110
+ label: "Reusing workflows — permissions and access"
111
+ - url: "https://github.com/orgs/community/discussions/52665"
112
+ label: "GitHub Community #52665 — reusable workflow permissions"
113
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token"
114
+ label: "Controlling permissions for GITHUB_TOKEN"