@htekdev/actions-debugger 1.0.95 → 1.0.96

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.
@@ -0,0 +1,90 @@
1
+ id: caching-artifacts-053
2
+ title: "download-artifact@v4 finds no artifacts in workflow_run context without run-id"
3
+ category: caching-artifacts
4
+ severity: error
5
+ tags:
6
+ - download-artifact
7
+ - workflow_run
8
+ - run-id
9
+ - cross-workflow
10
+ - artifact
11
+ patterns:
12
+ - regex: 'No artifacts found'
13
+ flags: 'i'
14
+ - regex: 'Unable to find any artifacts for the associated workflow'
15
+ flags: 'i'
16
+ error_messages:
17
+ - "No artifacts found for the associated workflow run"
18
+ - "Unable to find any artifacts for the associated workflow"
19
+ - "Error: Unable to find any artifacts for the associated workflow run"
20
+ root_cause: |
21
+ `actions/download-artifact@v4` defaults to downloading artifacts from the
22
+ CURRENT workflow run (`github.run_id`). In a `workflow_run`-triggered
23
+ workflow, the current run is the downstream (deploy) workflow — which has
24
+ produced no artifacts. The upstream (build) workflow's artifacts belong to
25
+ the triggering run, identified by `github.event.workflow_run.id`.
26
+
27
+ Without setting `run-id: ${{ github.event.workflow_run.id }}`, the download
28
+ step searches the current run's artifacts, finds nothing, and either fails
29
+ with "No artifacts found" or silently exits (depending on `if-no-files-found`
30
+ setting). No artifact was ever associated with the downstream run, so the
31
+ error can be confusing — the artifact clearly exists in the Actions UI under
32
+ the upstream run.
33
+
34
+ This is a distinct issue from the cross-run permissions error (ca-040):
35
+ that occurs when `run-id` IS set but `actions: read` permission is missing.
36
+ This issue occurs when `run-id` is simply not set at all.
37
+ fix: |
38
+ Set `run-id: ${{ github.event.workflow_run.id }}` on the download step to
39
+ target the triggering workflow's run. Also provide `github-token` (required
40
+ for cross-run downloads) and ensure `actions: read` permission is set.
41
+ fix_code:
42
+ - language: yaml
43
+ label: "Correct: set run-id from triggering workflow in workflow_run context"
44
+ code: |
45
+ on:
46
+ workflow_run:
47
+ workflows: ["CI"]
48
+ types: [completed]
49
+
50
+ permissions:
51
+ actions: read
52
+ contents: read
53
+
54
+ jobs:
55
+ deploy:
56
+ if: github.event.workflow_run.conclusion == 'success'
57
+ runs-on: ubuntu-latest
58
+ steps:
59
+ - name: Download build artifacts
60
+ uses: actions/download-artifact@v4
61
+ with:
62
+ name: build-output
63
+ # Required: point to the upstream run, not the current run
64
+ run-id: ${{ github.event.workflow_run.id }}
65
+ github-token: ${{ secrets.GITHUB_TOKEN }}
66
+
67
+ - name: Deploy
68
+ run: echo "Deploying from artifact"
69
+ - language: yaml
70
+ label: "Incorrect: missing run-id causes 'No artifacts found'"
71
+ code: |
72
+ jobs:
73
+ deploy:
74
+ runs-on: ubuntu-latest
75
+ steps:
76
+ - name: Download build artifacts
77
+ uses: actions/download-artifact@v4
78
+ with:
79
+ name: build-output
80
+ # Missing run-id — searches the CURRENT run, which has no artifacts
81
+ prevention:
82
+ - "In any `workflow_run`-triggered workflow, always set `run-id: ${{ github.event.workflow_run.id }}`"
83
+ - "Pair with `github-token: ${{ secrets.GITHUB_TOKEN }}` and `permissions: actions: read`"
84
+ - "Verify artifacts exist under the triggering run via the Actions UI before debugging download steps"
85
+ - "Name artifacts consistently between upload (in CI) and download (in deploy) workflows"
86
+ docs:
87
+ - url: "https://github.com/actions/download-artifact?tab=readme-ov-file#download-artifacts-from-other-workflow-runs-or-repositories"
88
+ label: "actions/download-artifact: Downloading from other workflow runs"
89
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_run"
90
+ label: "GitHub Docs: workflow_run event"
@@ -0,0 +1,70 @@
1
+ id: concurrency-timing-045
2
+ title: "workflow_run-triggered workflows run concurrently — no upstream concurrency linkage"
3
+ category: concurrency-timing
4
+ severity: silent-failure
5
+ tags:
6
+ - workflow_run
7
+ - concurrency
8
+ - deployment
9
+ - build-deploy-pipeline
10
+ - downstream-workflow
11
+ patterns:
12
+ - regex: 'on:\s+workflow_run:'
13
+ flags: 'si'
14
+ error_messages:
15
+ - "Multiple deployments triggered simultaneously for the same branch"
16
+ - "Deploy workflow triggered concurrently"
17
+ root_cause: |
18
+ Workflows triggered via `on: workflow_run:` do not inherit any concurrency
19
+ group from the triggering (upstream) workflow. If multiple upstream runs
20
+ complete in quick succession — for example, two commits pushed rapidly — each
21
+ `completed` event spawns an independent downstream run. All downstream runs
22
+ execute concurrently with no serialization or cancellation, even when the
23
+ upstream workflow had a concurrency group that serialized upstream runs.
24
+
25
+ The downstream workflow runs in the context of the default branch and receives
26
+ the triggering run's metadata via `github.event.workflow_run.*`, but GitHub
27
+ does not propagate any concurrency scope from upstream to downstream.
28
+
29
+ For build-then-deploy pipelines this creates a race condition: two deploy runs
30
+ may begin simultaneously, with whichever finishes last determining the final
31
+ deployed state regardless of commit order.
32
+ fix: |
33
+ Add an explicit `concurrency:` block to the `workflow_run`-triggered workflow,
34
+ keyed on `github.event.workflow_run.head_branch` to scope per branch.
35
+
36
+ Use `cancel-in-progress: true` for idempotent deploys (only the latest commit
37
+ matters) or `cancel-in-progress: false` for non-idempotent operations that
38
+ must complete once queued.
39
+ fix_code:
40
+ - language: yaml
41
+ label: "Add explicit concurrency group to workflow_run-triggered deploy workflow"
42
+ code: |
43
+ on:
44
+ workflow_run:
45
+ workflows: ["CI"]
46
+ types: [completed]
47
+ branches: [main]
48
+
49
+ # Without this block, concurrent CI completions spawn concurrent deploys
50
+ concurrency:
51
+ group: deploy-${{ github.event.workflow_run.head_branch }}
52
+ cancel-in-progress: true
53
+
54
+ jobs:
55
+ deploy:
56
+ if: github.event.workflow_run.conclusion == 'success'
57
+ runs-on: ubuntu-latest
58
+ steps:
59
+ - name: Deploy
60
+ run: echo "Deploying ${{ github.event.workflow_run.head_sha }}"
61
+ prevention:
62
+ - "Always define an explicit `concurrency:` block in `workflow_run`-triggered workflows"
63
+ - "Key the concurrency group on `github.event.workflow_run.head_branch` to scope by branch"
64
+ - "For CI-to-deploy pipelines, use `cancel-in-progress: true` so only the latest commit deploys"
65
+ - "Consider consolidating CI and deploy into a single workflow using `needs:` if elevated permissions are not required"
66
+ docs:
67
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_run"
68
+ label: "GitHub Docs: workflow_run event"
69
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/controlling-workflow-and-job-execution"
70
+ label: "GitHub Docs: Controlling workflow and job execution (concurrency)"
@@ -0,0 +1,99 @@
1
+ id: permissions-auth-054
2
+ title: "OIDC sub claim format changes when environment: block added — IdP trust policy breaks"
3
+ category: permissions-auth
4
+ severity: error
5
+ tags:
6
+ - oidc
7
+ - environment
8
+ - aws
9
+ - gcp
10
+ - azure
11
+ - sub-claim
12
+ - trust-policy
13
+ - deployment-protection
14
+ patterns:
15
+ - regex: 'Not authorized to perform sts:AssumeRoleWithWebIdentity'
16
+ flags: 'i'
17
+ - regex: 'Error: Credentials could not be loaded'
18
+ flags: 'i'
19
+ - regex: 'Permission.*denied.*generateAccessToken|WorkloadIdentityPool.*rejected'
20
+ flags: 'i'
21
+ error_messages:
22
+ - "Not authorized to perform sts:AssumeRoleWithWebIdentity"
23
+ - "Error: Credentials could not be loaded, please check your action inputs: Could not load credentials from any providers"
24
+ - "Permission 'iam.serviceAccounts.getOpenIdToken' denied on resource"
25
+ - "The provided token could not be validated"
26
+ root_cause: |
27
+ GitHub Actions OIDC token `sub` (subject) claim format depends on whether the
28
+ job has an `environment:` key. Without an environment, the subject is:
29
+ `repo:OWNER/REPO:ref:refs/heads/BRANCH`
30
+
31
+ When `environment: production` is present on the job, the format changes to:
32
+ `repo:OWNER/REPO:environment:production`
33
+
34
+ The branch/ref component is replaced entirely by the environment name. AWS IAM
35
+ role trust policies, GCP Workload Identity Federation conditions, and Azure
36
+ federated credential filters that matched the branch-ref format now receive a
37
+ token with a different sub claim and reject the OIDC exchange with a 403 or
38
+ permission-denied error.
39
+
40
+ This commonly occurs when a team adds environment protection rules (required
41
+ reviewers, wait timers) to an existing workflow that already had OIDC
42
+ credentials working. CI passes before adding `environment:` but fails after.
43
+ fix: |
44
+ Update the IdP trust policy to match the new subject format containing the
45
+ environment name. Options:
46
+ 1. Narrow to environment: change the condition to match
47
+ `repo:OWNER/REPO:environment:production`.
48
+ 2. Use a wildcard: match `repo:OWNER/REPO:*` to accept both formats (less secure).
49
+ 3. GitHub subject claim customization (Enterprise): define a consistent sub
50
+ claim format that does not change based on environment presence.
51
+ fix_code:
52
+ - language: yaml
53
+ label: "Workflow: annotate environment and required OIDC permissions"
54
+ code: |
55
+ permissions:
56
+ id-token: write
57
+ contents: read
58
+
59
+ jobs:
60
+ deploy:
61
+ # Adding this key changes the OIDC sub claim format — update IdP trust policy
62
+ environment: production
63
+ runs-on: ubuntu-latest
64
+ steps:
65
+ - uses: aws-actions/configure-aws-credentials@v4
66
+ with:
67
+ role-to-assume: arn:aws:iam::123456789012:role/DeployRole
68
+ aws-region: us-east-1
69
+ # AWS trust policy must now use:
70
+ # "token.actions.githubusercontent.com:sub":
71
+ # "StringEquals": "repo:org/repo:environment:production"
72
+ # (not "repo:org/repo:ref:refs/heads/main")
73
+ - language: yaml
74
+ label: "AWS IAM trust policy: match environment sub claim"
75
+ code: |
76
+ # AWS IAM Role Trust Policy — update Condition after adding environment:
77
+ # Before (no environment):
78
+ # "token.actions.githubusercontent.com:sub": "repo:org/repo:ref:refs/heads/main"
79
+ #
80
+ # After (with environment: production):
81
+ # "token.actions.githubusercontent.com:sub": "repo:org/repo:environment:production"
82
+ #
83
+ # Wildcard to accept both (less restrictive):
84
+ # "token.actions.githubusercontent.com:sub":
85
+ # StringLike: "repo:org/repo:*"
86
+ #
87
+ # GCP: update attribute.repository_environment or use attribute mapping
88
+ prevention:
89
+ - "Before adding `environment:` to a job using OIDC, audit and update all IdP trust policies"
90
+ - "Document the expected sub claim format in trust policy comments to avoid future confusion"
91
+ - "Use GitHub's OIDC token debugger step to inspect the actual sub claim at runtime"
92
+ - "For consistent sub format across environment and non-environment jobs, consider subject claim customization"
93
+ docs:
94
+ - url: "https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/about-security-hardening-with-openid-connect#filtering-for-a-specific-environment"
95
+ label: "GitHub Docs: OIDC filtering for a specific environment"
96
+ - url: "https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/about-security-hardening-with-openid-connect#customizing-the-subject-claims-for-an-organization-or-repository"
97
+ label: "GitHub Docs: Customizing subject claims"
98
+ - url: "https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services"
99
+ label: "GitHub Docs: Configuring OIDC in AWS"
@@ -0,0 +1,93 @@
1
+ id: yaml-syntax-059
2
+ title: "needs: key does not accept runtime expressions — must be static job IDs"
3
+ category: yaml-syntax
4
+ severity: error
5
+ tags:
6
+ - needs
7
+ - expressions
8
+ - dynamic-jobs
9
+ - job-dependencies
10
+ - parse-time
11
+ - actionlint
12
+ patterns:
13
+ - regex: "The pipeline is not valid.*needs|needs.*references.*job.*does not exist"
14
+ flags: 'i'
15
+ - regex: 'Unrecognized named-value.*steps.*in needs|needs.*invalid.*expression'
16
+ flags: 'i'
17
+ error_messages:
18
+ - "The pipeline is not valid. Job 'deploy' needs 'steps' which does not exist"
19
+ - "Unrecognized named-value: 'steps'"
20
+ - "Job 'X' depends on unknown job '${{ fromJSON(...) }}'"
21
+ - "needs: field value '${{ ... }}' is not a valid job identifier"
22
+ root_cause: |
23
+ The `needs:` key in a GitHub Actions job definition must contain static job ID
24
+ strings. It is evaluated at workflow parse time — before any step or job runs
25
+ — so runtime expressions such as `${{ steps.gen.outputs.jobs }}` or
26
+ `${{ fromJSON(env.DYNAMIC_JOBS) }}` are not evaluated. They are treated as
27
+ literal strings, and since no job with that literal name exists, GitHub reports
28
+ a validation error or the dependency is silently ignored.
29
+
30
+ This surprises developers who successfully use `fromJSON()` in `matrix:` or
31
+ `env:` blocks (which ARE expression-capable) and assume `needs:` works the
32
+ same way. The difference is that the job dependency graph must be fully
33
+ resolved before execution begins; expressions in `needs:` would create a
34
+ circular dependency at parse time.
35
+
36
+ actionlint statically detects this and reports: "needs: field cannot be
37
+ computed by a dynamic value. Use a literal value instead."
38
+ fix: |
39
+ Job dependencies must be statically defined. Use one of these patterns:
40
+ 1. List all potential dependent jobs statically; use `if:` conditions on
41
+ each downstream job to skip those not needed.
42
+ 2. Use a matrix fan-out + fan-in pattern where the fan-in job has a single
43
+ static `needs:` on the matrix job name (not individual matrix legs).
44
+ 3. Restructure so the dependency graph is known at workflow authoring time.
45
+ fix_code:
46
+ - language: yaml
47
+ label: "Correct: static needs: with if: conditions to control execution"
48
+ code: |
49
+ jobs:
50
+ build:
51
+ runs-on: ubuntu-latest
52
+ outputs:
53
+ should_deploy: ${{ steps.check.outputs.deploy }}
54
+ steps:
55
+ - id: check
56
+ run: echo "deploy=true" >> $GITHUB_OUTPUT
57
+
58
+ deploy:
59
+ # Static needs: always declared; if: controls whether it runs
60
+ needs: [build]
61
+ if: needs.build.outputs.should_deploy == 'true'
62
+ runs-on: ubuntu-latest
63
+ steps:
64
+ - run: echo "deploying"
65
+ - language: yaml
66
+ label: "Incorrect: expression in needs: causes parse-time validation error"
67
+ code: |
68
+ jobs:
69
+ generate:
70
+ runs-on: ubuntu-latest
71
+ outputs:
72
+ jobs: ${{ steps.list.outputs.jobs }}
73
+ steps:
74
+ - id: list
75
+ run: echo 'jobs=["build","lint"]' >> $GITHUB_OUTPUT
76
+
77
+ # ERROR: needs: does not evaluate expressions — this is a parse-time failure
78
+ deploy:
79
+ needs: ${{ fromJSON(needs.generate.outputs.jobs) }}
80
+ runs-on: ubuntu-latest
81
+ steps:
82
+ - run: echo "this never runs"
83
+ prevention:
84
+ - "Always use static job ID string literals in `needs:` — no expressions, no fromJSON()"
85
+ - "Use actionlint to pre-validate workflows before pushing: it catches invalid expression contexts"
86
+ - "For dynamic fan-in, depend on the matrix job name itself, not individual matrix leg names"
87
+ - "Use `if: contains(needs.*.result, 'failure')` for conditional logic after static needs"
88
+ docs:
89
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idneeds"
90
+ label: "GitHub Docs: jobs.<job_id>.needs"
91
+ - url: "https://rhysd.github.io/actionlint/"
92
+ label: "actionlint: Static checker for GitHub Actions workflow files"
93
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htekdev/actions-debugger",
3
- "version": "1.0.95",
3
+ "version": "1.0.96",
4
4
  "description": "65+ real GitHub Actions errors, queryable by agents. CLI + MCP server + Copilot skills + error database.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",