@htekdev/actions-debugger 1.0.0

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 (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +108 -0
  3. package/dist/db/loader.d.ts +12 -0
  4. package/dist/db/loader.d.ts.map +1 -0
  5. package/dist/db/loader.js +76 -0
  6. package/dist/db/loader.js.map +1 -0
  7. package/dist/db/search.d.ts +19 -0
  8. package/dist/db/search.d.ts.map +1 -0
  9. package/dist/db/search.js +123 -0
  10. package/dist/db/search.js.map +1 -0
  11. package/dist/db/types.d.ts +61 -0
  12. package/dist/db/types.d.ts.map +1 -0
  13. package/dist/db/types.js +5 -0
  14. package/dist/db/types.js.map +1 -0
  15. package/dist/index.d.ts +20 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +44 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/server.d.ts +10 -0
  20. package/dist/server.d.ts.map +1 -0
  21. package/dist/server.js +164 -0
  22. package/dist/server.js.map +1 -0
  23. package/dist/tools/diagnose-workflow.d.ts +13 -0
  24. package/dist/tools/diagnose-workflow.d.ts.map +1 -0
  25. package/dist/tools/diagnose-workflow.js +53 -0
  26. package/dist/tools/diagnose-workflow.js.map +1 -0
  27. package/dist/tools/list-categories.d.ts +13 -0
  28. package/dist/tools/list-categories.d.ts.map +1 -0
  29. package/dist/tools/list-categories.js +51 -0
  30. package/dist/tools/list-categories.js.map +1 -0
  31. package/dist/tools/lookup-error.d.ts +18 -0
  32. package/dist/tools/lookup-error.d.ts.map +1 -0
  33. package/dist/tools/lookup-error.js +67 -0
  34. package/dist/tools/lookup-error.js.map +1 -0
  35. package/dist/tools/search-errors.d.ts +17 -0
  36. package/dist/tools/search-errors.d.ts.map +1 -0
  37. package/dist/tools/search-errors.js +33 -0
  38. package/dist/tools/search-errors.js.map +1 -0
  39. package/dist/tools/suggest-fix.d.ts +13 -0
  40. package/dist/tools/suggest-fix.d.ts.map +1 -0
  41. package/dist/tools/suggest-fix.js +62 -0
  42. package/dist/tools/suggest-fix.js.map +1 -0
  43. package/dist/utils/pattern-matcher.d.ts +15 -0
  44. package/dist/utils/pattern-matcher.d.ts.map +1 -0
  45. package/dist/utils/pattern-matcher.js +50 -0
  46. package/dist/utils/pattern-matcher.js.map +1 -0
  47. package/dist/utils/yaml-parser.d.ts +10 -0
  48. package/dist/utils/yaml-parser.d.ts.map +1 -0
  49. package/dist/utils/yaml-parser.js +142 -0
  50. package/dist/utils/yaml-parser.js.map +1 -0
  51. package/errors/_schema.json +89 -0
  52. package/errors/caching-artifacts/cache-miss.yml +56 -0
  53. package/errors/caching-artifacts/upload-artifact-v4-breaking.yml +67 -0
  54. package/errors/concurrency-timing/jobs-cancelled-unexpectedly.yml +60 -0
  55. package/errors/known-unsolved/no-step-retry.yml +53 -0
  56. package/errors/permissions-auth/github-token-403.yml +64 -0
  57. package/errors/permissions-auth/oidc-aws-failure.yml +85 -0
  58. package/errors/runner-environment/disk-space.yml +57 -0
  59. package/errors/runner-environment/node-runtime-deprecation.yml +56 -0
  60. package/errors/silent-failures/github-token-no-trigger.yml +57 -0
  61. package/errors/silent-failures/scheduled-workflow-disabled.yml +59 -0
  62. package/errors/triggers/cron-schedule-late.yml +59 -0
  63. package/errors/triggers/workflow-not-triggering.yml +60 -0
  64. package/errors/yaml-syntax/if-always-true.yml +52 -0
  65. package/errors/yaml-syntax/secrets-in-if.yml +55 -0
  66. package/errors/yaml-syntax/unexpected-yaml-key.yml +69 -0
  67. package/package.json +67 -0
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Workflow YAML analysis utilities.
3
+ * Parses GitHub Actions workflow YAML and checks for common mistakes.
4
+ */
5
+ import type { DiagnosticFinding } from "../db/types.js";
6
+ /**
7
+ * Analyze a workflow YAML string for common issues.
8
+ */
9
+ export declare function analyzeWorkflow(workflowYaml: string): DiagnosticFinding[];
10
+ //# sourceMappingURL=yaml-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yaml-parser.d.ts","sourceRoot":"","sources":["../../src/utils/yaml-parser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AA4BxD;;GAEG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAiJzE"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Workflow YAML analysis utilities.
3
+ * Parses GitHub Actions workflow YAML and checks for common mistakes.
4
+ */
5
+ import yaml from "js-yaml";
6
+ /**
7
+ * Analyze a workflow YAML string for common issues.
8
+ */
9
+ export function analyzeWorkflow(workflowYaml) {
10
+ const findings = [];
11
+ // Check for tab characters (before parsing — YAML rejects tabs)
12
+ if (workflowYaml.includes("\t")) {
13
+ findings.push({
14
+ severity: "critical",
15
+ message: "Tab characters detected — GitHub Actions requires spaces for indentation.",
16
+ fix: "Replace all tabs with spaces (2-space indentation recommended).",
17
+ fix_code: "# Use .editorconfig:\nindent_style = space\nindent_size = 2",
18
+ });
19
+ }
20
+ let workflow;
21
+ try {
22
+ workflow = yaml.load(workflowYaml);
23
+ }
24
+ catch (err) {
25
+ findings.push({
26
+ severity: "critical",
27
+ message: `YAML parse error: ${err.message}`,
28
+ fix: "Fix the YAML syntax error before proceeding.",
29
+ });
30
+ return findings;
31
+ }
32
+ if (!workflow || typeof workflow !== "object") {
33
+ findings.push({
34
+ severity: "critical",
35
+ message: "Workflow is empty or not a valid YAML object.",
36
+ fix: "Ensure the file contains a valid GitHub Actions workflow.",
37
+ });
38
+ return findings;
39
+ }
40
+ // Check jobs
41
+ if (!workflow.jobs || Object.keys(workflow.jobs).length === 0) {
42
+ findings.push({
43
+ severity: "critical",
44
+ message: "No jobs defined in workflow.",
45
+ fix: "Add at least one job under the `jobs:` key.",
46
+ });
47
+ return findings;
48
+ }
49
+ const hasTopLevelPermissions = !!workflow.permissions;
50
+ for (const [jobName, job] of Object.entries(workflow.jobs)) {
51
+ // Missing runs-on
52
+ if (!job["runs-on"]) {
53
+ findings.push({
54
+ severity: "critical",
55
+ message: `Job '${jobName}' is missing 'runs-on'.`,
56
+ fix: "Add runs-on: ubuntu-latest (or another runner label).",
57
+ fix_code: `jobs:\n ${jobName}:\n runs-on: ubuntu-latest`,
58
+ });
59
+ }
60
+ // Missing permissions
61
+ if (!hasTopLevelPermissions && !job.permissions) {
62
+ findings.push({
63
+ severity: "high",
64
+ message: `Job '${jobName}' has no 'permissions:' block — defaults are read-only since Feb 2023.`,
65
+ fix: "Add explicit permissions for the GITHUB_TOKEN.",
66
+ fix_code: `permissions:\n contents: read`,
67
+ });
68
+ }
69
+ // Missing timeout
70
+ if (!job["timeout-minutes"]) {
71
+ findings.push({
72
+ severity: "medium",
73
+ message: `Job '${jobName}' has no 'timeout-minutes' — default is 6 hours.`,
74
+ fix: "Add timeout-minutes to prevent runaway jobs.",
75
+ fix_code: `jobs:\n ${jobName}:\n timeout-minutes: 30`,
76
+ });
77
+ }
78
+ // Check steps
79
+ for (const step of job.steps ?? []) {
80
+ // Deprecated set-output
81
+ if (step.run?.includes("::set-output")) {
82
+ findings.push({
83
+ severity: "high",
84
+ message: `Step '${step.name ?? "unnamed"}' uses deprecated set-output command.`,
85
+ fix: "Use $GITHUB_OUTPUT instead.",
86
+ fix_code: 'echo "key=value" >> $GITHUB_OUTPUT',
87
+ relatedError: "runner-environment-005",
88
+ });
89
+ }
90
+ // Deprecated set-env
91
+ if (step.run?.includes("::set-env")) {
92
+ findings.push({
93
+ severity: "high",
94
+ message: `Step '${step.name ?? "unnamed"}' uses deprecated set-env command.`,
95
+ fix: "Use $GITHUB_ENV instead.",
96
+ fix_code: 'echo "KEY=value" >> $GITHUB_ENV',
97
+ });
98
+ }
99
+ // Deprecated action versions
100
+ if (step.uses) {
101
+ // Node 16 actions
102
+ if (step.uses.match(/actions\/upload-artifact@v3/)) {
103
+ findings.push({
104
+ severity: "high",
105
+ message: `Step uses actions/upload-artifact@v3 — v4 is current and uses a different backend.`,
106
+ fix: "Upgrade to actions/upload-artifact@v4. Note: v3 and v4 artifacts are incompatible.",
107
+ relatedError: "caching-artifacts-004",
108
+ });
109
+ }
110
+ if (step.uses.match(/actions\/download-artifact@v3/)) {
111
+ findings.push({
112
+ severity: "high",
113
+ message: `Step uses actions/download-artifact@v3 — v4 is current.`,
114
+ fix: "Upgrade to actions/download-artifact@v4. Ensure upload and download versions match.",
115
+ });
116
+ }
117
+ }
118
+ // if: with pipe scalar
119
+ if (step.if && typeof step.if === "string") {
120
+ if (step.if.trim().startsWith("|\n") || step.if.trim().startsWith("|")) {
121
+ findings.push({
122
+ severity: "medium",
123
+ message: `Step '${step.name ?? "unnamed"}' if: condition uses pipe scalar — will always be true.`,
124
+ fix: "Remove the pipe character. Write the condition on a single line.",
125
+ relatedError: "yaml-syntax-007",
126
+ });
127
+ }
128
+ // Secrets in if conditions
129
+ if (step.if.includes("secrets.")) {
130
+ findings.push({
131
+ severity: "medium",
132
+ message: `Step '${step.name ?? "unnamed"}' uses secrets.* in if: condition — secrets context is not available in if:.`,
133
+ fix: "Pass the secret to an env var first, then check the env var in the if: condition.",
134
+ relatedError: "yaml-syntax-005",
135
+ });
136
+ }
137
+ }
138
+ }
139
+ }
140
+ return findings;
141
+ }
142
+ //# sourceMappingURL=yaml-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yaml-parser.js","sourceRoot":"","sources":["../../src/utils/yaml-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "Actions Debugger Error Entry",
4
+ "description": "Schema for GitHub Actions error database entries",
5
+ "type": "object",
6
+ "required": ["id", "title", "category", "severity", "patterns", "root_cause", "fix"],
7
+ "properties": {
8
+ "id": {
9
+ "type": "string",
10
+ "pattern": "^[a-z-]+-\\d{3}$",
11
+ "description": "Unique ID: {category}-{number}"
12
+ },
13
+ "title": {
14
+ "type": "string",
15
+ "description": "Human-readable error title"
16
+ },
17
+ "category": {
18
+ "type": "string",
19
+ "enum": [
20
+ "yaml-syntax",
21
+ "silent-failures",
22
+ "runner-environment",
23
+ "permissions-auth",
24
+ "caching-artifacts",
25
+ "triggers",
26
+ "concurrency-timing",
27
+ "known-unsolved"
28
+ ]
29
+ },
30
+ "severity": {
31
+ "type": "string",
32
+ "enum": ["error", "warning", "silent-failure", "limitation"]
33
+ },
34
+ "tags": {
35
+ "type": "array",
36
+ "items": { "type": "string" }
37
+ },
38
+ "patterns": {
39
+ "type": "array",
40
+ "items": {
41
+ "type": "object",
42
+ "required": ["regex"],
43
+ "properties": {
44
+ "regex": { "type": "string" },
45
+ "flags": { "type": "string", "default": "i" }
46
+ }
47
+ }
48
+ },
49
+ "error_messages": {
50
+ "type": "array",
51
+ "items": { "type": "string" },
52
+ "description": "Exact error message strings for full-text search"
53
+ },
54
+ "root_cause": { "type": "string" },
55
+ "fix": { "type": "string" },
56
+ "fix_code": {
57
+ "type": "array",
58
+ "items": {
59
+ "type": "object",
60
+ "properties": {
61
+ "language": { "type": "string" },
62
+ "label": { "type": "string" },
63
+ "code": { "type": "string" }
64
+ }
65
+ }
66
+ },
67
+ "prevention": {
68
+ "type": "array",
69
+ "items": { "type": "string" }
70
+ },
71
+ "docs": {
72
+ "type": "array",
73
+ "items": {
74
+ "type": "object",
75
+ "properties": {
76
+ "url": { "type": "string", "format": "uri" },
77
+ "label": { "type": "string" }
78
+ }
79
+ }
80
+ },
81
+ "source": {
82
+ "type": "object",
83
+ "properties": {
84
+ "article": { "type": "string", "format": "uri" },
85
+ "section": { "type": "string" }
86
+ }
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,56 @@
1
+ id: caching-artifacts-001
2
+ title: "Cache Miss Despite Recent Save"
3
+ category: caching-artifacts
4
+ severity: warning
5
+ tags:
6
+ - cache
7
+ - artifacts
8
+ - restore-keys
9
+ - branch-scope
10
+ - performance
11
+ patterns:
12
+ - regex: "Cache not found for input keys: .*"
13
+ flags: "i"
14
+ - regex: "Failed to restore: .*"
15
+ flags: "i"
16
+ - regex: "Received 429 response while trying to reserve cache"
17
+ flags: "i"
18
+ error_messages:
19
+ - "Cache not found for input keys"
20
+ - "Received 429 response while trying to reserve cache"
21
+ root_cause: |
22
+ GitHub Actions caches are scoped by key, version, and branch. A cache saved on one branch
23
+ is not always visible from another branch, and a small key mismatch can force a full miss.
24
+ High-volume repositories can also hit cache service throttling, which makes cache restore
25
+ or save behavior look flaky.
26
+
27
+ This is especially confusing when a previous run clearly saved a cache but the next run
28
+ still reports a miss.
29
+ fix: |
30
+ Design cache keys intentionally, add `restore-keys` for partial matches, and understand the
31
+ branch visibility rules. Prime important caches on the default branch and avoid creating an
32
+ overly specific key for data that should be shared more broadly.
33
+ fix_code:
34
+ - language: yaml
35
+ label: "Use restore keys and stable cache key prefixes"
36
+ code: |
37
+ - uses: actions/cache@v4
38
+ with:
39
+ path: |
40
+ ~/.npm
41
+ node_modules
42
+ key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
43
+ restore-keys: |
44
+ ${{ runner.os }}-npm-
45
+ prevention:
46
+ - "Keep cache keys stable enough to be reusable, but specific enough to avoid stale restores."
47
+ - "Use `restore-keys` for partial fallback instead of a single exact key."
48
+ - "Prime caches on the default branch for the widest reuse."
49
+ docs:
50
+ - url: "https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows"
51
+ label: "Caching dependencies to speed up workflows"
52
+ - url: "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions"
53
+ label: "Workflow syntax for GitHub Actions"
54
+ source:
55
+ article: "https://htek.dev/articles/github-actions-debugging-guide"
56
+ section: "Cache misses despite recent saves"
@@ -0,0 +1,67 @@
1
+ id: caching-artifacts-004
2
+ title: "upload-artifact v3 → v4 Breaking Changes"
3
+ category: caching-artifacts
4
+ severity: error
5
+ tags:
6
+ - artifacts
7
+ - upload-artifact
8
+ - download-artifact
9
+ - v4
10
+ - compatibility
11
+ patterns:
12
+ - regex: "Artifact not found for name: .*"
13
+ flags: "i"
14
+ - regex: "Unable to find any artifacts for the associated workflow"
15
+ flags: "i"
16
+ - regex: "The requested artifact was not found"
17
+ flags: "i"
18
+ error_messages:
19
+ - "Artifact not found for name: build-output"
20
+ - "Unable to find any artifacts for the associated workflow"
21
+ - "The requested artifact was not found"
22
+ root_cause: |
23
+ The v4 artifact actions use a different backend and behavior than v3. Mixing
24
+ `actions/upload-artifact@v3` with `actions/download-artifact@v4` can produce confusing
25
+ artifact-not-found failures even when the earlier upload step seemed successful.
26
+
27
+ The safest rule is to keep upload and download artifact actions on the same major version,
28
+ and preferably migrate both sides to v4 together.
29
+ fix: |
30
+ Upgrade both upload and download steps to v4 in the same workflow or workflow chain.
31
+ Re-test artifact names exactly as written, because name mismatches compound the version
32
+ mismatch problem.
33
+ fix_code:
34
+ - language: yaml
35
+ label: "Use matching artifact action versions"
36
+ code: |
37
+ jobs:
38
+ build:
39
+ runs-on: ubuntu-latest
40
+ steps:
41
+ - uses: actions/checkout@v4
42
+ - run: npm run build
43
+ - uses: actions/upload-artifact@v4
44
+ with:
45
+ name: build-output
46
+ path: dist/
47
+
48
+ consume:
49
+ runs-on: ubuntu-latest
50
+ needs: build
51
+ steps:
52
+ - uses: actions/download-artifact@v4
53
+ with:
54
+ name: build-output
55
+ path: dist/
56
+ prevention:
57
+ - "Upgrade upload and download artifact actions together, not one side at a time."
58
+ - "Keep artifact names consistent and explicit across jobs."
59
+ - "Retest cross-workflow artifact usage after action major-version upgrades."
60
+ docs:
61
+ - url: "https://docs.github.com/en/actions/using-workflows/storing-workflow-data-as-artifacts"
62
+ label: "Store and share data with workflow artifacts"
63
+ - url: "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions"
64
+ label: "Workflow syntax for GitHub Actions"
65
+ source:
66
+ article: "https://htek.dev/articles/github-actions-debugging-guide"
67
+ section: "Artifact v4 breaking changes"
@@ -0,0 +1,60 @@
1
+ id: concurrency-timing-001
2
+ title: "Jobs Cancelled Unexpectedly"
3
+ category: concurrency-timing
4
+ severity: warning
5
+ tags:
6
+ - concurrency
7
+ - cancellation
8
+ - matrix
9
+ - timing
10
+ - branch-isolation
11
+ patterns:
12
+ - regex: "Canceling since a higher priority waiting request for '.+' exists"
13
+ flags: "i"
14
+ - regex: "The workflow run was canceled because another workflow run with the same concurrency group was queued"
15
+ flags: "i"
16
+ - regex: "Operation was canceled\\."
17
+ flags: "i"
18
+ error_messages:
19
+ - "Canceling since a higher priority waiting request for 'deploy' exists"
20
+ - "Operation was canceled."
21
+ root_cause: |
22
+ Concurrency groups are global to the repository unless you scope them yourself. If every
23
+ branch uses the same group name, a push on one branch can cancel a run on a completely
24
+ different branch. Matrix jobs can make this harder to spot because only some legs appear to
25
+ vanish, even though the concurrency rule is what canceled them.
26
+
27
+ The workflow is behaving exactly as configured, but the group name is too broad.
28
+ fix: |
29
+ Include branch or ref information in the concurrency group so only related runs cancel one
30
+ another. Keep `cancel-in-progress: true` only when you truly want a new run to replace the
31
+ older run for the same ref.
32
+ fix_code:
33
+ - language: yaml
34
+ label: "Scope concurrency groups by workflow and ref"
35
+ code: |
36
+ concurrency:
37
+ group: ${{ github.workflow }}-${{ github.ref }}
38
+ cancel-in-progress: true
39
+
40
+ jobs:
41
+ test:
42
+ runs-on: ubuntu-latest
43
+ strategy:
44
+ matrix:
45
+ node: [18, 20]
46
+ steps:
47
+ - uses: actions/checkout@v4
48
+ - run: npm test
49
+ prevention:
50
+ - "Never use a bare group like `deploy` or `ci` unless cross-branch cancellation is intentional."
51
+ - "Include `${{ github.ref }}` or `${{ github.head_ref || github.ref }}` in concurrency groups."
52
+ - "Review concurrency settings any time runs are mysteriously disappearing."
53
+ docs:
54
+ - url: "https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/control-workflow-concurrency"
55
+ label: "Control the concurrency of workflows and jobs"
56
+ - url: "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions"
57
+ label: "Workflow syntax for GitHub Actions"
58
+ source:
59
+ article: "https://htek.dev/articles/github-actions-debugging-guide"
60
+ section: "Unexpected cancellations from concurrency"
@@ -0,0 +1,53 @@
1
+ id: known-unsolved-002
2
+ title: "No Step-Level Retry"
3
+ category: known-unsolved
4
+ severity: limitation
5
+ tags:
6
+ - retry
7
+ - steps
8
+ - limitation
9
+ - flakiness
10
+ - resilience
11
+ patterns:
12
+ - regex: "Process completed with exit code [0-9]+"
13
+ flags: "i"
14
+ - regex: 'curl: \(28\) Operation timed out'
15
+ flags: "i"
16
+ - regex: "npm ERR! network"
17
+ flags: "i"
18
+ error_messages:
19
+ - "Process completed with exit code 1"
20
+ - "curl: (28) Operation timed out"
21
+ root_cause: |
22
+ GitHub Actions can rerun jobs and whole workflows, but it does not provide native retry
23
+ semantics for a single arbitrary step. That means flaky network calls, package registry
24
+ hiccups, and transient shell commands fail the step immediately unless you build a retry
25
+ wrapper yourself.
26
+
27
+ This is a platform limitation rather than a YAML mistake.
28
+ fix: |
29
+ Wrap the flaky command in a retry helper or use a marketplace action such as
30
+ `nick-fields/retry` when retry semantics are needed for one step only.
31
+ fix_code:
32
+ - language: yaml
33
+ label: "Retry a flaky step with nick-fields/retry"
34
+ code: |
35
+ - name: Retry npm install
36
+ uses: nick-fields/retry@v3
37
+ with:
38
+ timeout_minutes: 15
39
+ max_attempts: 3
40
+ retry_wait_seconds: 20
41
+ command: npm ci
42
+ prevention:
43
+ - "Assume external network calls are flaky and wrap them in retries if they are business-critical."
44
+ - "Prefer idempotent commands for steps that may need retry wrappers."
45
+ - "Document step-level retry strategy because GitHub Actions does not provide it natively."
46
+ docs:
47
+ - url: "https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-workflow-runs/re-running-workflows-and-jobs"
48
+ label: "Re-running workflows and jobs"
49
+ - url: "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions"
50
+ label: "Workflow syntax for GitHub Actions"
51
+ source:
52
+ article: "https://htek.dev/articles/github-actions-debugging-guide"
53
+ section: "Platform limitations: no step-level retry"
@@ -0,0 +1,64 @@
1
+ id: permissions-auth-001
2
+ title: "GITHUB_TOKEN Permission Denied (403)"
3
+ category: permissions-auth
4
+ severity: error
5
+ tags:
6
+ - github-token
7
+ - permissions
8
+ - 403
9
+ - auth
10
+ - push
11
+ patterns:
12
+ - regex: "remote: Permission to .+\\.git denied to github-actions\\[bot\\]"
13
+ flags: "i"
14
+ - regex: "fatal: unable to access 'https://github\\.com/.+': The requested URL returned error: 403"
15
+ flags: "i"
16
+ - regex: "Resource not accessible by integration"
17
+ flags: "i"
18
+ error_messages:
19
+ - "remote: Permission to org/repo.git denied to github-actions[bot]."
20
+ - "fatal: unable to access 'https://github.com/org/repo.git/': The requested URL returned error: 403"
21
+ - "Resource not accessible by integration"
22
+ root_cause: |
23
+ Since February 2023, newly created repositories default `GITHUB_TOKEN` to read-only
24
+ permissions in many cases. A workflow that tries to push commits, create releases, or
25
+ modify pull requests without an explicit `permissions:` block can suddenly fail with 403
26
+ or integration access errors.
27
+
28
+ The token exists, but it does not have the scopes the job assumed it had.
29
+ fix: |
30
+ Add the minimum required `permissions:` block at the workflow or job level. For pushes,
31
+ tags, or release creation, that usually means `contents: write`. For pull request comments
32
+ or checks, grant the specific write permission those APIs require.
33
+ fix_code:
34
+ - language: yaml
35
+ label: "Grant explicit write permissions to GITHUB_TOKEN"
36
+ code: |
37
+ name: Release
38
+
39
+ on:
40
+ push:
41
+ branches:
42
+ - main
43
+
44
+ permissions:
45
+ contents: write
46
+
47
+ jobs:
48
+ release:
49
+ runs-on: ubuntu-latest
50
+ steps:
51
+ - uses: actions/checkout@v4
52
+ - run: git push origin HEAD:main
53
+ prevention:
54
+ - "Assume `GITHUB_TOKEN` is read-only unless you explicitly grant the needed permission."
55
+ - "Set least-privilege `permissions:` blocks on every workflow instead of relying on defaults."
56
+ - "Match API usage to the smallest write scope required."
57
+ docs:
58
+ - url: "https://docs.github.com/en/actions/security-guides/automatic-token-authentication"
59
+ label: "Automatic token authentication"
60
+ - url: "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions"
61
+ label: "permissions"
62
+ source:
63
+ article: "https://htek.dev/articles/github-actions-debugging-guide"
64
+ section: "GITHUB_TOKEN 403 and read-only defaults"
@@ -0,0 +1,85 @@
1
+ id: permissions-auth-002
2
+ title: "OIDC Federation Failures with AWS"
3
+ category: permissions-auth
4
+ severity: error
5
+ tags:
6
+ - oidc
7
+ - aws
8
+ - sts
9
+ - iam
10
+ - federation
11
+ patterns:
12
+ - regex: "Not authorized to perform sts:AssumeRoleWithWebIdentity"
13
+ flags: "i"
14
+ - regex: "InvalidIdentityToken"
15
+ flags: "i"
16
+ - regex: "No OpenIDConnect provider found in your account"
17
+ flags: "i"
18
+ - regex: "audience.*sts\\.amazonaws\\.com"
19
+ flags: "i"
20
+ error_messages:
21
+ - "Not authorized to perform sts:AssumeRoleWithWebIdentity"
22
+ - "InvalidIdentityToken"
23
+ - "No OpenIDConnect provider found in your account"
24
+ root_cause: |
25
+ GitHub's OIDC token must match the AWS IAM trust policy exactly. Failures usually come
26
+ from one of three mismatches: the workflow is missing `id-token: write`, the IAM role
27
+ trust policy expects the wrong `aud` value, or the `sub` claim does not match the repo,
28
+ branch, environment, or tag that is actually requesting the token.
29
+
30
+ Any one of those mismatches is enough for AWS STS to reject the federation request.
31
+ fix: |
32
+ Grant `id-token: write`, verify the GitHub OIDC provider exists in AWS, and align the IAM
33
+ trust policy's `aud` and `sub` conditions with the workflow that is assuming the role.
34
+ fix_code:
35
+ - language: yaml
36
+ label: "Grant OIDC permission in the workflow"
37
+ code: |
38
+ permissions:
39
+ id-token: write
40
+ contents: read
41
+
42
+ jobs:
43
+ deploy:
44
+ runs-on: ubuntu-latest
45
+ steps:
46
+ - uses: actions/checkout@v4
47
+ - uses: aws-actions/configure-aws-credentials@v4
48
+ with:
49
+ role-to-assume: arn:aws:iam::123456789012:role/github-actions-deploy
50
+ aws-region: us-east-1
51
+ - language: json
52
+ label: "Example AWS trust policy for GitHub OIDC"
53
+ code: |
54
+ {
55
+ "Version": "2012-10-17",
56
+ "Statement": [
57
+ {
58
+ "Effect": "Allow",
59
+ "Principal": {
60
+ "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
61
+ },
62
+ "Action": "sts:AssumeRoleWithWebIdentity",
63
+ "Condition": {
64
+ "StringEquals": {
65
+ "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
66
+ },
67
+ "StringLike": {
68
+ "token.actions.githubusercontent.com:sub": "repo:owner/repo:ref:refs/heads/main"
69
+ }
70
+ }
71
+ }
72
+ ]
73
+ }
74
+ prevention:
75
+ - "Treat the OIDC `aud` and `sub` claims as part of your contract and document them with the role."
76
+ - "Test branch, tag, and environment-specific subjects before rolling OIDC out broadly."
77
+ - "Always include `id-token: write` when using cloud federation from GitHub Actions."
78
+ docs:
79
+ - url: "https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services"
80
+ label: "Configuring OpenID Connect in Amazon Web Services"
81
+ - url: "https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/about-security-hardening-with-openid-connect"
82
+ label: "About security hardening with OpenID Connect"
83
+ source:
84
+ article: "https://htek.dev/articles/github-actions-debugging-guide"
85
+ section: "OIDC federation with AWS"