@htekdev/actions-debugger 1.0.38 → 1.0.40

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,120 @@
1
+ id: caching-artifacts-031
2
+ title: 'Cache failures from manually-overridden ACTIONS_CACHE_URL after legacy service decommission (April 2025)'
3
+ category: caching-artifacts
4
+ severity: error
5
+ tags:
6
+ - cache
7
+ - legacy-service
8
+ - ACTIONS_CACHE_URL
9
+ - service-migration
10
+ - brownout
11
+ - self-hosted
12
+ patterns:
13
+ - regex: 'ACTIONS_CACHE_URL.*403|ACTIONS_CACHE_URL.*503|ACTIONS_CACHE_URL.*Connection refused'
14
+ flags: 'i'
15
+ - regex: 'Cache service responded with (403|503|5\d\d)'
16
+ flags: 'i'
17
+ - regex: 'Failed to restore cache entry\. Exiting\.\.\.'
18
+ flags: 'i'
19
+ - regex: 'Unable to reserve cache with key.*ACTIONS_CACHE_URL'
20
+ flags: 'i'
21
+ error_messages:
22
+ - "Cache service responded with 503"
23
+ - "Cache service responded with 403"
24
+ - "Failed to restore cache entry. Exiting..."
25
+ - "Unable to reserve cache with key"
26
+ - "Error: ECONNREFUSED connecting to ACTIONS_CACHE_URL"
27
+ root_cause: |
28
+ GitHub migrated all customers to a new cache service backend in early 2025
29
+ and decommissioned the legacy service on April 15, 2025. Prior to decommission,
30
+ brownout windows were scheduled on April 1 and April 8 (each 4-8 hours).
31
+
32
+ Workflows that explicitly override ACTIONS_CACHE_URL, ACTIONS_RESULTS_URL, or
33
+ ACTIONS_RUNTIME_URL continue routing requests to the decommissioned endpoint,
34
+ causing 403 or 503 responses. The cache action reports "Failed to restore cache
35
+ entry" or "Unable to reserve cache" and either skips caching silently or fails
36
+ the step (depending on fail-on-cache-miss settings).
37
+
38
+ Common sources of stale overrides:
39
+ - Third-party self-hosted runner software (ARC add-ons, Buildkite agents, etc.)
40
+ that inject a corporate cache proxy URL into the runner environment
41
+ - Composite actions or reusable workflows with hardcoded env var overrides
42
+ copied from pre-migration documentation
43
+ - Container images with ENV ACTIONS_CACHE_URL set in their Dockerfile,
44
+ inherited by container jobs and overriding the runner-injected value
45
+ - Enterprise self-hosted runner configurations in on-premises GitHub instances
46
+ that still point to a proxy configured for the old cache service API
47
+
48
+ The runner agent always injects the correct new-service values at job startup.
49
+ Any explicit override — even one set a millisecond earlier — takes precedence
50
+ and silently routes to the wrong endpoint.
51
+ fix: |
52
+ Remove all explicit overrides of ACTIONS_CACHE_URL, ACTIONS_RESULTS_URL, and
53
+ ACTIONS_RUNTIME_URL from:
54
+ - Workflow env: blocks (top-level, job-level, and step-level)
55
+ - Composite action env blocks
56
+ - Reusable workflow env blocks
57
+ - Container image Dockerfiles (ENV directives)
58
+ - Self-hosted runner startup scripts and systemd unit files
59
+ - ARC runner controller configuration and any environment-injection middleware
60
+
61
+ Let the runner agent inject the correct values automatically at job startup.
62
+ These values are ephemeral per-job tokens — they cannot be cached or pre-set
63
+ and must come from the runner agent.
64
+
65
+ For self-hosted setups using a corporate cache proxy, update the proxy
66
+ to forward requests to the new service endpoint format, or decommission the
67
+ proxy if it is no longer required.
68
+ fix_code:
69
+ - language: yaml
70
+ label: 'Remove ACTIONS_CACHE_URL override from workflow — let runner inject correct value'
71
+ code: |
72
+ # WRONG: overriding cache service URL causes failures after April 2025
73
+ # env:
74
+ # ACTIONS_CACHE_URL: https://my-corp-proxy.example.com/_apis/artifactcache/
75
+ # ACTIONS_RESULTS_URL: https://my-corp-proxy.example.com/_apis/
76
+ # ACTIONS_RUNTIME_URL: https://my-corp-proxy.example.com/
77
+
78
+ # CORRECT: remove all overrides, let the runner inject the values
79
+ jobs:
80
+ build:
81
+ runs-on: [self-hosted, linux]
82
+ steps:
83
+ - uses: actions/checkout@v4
84
+ - name: Cache dependencies
85
+ uses: actions/cache@v4
86
+ with:
87
+ path: ~/.npm
88
+ key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
89
+ - name: Install
90
+ run: npm ci
91
+ - language: yaml
92
+ label: 'Audit container images for hardcoded ACTIONS_CACHE_URL'
93
+ code: |
94
+ # In your Dockerfile — remove any hardcoded cache service URL
95
+ # FROM ubuntu:22.04
96
+ # ENV ACTIONS_CACHE_URL=https://... ← REMOVE: causes failures after April 2025
97
+
98
+ # In your workflow — do not set cache URL env vars in container definitions
99
+ jobs:
100
+ build:
101
+ runs-on: ubuntu-latest
102
+ container:
103
+ image: myimage:latest
104
+ # Do not add env overrides for ACTIONS_CACHE_URL here
105
+ steps:
106
+ - uses: actions/cache@v4
107
+ with:
108
+ path: ~/.cache/pip
109
+ key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
110
+ prevention:
111
+ - 'Never hardcode ACTIONS_CACHE_URL, ACTIONS_RESULTS_URL, or ACTIONS_RUNTIME_URL in workflows, container images, or runner configs'
112
+ - 'Audit third-party composite actions and runner middleware for injected cache URL overrides after any GitHub cache service migration'
113
+ - 'Subscribe to the GitHub Changelog (github.blog/changelog) to receive advance notice of cache service migrations and brownout schedules'
114
+ - 'Upgrade to actions/cache@v4 or later — the v4 client was updated to use the new service API and is the supported path forward'
115
+ - 'Add a pre-flight check step on self-hosted runners that logs the injected ACTIONS_CACHE_URL to detect unexpected overrides'
116
+ docs:
117
+ - url: 'https://github.blog/changelog/2025-03-20-notification-of-upcoming-breaking-changes-in-github-actions/'
118
+ label: 'GitHub Changelog: Upcoming breaking changes — legacy cache service decommission (March 2025)'
119
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows'
120
+ label: 'Caching dependencies to speed up workflows — actions/cache@v4'
@@ -0,0 +1,111 @@
1
+ id: permissions-auth-033
2
+ title: 'github.actor frozen at original trigger time — github.triggering_actor differs on re-run, breaking actor-based access checks'
3
+ category: permissions-auth
4
+ severity: silent-failure
5
+ tags:
6
+ - github.actor
7
+ - github.triggering_actor
8
+ - re-run
9
+ - access-control
10
+ - if-condition
11
+ - silent-failure
12
+ - permissions
13
+ patterns:
14
+ - regex: 'github\.triggering_actor|triggering_actor'
15
+ flags: 'i'
16
+ - regex: 'Skipping.*actor.*not.*allowed|actor.*not in.*allowlist'
17
+ flags: 'i'
18
+ - regex: 'Access denied.*github\.actor'
19
+ flags: 'i'
20
+ error_messages:
21
+ - "Skipping deployment: actor 'original-bot' is not in the deployers allowlist"
22
+ - "Access denied: github.actor does not match the expected release account"
23
+ root_cause: |
24
+ GitHub Actions provides two separate context properties for workflow actor identity:
25
+
26
+ github.actor — the user or app that ORIGINALLY triggered the workflow run
27
+ github.triggering_actor — the user or app that triggered the CURRENT run attempt
28
+ (reflects re-runs and re-trigger operations)
29
+
30
+ These values are identical for the first run of a workflow. They diverge when
31
+ the workflow is re-triggered via the "Re-run jobs" button, "Re-run failed jobs",
32
+ or the REST API re-run endpoint. In that case, github.actor still holds the
33
+ original requester's login while github.triggering_actor holds the person or
34
+ app that clicked re-run.
35
+
36
+ Two classes of silent failure result:
37
+
38
+ 1. Security bypass: A workflow guards a deployment with
39
+ if: github.actor == 'deploy-bot'. A human clicks "Re-run" — github.actor
40
+ still shows 'deploy-bot' (original requester), so the guard passes and the
41
+ human inadvertently triggers a privileged deployment step.
42
+
43
+ 2. Unintended block: A workflow allows deployments only for a specific release
44
+ manager by checking github.actor. A second authorized team member re-runs
45
+ the workflow — github.actor shows the original requester (someone else),
46
+ so the guard incorrectly blocks the re-run.
47
+
48
+ In both cases there is no error message indicating the actor mismatch — the
49
+ guard silently passes or silently blocks based on stale identity data.
50
+ fix: |
51
+ For access control checks that should apply to WHO IS CURRENTLY RUNNING the
52
+ workflow (including re-runs), replace github.actor with github.triggering_actor.
53
+
54
+ For checks that must enforce the original requester (e.g., "only the PR author
55
+ can trigger this check"), use github.actor explicitly and document the intent.
56
+
57
+ For high-security deployment gates, use GitHub Environment protection rules
58
+ with required reviewers. Environment protection is enforced by GitHub platform
59
+ security rather than YAML if: conditions and cannot be bypassed by re-runs.
60
+ fix_code:
61
+ - language: yaml
62
+ label: 'Use triggering_actor for re-run-aware access control'
63
+ code: |
64
+ jobs:
65
+ deploy:
66
+ runs-on: ubuntu-latest
67
+ steps:
68
+ # WRONG: github.actor is frozen at original trigger time
69
+ # github.actor still shows 'deploy-bot' even when a human re-runs
70
+ # - name: Gate check
71
+ # if: github.actor != 'deploy-bot'
72
+ # run: exit 1
73
+
74
+ # CORRECT: github.triggering_actor reflects who actually ran this attempt
75
+ - name: Gate check
76
+ if: github.triggering_actor != 'deploy-bot'
77
+ run: |
78
+ echo "::error::Deploy must be triggered by deploy-bot, got ${{ github.triggering_actor }}"
79
+ exit 1
80
+
81
+ - name: Deploy
82
+ run: ./deploy.sh
83
+ - language: yaml
84
+ label: 'Use environment protection rules for production deployments (preferred)'
85
+ code: |
86
+ jobs:
87
+ deploy:
88
+ runs-on: ubuntu-latest
89
+ environment: production # required reviewers enforced at platform level
90
+ steps:
91
+ - name: Deploy
92
+ env:
93
+ ACTOR: ${{ github.actor }}
94
+ TRIGGERED_BY: ${{ github.triggering_actor }}
95
+ run: |
96
+ echo "Original trigger: $ACTOR"
97
+ echo "This run triggered by: $TRIGGERED_BY"
98
+ ./deploy.sh
99
+ prevention:
100
+ - 'Use github.triggering_actor (not github.actor) when the intent is to check who triggered the current run attempt'
101
+ - 'Prefer GitHub Environment protection rules and required reviewers over actor-based if: conditions for deployment gates'
102
+ - 'Document in each workflow whether actor checks use github.actor (original) or github.triggering_actor (current)'
103
+ - 'Test actor-based gates by having a second authorized user re-run the workflow to verify the check fires as expected'
104
+ - 'Never use github.actor alone for security-sensitive production deployment gates — it is not re-run-aware'
105
+ docs:
106
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#github-context'
107
+ label: 'github context — github.actor vs github.triggering_actor properties'
108
+ - url: 'https://github.blog/changelog/2022-08-09-github-actions-re-run-workflows-and-jobs/'
109
+ label: 'GitHub Changelog 2022-08-09: Re-run workflows and jobs — introducing triggering_actor'
110
+ - url: 'https://github.com/orgs/community/discussions/27154'
111
+ label: 'GitHub Community: github.actor vs github.triggering_actor for re-run access control'
@@ -0,0 +1,103 @@
1
+ id: runner-environment-097
2
+ title: 'Container job with non-root Docker user fails with EACCES on workspace and command files'
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - container-jobs
7
+ - non-root
8
+ - rootless
9
+ - permissions
10
+ - EACCES
11
+ - docker
12
+ - workspace
13
+ patterns:
14
+ - regex: 'EACCES.*permission denied.*_runner_file_commands|permission denied.*_runner_file_commands'
15
+ flags: 'i'
16
+ - regex: 'permission denied.*GITHUB_ENV|permission denied.*GITHUB_OUTPUT|permission denied.*GITHUB_PATH|permission denied.*GITHUB_STEP_SUMMARY'
17
+ flags: 'i'
18
+ - regex: 'could not lock config file.*Permission denied'
19
+ flags: 'i'
20
+ - regex: 'EACCES.*permission denied.*__w|permission denied.*github/workspace'
21
+ flags: 'i'
22
+ error_messages:
23
+ - "Error: EACCES: permission denied, open '/home/runner/work/_temp/_runner_file_commands/set_env_'"
24
+ - "Error: EACCES: permission denied, open '/__w/_temp/_runner_file_commands/add_path_'"
25
+ - "error: could not lock config file /home/runner/work/repo/.git/config: Permission denied"
26
+ - "EACCES: permission denied, open '/github/workspace/_temp/_runner_file_commands/'"
27
+ root_cause: |
28
+ When a workflow uses a container job (jobs.<id>.container), the GitHub Actions
29
+ runner creates the workspace directories, .git directory, and all special command
30
+ files (GITHUB_ENV, GITHUB_OUTPUT, GITHUB_PATH, GITHUB_STEP_SUMMARY) as root UID
31
+ on the host before starting the container.
32
+
33
+ If the container image runs as a non-root user — via a USER directive in the
34
+ Dockerfile, docker run --user, or a Kubernetes securityContext.runAsUser setting —
35
+ that user has no write access to the root-owned files and directories. Every step
36
+ that writes to GITHUB_ENV, GITHUB_OUTPUT, GITHUB_PATH, or GITHUB_STEP_SUMMARY
37
+ fails with EACCES: permission denied. The checkout step also fails because git
38
+ cannot write the lock file for the config.
39
+
40
+ The runner does not automatically adjust ownership, set ACLs, or apply mount
41
+ options to make the workspace writable by non-root container users. This is a
42
+ known long-standing platform limitation tracked in runner#2411 (30 reactions)
43
+ with no built-in fix as of 2026. The issue also affects ARC (actions-runner-controller)
44
+ Kubernetes runners when the pod securityContext sets a non-root runAsUser.
45
+ fix: |
46
+ Option 1 — Add `options: --user root` to the container definition.
47
+ This overrides the container USER and runs job steps as root, granting
48
+ full access to all runner-created files.
49
+
50
+ Option 2 — Set fsGroup in Kubernetes/ARC pod spec so mounted directories
51
+ are group-writable and the container's supplemental group matches.
52
+
53
+ Option 3 — Use a privileged init step (--user 0) to chown the workspace
54
+ to the container's non-root UID before executing actual build steps.
55
+
56
+ Option 4 — Build the container image with UID 1001 (the runner UID on
57
+ GitHub-hosted runners) instead of a custom non-root UID, so ownership
58
+ matches automatically.
59
+ fix_code:
60
+ - language: yaml
61
+ label: 'Force container to run as root with options: --user root'
62
+ code: |
63
+ jobs:
64
+ build:
65
+ runs-on: ubuntu-latest
66
+ container:
67
+ image: myapp:latest # Has a non-root USER in its Dockerfile
68
+ options: --user root # Override: run job steps as root
69
+ steps:
70
+ - uses: actions/checkout@v4
71
+ - name: Build
72
+ run: make build
73
+ - language: yaml
74
+ label: 'Set fsGroup in ARC RunnerSet to make workspace group-writable'
75
+ code: |
76
+ apiVersion: actions.github.com/v1alpha1
77
+ kind: RunnerSet
78
+ metadata:
79
+ name: my-runners
80
+ spec:
81
+ template:
82
+ spec:
83
+ securityContext:
84
+ fsGroup: 1001 # Match runner UID so workspace is accessible
85
+ containers:
86
+ - name: runner
87
+ image: ghcr.io/actions/actions-runner:latest
88
+ securityContext:
89
+ runAsUser: 1001
90
+ runAsGroup: 1001
91
+ prevention:
92
+ - 'Prefer running container jobs as root or as UID 1001 to match the runner workspace ownership'
93
+ - 'Test container images locally with docker run --user <uid> to catch permission issues before CI'
94
+ - 'Document the --user root workaround in workflow templates that use custom container images'
95
+ - 'Consider using a job-level container for tool availability only, keeping privileged steps on the host runner'
96
+ - 'When building custom runner images, set USER to UID 1001 to match GitHub-hosted runner conventions'
97
+ docs:
98
+ - url: 'https://github.com/actions/runner/issues/2411'
99
+ label: 'runner#2411: Runner does not set proper permissions for mounted folders in rootless container jobs (30 reactions)'
100
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-where-your-workflow-runs/running-jobs-in-a-container'
101
+ label: 'Running jobs in a container — options field and container configuration'
102
+ - url: 'https://github.com/actions/runner/issues/3290'
103
+ label: 'runner#3290: Kubernetes container pods fail with EACCES when using a custom user'
@@ -0,0 +1,112 @@
1
+ id: runner-environment-096
2
+ title: 'Self-hosted runner runsvc.sh corrupted to 0 bytes after auto-update'
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - self-hosted
7
+ - auto-update
8
+ - runsvc
9
+ - systemd
10
+ - service-restart
11
+ patterns:
12
+ - regex: 'runsvc\.sh.*0 bytes|0 bytes.*runsvc\.sh'
13
+ flags: 'i'
14
+ - regex: 'code=exited.*status=203/EXEC|status=203/EXEC'
15
+ flags: 'i'
16
+ - regex: 'Failed to start GitHub Actions Runner'
17
+ flags: 'i'
18
+ - regex: 'bin/runsvc\.sh.*Syntax error.*end of file'
19
+ flags: 'i'
20
+ error_messages:
21
+ - "(code=exited, status=203/EXEC)"
22
+ - "Failed to start GitHub Actions Runner (svc.sh)"
23
+ - "bin/runsvc.sh: 1: Syntax error: Unexpected end of file"
24
+ - "bin.2.334.0/runsvc.sh: 0 bytes"
25
+ root_cause: |
26
+ When a self-hosted runner auto-updates from v2.328.0 to v2.334.0 (and some
27
+ adjacent version pairs), a race condition in the update file-extraction process
28
+ sometimes writes the new bin.{version}/runsvc.sh as 0 bytes instead of the
29
+ correct shell script content.
30
+
31
+ The currently-running listener operates from in-memory state and continues
32
+ accepting and completing jobs normally — so the runner appears healthy in
33
+ the GitHub Actions UI and the corruption is not immediately visible. The
34
+ bin/runsvc.sh symlink quietly points to the corrupted 0-byte file.
35
+
36
+ On the next service restart (host reboot, manual systemctl restart, OOM kill,
37
+ scheduled maintenance window), systemd attempts to execute the 0-byte runsvc.sh,
38
+ receives Status=203/EXEC (exec format error because the file is empty), and the
39
+ runner fails to start entirely — dropping all pending and future jobs.
40
+
41
+ The failure is especially hard to diagnose because the runner appears fully
42
+ online right up to the restart event. Runners in pools that restart infrequently
43
+ may run corrupted for days before the symptom appears.
44
+ fix: |
45
+ Immediate recovery:
46
+ 1. Check if runsvc.sh is 0 bytes:
47
+ ls -lh /path/to/runner/bin/runsvc.sh
48
+ 2. If 0 bytes, stop the service and re-download the runner package at the
49
+ same version, or manually copy runsvc.sh from a known-good runner
50
+ installation of the same version.
51
+ 3. Restart the service and confirm it comes up cleanly before re-enabling
52
+ job acceptance.
53
+
54
+ Preventive measures:
55
+ - Disable auto-update (--no-auto-update flag during registration) and manage
56
+ runner version upgrades manually during maintenance windows.
57
+ - Add a startup health check (see fix_code) that verifies runsvc.sh is
58
+ non-zero before the service is considered ready.
59
+ - For ephemeral runners, use container restart policies that detect the
60
+ 0-byte condition and re-register a fresh runner instead of recycling
61
+ a corrupted one.
62
+ fix_code:
63
+ - language: yaml
64
+ label: 'Detect corrupted runsvc.sh in a pre-job health check step'
65
+ code: |
66
+ jobs:
67
+ preflight:
68
+ runs-on: [self-hosted, linux]
69
+ steps:
70
+ - name: Verify runner service script integrity
71
+ shell: bash
72
+ run: |
73
+ RUNNER_SVC="$(dirname "$(realpath "$0")")/../bin/runsvc.sh"
74
+ if [ ! -s "$RUNNER_SVC" ]; then
75
+ echo "::error::runsvc.sh is 0 bytes — runner update corrupted the service script. Re-register this runner."
76
+ exit 1
77
+ fi
78
+ echo "runsvc.sh OK ($(wc -c < "$RUNNER_SVC") bytes)"
79
+ - language: yaml
80
+ label: 'Pin runner version and disable auto-update via ARC RunnerSet spec'
81
+ code: |
82
+ # actions-runner-controller RunnerSet — pin version, disable auto-update
83
+ apiVersion: actions.github.com/v1alpha1
84
+ kind: RunnerSet
85
+ metadata:
86
+ name: my-runners
87
+ spec:
88
+ githubConfigUrl: https://github.com/my-org/my-repo
89
+ githubConfigSecret: controller-manager
90
+ minRunners: 2
91
+ maxRunners: 10
92
+ template:
93
+ spec:
94
+ containers:
95
+ - name: runner
96
+ image: ghcr.io/actions/actions-runner:2.334.0 # pin version
97
+ env:
98
+ - name: DISABLE_RUNNER_UPDATE
99
+ value: '1'
100
+ prevention:
101
+ - 'Pin runner version with --no-auto-update and upgrade manually during maintenance windows'
102
+ - 'Monitor runner systemd units with alerting on failed states before jobs queue up'
103
+ - 'Use ephemeral runners (--ephemeral flag) so each job gets a freshly registered runner, avoiding accumulated update corruption'
104
+ - 'After any auto-update event, verify that bin/runsvc.sh is non-zero before accepting production jobs'
105
+ - 'Run a nightly canary workflow that exercises a restart-then-run cycle on self-hosted pools'
106
+ docs:
107
+ - url: 'https://github.com/actions/runner/issues/4421'
108
+ label: 'runner#4421: runsvc.sh sometimes 0 bytes after auto-update from 2.328.0 to 2.334.0 (May 2026)'
109
+ - url: 'https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/autoscaling-with-self-hosted-runners'
110
+ label: 'Autoscaling with self-hosted runners — runner lifecycle management'
111
+ - url: 'https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners#self-hosted-runner-version-updates'
112
+ label: 'Self-hosted runner version updates'
@@ -0,0 +1,123 @@
1
+ id: silent-failures-043
2
+ title: 'github.workspace and runner.workspace return host paths, not container paths, inside container jobs'
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - container-jobs
7
+ - github-context
8
+ - workspace
9
+ - path-mismatch
10
+ - expressions
11
+ - silent
12
+ patterns:
13
+ - regex: '\$\{\{\s*github\.workspace\s*\}\}.*container|\$\{\{\s*runner\.workspace\s*\}\}.*container'
14
+ flags: 'i'
15
+ - regex: '/home/runner/work/[^/]+/[^/]+.*no such file|not found.*home/runner/work'
16
+ flags: 'i'
17
+ error_messages: []
18
+ root_cause: |
19
+ Inside container jobs, `${{ github.workspace }}` and `${{ runner.workspace }}`
20
+ resolve to the HOST-side path (e.g., /home/runner/work/repo/repo), not the
21
+ path that the container actually sees at runtime (e.g., /github/workspace or
22
+ /__w/repo/repo depending on the runner type).
23
+
24
+ The container mounts the workspace at a different path than the host. Any
25
+ expression using these context values to construct file paths, Docker build
26
+ contexts, artifact paths, or shell script arguments will silently resolve to
27
+ the wrong location inside the container — either a non-existent path or an
28
+ unexpected host directory leaked into the container mount namespace.
29
+
30
+ By contrast, the GITHUB_WORKSPACE and RUNNER_WORKSPACE environment variables
31
+ ARE injected with the correct container-visible paths. Only the expression
32
+ context values (${{ github.workspace }}) are wrong. This inconsistency is the
33
+ core trap: developers expect context and env var to be equivalent, but inside
34
+ containers they diverge.
35
+
36
+ No error is raised — wrong paths are silently accepted by shells and tools,
37
+ causing subtly incorrect behavior: files not found, wrong directory used for
38
+ builds, artifacts uploaded from wrong paths, or test results pointing to
39
+ non-existent locations.
40
+
41
+ Tracked in runner#2058 (81 reactions, 13 confused reactions) as a known bug
42
+ with no built-in fix as of 2026.
43
+ fix: |
44
+ Use the GITHUB_WORKSPACE environment variable instead of the
45
+ ${{ github.workspace }} expression inside container job steps. The env var
46
+ is injected by the runner with the correct container-visible path.
47
+
48
+ Similarly, use RUNNER_WORKSPACE instead of ${{ runner.workspace }}.
49
+
50
+ For Docker build contexts and tool paths that require absolute paths, use
51
+ the container-visible path directly:
52
+ - GitHub-hosted runners: /github/workspace
53
+ - ARC/self-hosted: /__w/<repo-name>/<repo-name> (verify with pwd in first step)
54
+
55
+ Alternatively, use relative paths (.) wherever possible to avoid the
56
+ host/container path discrepancy entirely.
57
+ fix_code:
58
+ - language: yaml
59
+ label: 'Use GITHUB_WORKSPACE env var instead of ${{ github.workspace }} inside container steps'
60
+ code: |
61
+ jobs:
62
+ build:
63
+ runs-on: ubuntu-latest
64
+ container:
65
+ image: myapp-builder:latest
66
+ steps:
67
+ - uses: actions/checkout@v4
68
+
69
+ # WRONG: returns host path, not the container-visible mount path
70
+ # - name: Build
71
+ # run: cd "${{ github.workspace }}" && make build
72
+
73
+ # CORRECT: GITHUB_WORKSPACE is set to the container-visible path
74
+ - name: Build
75
+ run: |
76
+ echo "Container workspace: $GITHUB_WORKSPACE"
77
+ cd "$GITHUB_WORKSPACE" && make build
78
+ - language: yaml
79
+ label: 'Use relative paths for Docker build context inside container jobs'
80
+ code: |
81
+ jobs:
82
+ docker-in-docker:
83
+ runs-on: ubuntu-latest
84
+ container:
85
+ image: docker:24
86
+ steps:
87
+ - uses: actions/checkout@v4
88
+ - name: Build image
89
+ run: |
90
+ # Use . (current dir) not ${{ github.workspace }} for build context
91
+ docker build -t myimage:latest .
92
+
93
+ # If absolute path needed, use the env var:
94
+ docker build -t myimage:latest "$GITHUB_WORKSPACE"
95
+ - language: yaml
96
+ label: 'Debug step to reveal the actual container workspace path'
97
+ code: |
98
+ jobs:
99
+ debug:
100
+ runs-on: ubuntu-latest
101
+ container:
102
+ image: ubuntu:22.04
103
+ steps:
104
+ - name: Show path discrepancy
105
+ run: |
106
+ echo "Host path via context (WRONG inside container):"
107
+ echo " github.workspace = ${{ github.workspace }}"
108
+ echo ""
109
+ echo "Container-visible path via env var (CORRECT):"
110
+ echo " GITHUB_WORKSPACE = $GITHUB_WORKSPACE"
111
+ echo ""
112
+ echo "Actual current directory: $(pwd)"
113
+ prevention:
114
+ - 'Never use ${{ github.workspace }} or ${{ runner.workspace }} expressions inside container job steps — they return host paths'
115
+ - 'Use the GITHUB_WORKSPACE and RUNNER_WORKSPACE environment variables for all path references inside containers'
116
+ - 'Use relative paths wherever possible in container steps to avoid the host/container path mismatch entirely'
117
+ - 'Add a debug step printing both the context value and the env var when authoring new container workflows'
118
+ - 'Test container-based workflows locally with nektos/act to surface path resolution issues before CI'
119
+ docs:
120
+ - url: 'https://github.com/actions/runner/issues/2058'
121
+ label: 'runner#2058: github.workspace and runner.workspace are incorrect inside container jobs (81 reactions)'
122
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-where-your-workflow-runs/running-jobs-in-a-container'
123
+ label: 'Running jobs in a container — environment variables and context values'
@@ -0,0 +1,103 @@
1
+ id: silent-failures-044
2
+ title: 'upload-artifact path patterns resolved from workspace root — working-directory setting ignored'
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - upload-artifact
7
+ - working-directory
8
+ - path
9
+ - glob
10
+ - artifacts
11
+ - workspace
12
+ patterns:
13
+ - regex: 'No files were found with the provided path'
14
+ flags: 'i'
15
+ - regex: 'Warning: No files were found with the provided path'
16
+ flags: 'i'
17
+ - regex: 'artifact.*no files.*found|no files.*artifact'
18
+ flags: 'i'
19
+ error_messages:
20
+ - "Error: No files were found with the provided path: dist/build.zip. No artifacts will be uploaded."
21
+ - "Warning: No files were found with the provided path: *.tar.gz. No artifacts will be uploaded."
22
+ - "No files were found with the provided path: output/*.zip"
23
+ root_cause: |
24
+ The path: input in actions/upload-artifact (all versions) is always resolved
25
+ relative to $GITHUB_WORKSPACE (the repository root), regardless of any
26
+ working-directory: setting on the step or enclosing job.
27
+
28
+ Developers who set working-directory: dist at the job level or on the step
29
+ and then specify path: *.js or path: build.zip expect the glob to be evaluated
30
+ from within dist/. Instead, the action evaluates it from workspace root, finds
31
+ no matching files, and either warns and uploads nothing (silent-failure) or
32
+ fails the step entirely depending on if-no-files-found setting.
33
+
34
+ The working-directory: context is respected only by run: shell steps for
35
+ command execution. It is not propagated to uses: action inputs — actions
36
+ receive path inputs as raw strings and resolve them internally from GITHUB_WORKSPACE.
37
+
38
+ The same behavior applies to actions/download-artifact path: inputs and to
39
+ other actions that accept file path parameters (e.g., docker/build-push-action
40
+ context: and file: inputs also require workspace-relative paths).
41
+ fix: |
42
+ Prefix all path: patterns with the subdirectory path relative to GITHUB_WORKSPACE.
43
+
44
+ Instead of:
45
+ working-directory: dist
46
+ path: build.zip
47
+
48
+ Use:
49
+ path: dist/build.zip
50
+
51
+ Or to upload an entire directory tree:
52
+ path: dist/
53
+
54
+ Set if-no-files-found: error to convert the silent warning into a visible
55
+ failure so path mistakes are caught immediately rather than silently producing
56
+ empty or missing artifacts downstream.
57
+ fix_code:
58
+ - language: yaml
59
+ label: 'Use workspace-relative path instead of relying on working-directory'
60
+ code: |
61
+ jobs:
62
+ build:
63
+ runs-on: ubuntu-latest
64
+ steps:
65
+ - uses: actions/checkout@v4
66
+
67
+ - name: Build
68
+ working-directory: dist # only affects this run: step
69
+ run: npm run build
70
+
71
+ # WRONG: path: build.zip searches workspace root, not dist/
72
+ # - uses: actions/upload-artifact@v4
73
+ # with:
74
+ # name: release
75
+ # path: build.zip
76
+
77
+ # CORRECT: include the subdirectory in the path
78
+ - uses: actions/upload-artifact@v4
79
+ with:
80
+ name: release
81
+ path: dist/build.zip # relative to GITHUB_WORKSPACE
82
+ if-no-files-found: error
83
+ - language: yaml
84
+ label: 'Upload all files from a subdirectory and fail fast on missing files'
85
+ code: |
86
+ - uses: actions/upload-artifact@v4
87
+ with:
88
+ name: dist-files
89
+ path: dist/ # uploads entire dist/ directory tree
90
+ if-no-files-found: error # fail fast instead of silent warning
91
+ prevention:
92
+ - 'Always write path: patterns in upload-artifact relative to GITHUB_WORKSPACE (repository root), not working-directory'
93
+ - 'Set if-no-files-found: error on every upload-artifact step to catch path mistakes immediately'
94
+ - 'Verify artifact contents in the Actions UI after the first run to confirm the correct files were captured'
95
+ - 'Remember that working-directory: only affects run: shell steps — uses: action inputs are always workspace-relative'
96
+ - 'Use ${{ github.workspace }} to build absolute paths when the relative path is ambiguous'
97
+ docs:
98
+ - url: 'https://github.com/actions/upload-artifact#inputs'
99
+ label: 'actions/upload-artifact inputs — path field documentation'
100
+ - url: 'https://github.com/actions/upload-artifact/issues/232'
101
+ label: 'upload-artifact#232: path is resolved relative to workspace root, not working-directory (community report)'
102
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#default-environment-variables'
103
+ label: 'GITHUB_WORKSPACE default environment variable — GitHub Docs'
@@ -0,0 +1,119 @@
1
+ id: triggers-031
2
+ title: 'Required status check never satisfied when workflow uses paths: filter — PR permanently blocked'
3
+ category: triggers
4
+ severity: error
5
+ tags:
6
+ - required-status-check
7
+ - paths-filter
8
+ - pull-request
9
+ - branch-protection
10
+ - PR-blocked
11
+ - monorepo
12
+ - status-check
13
+ patterns:
14
+ - regex: 'Required status check.*is expected'
15
+ flags: 'i'
16
+ - regex: 'Merging is blocked.*required status check'
17
+ flags: 'i'
18
+ - regex: 'Waiting for status to be reported'
19
+ flags: 'i'
20
+ error_messages:
21
+ - "Required status check 'CI / build' is expected — 1 pending check"
22
+ - "Merging is blocked: 1 required status check has not completed"
23
+ - "Waiting for status to be reported"
24
+ root_cause: |
25
+ When a GitHub Actions workflow uses on: push: paths: or on: pull_request: paths:
26
+ filter AND that workflow's job name is configured as a required status check in
27
+ branch protection rules, a critical gap emerges.
28
+
29
+ If a pull request does NOT modify any files matching the paths: filter, the
30
+ workflow is skipped entirely — no workflow run is created and no check status
31
+ is posted to the commit. GitHub branch protection interprets a missing status
32
+ check as "pending" (not as "skipped" or "passed"), which permanently blocks the
33
+ PR from merging.
34
+
35
+ This is the most common misconfiguration in monorepo setups where teams add
36
+ per-service CI: a workflow for service-A runs only when src/service-a/** changes.
37
+ Adding this workflow's job as a required status check then breaks ALL other PRs
38
+ that don't touch service-A — they are blocked forever waiting for a check that
39
+ will never run.
40
+
41
+ The same issue occurs with paths-ignore: if ALL changed files match the ignore
42
+ patterns, the workflow is skipped and the required check is never posted.
43
+
44
+ Note: GitHub does not automatically treat a "skipped" workflow as passing a
45
+ required status check. The job must explicitly run and succeed.
46
+ fix: |
47
+ Remove the paths: filter from the on: trigger and instead use dorny/paths-filter
48
+ or tj-actions/changed-files inside the workflow to detect changed files. The
49
+ workflow always runs (posting a check status) but skips expensive build steps
50
+ when irrelevant files changed.
51
+
52
+ Add a final ci-complete or always-pass job that runs with if: always() and
53
+ depends on the conditional jobs. Configure this final job name as the required
54
+ status check. It posts a success status for all PRs, whether or not the
55
+ upstream jobs ran.
56
+ fix_code:
57
+ - language: yaml
58
+ label: 'Replace paths: filter with internal file detection — always post a check status'
59
+ code: |
60
+ name: Service A CI
61
+
62
+ on:
63
+ pull_request:
64
+ branches: [main]
65
+ # REMOVE the paths: filter that prevents check from running on non-matching PRs
66
+ # paths:
67
+ # - src/service-a/**
68
+
69
+ jobs:
70
+ detect-changes:
71
+ runs-on: ubuntu-latest
72
+ outputs:
73
+ service-a-changed: ${{ steps.filter.outputs.service-a }}
74
+ steps:
75
+ - uses: actions/checkout@v4
76
+ - uses: dorny/paths-filter@v3
77
+ id: filter
78
+ with:
79
+ filters: |
80
+ service-a:
81
+ - 'src/service-a/**'
82
+
83
+ build:
84
+ needs: detect-changes
85
+ if: needs.detect-changes.outputs.service-a-changed == 'true'
86
+ runs-on: ubuntu-latest
87
+ steps:
88
+ - uses: actions/checkout@v4
89
+ - run: make build-service-a
90
+
91
+ # Required status check name: "Service A CI / ci-complete"
92
+ # This job ALWAYS runs and posts a check — satisfies branch protection for all PRs
93
+ ci-complete:
94
+ needs: [detect-changes, build]
95
+ if: always()
96
+ runs-on: ubuntu-latest
97
+ steps:
98
+ - name: Evaluate build result
99
+ run: |
100
+ if [[ "${{ needs.build.result }}" == "failure" ]]; then
101
+ echo "Build failed"
102
+ exit 1
103
+ fi
104
+ echo "CI complete (build skipped or passed)"
105
+ prevention:
106
+ - 'Never add a required status check on a workflow that has a paths: filter — the check will be missing for non-matching PRs'
107
+ - 'Use paths-filter action inside the workflow instead of on.pull_request.paths to keep the workflow always running'
108
+ - 'Add a ci-complete job with if: always() as the required status check — not the individual build job'
109
+ - 'Test branch protection + paths filter by opening a PR that changes only unrelated files before enabling required checks'
110
+ - 'Document in your monorepo contributing guide that required checks use the internal paths-filter pattern'
111
+ docs:
112
+ - url: 'https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#require-status-checks-before-merging'
113
+ label: 'About protected branches — require status checks before merging'
114
+ - url: 'https://github.com/orgs/community/discussions/20548'
115
+ label: 'GitHub Community: Required status check never satisfies when workflow has paths filter (30+ reactions)'
116
+ - url: 'https://github.com/dorny/paths-filter'
117
+ label: 'dorny/paths-filter — recommended replacement for workflow-level paths: filter'
118
+ - url: 'https://github.com/orgs/community/discussions/44490'
119
+ label: 'GitHub Community: paths filter skips required checks causing PR stuck (additional discussion)'
@@ -0,0 +1,97 @@
1
+ id: yaml-syntax-034
2
+ title: 'runs-on label array requires ALL labels to match (AND logic) — job queues indefinitely when no runner qualifies'
3
+ category: yaml-syntax
4
+ severity: error
5
+ tags:
6
+ - runs-on
7
+ - self-hosted
8
+ - labels
9
+ - runner-matching
10
+ - AND-logic
11
+ - job-queue
12
+ - infinite-wait
13
+ patterns:
14
+ - regex: 'Waiting for a runner to pick up this job'
15
+ flags: 'i'
16
+ - regex: 'Could not find any available self-hosted runner that matches the required labels'
17
+ flags: 'i'
18
+ - regex: 'No hosted runner matching the labels.*was found'
19
+ flags: 'i'
20
+ error_messages:
21
+ - "Waiting for a runner to pick up this job"
22
+ - "Could not find any available self-hosted runner that matches the required labels: self-hosted, linux, arm64, fast-ssd"
23
+ - "No hosted runner matching the labels ['self-hosted', 'linux', 'gpu'] was found"
24
+ root_cause: |
25
+ When runs-on: specifies an array of labels, GitHub requires a runner to have
26
+ ALL of the listed labels simultaneously (AND logic, not OR). A runner registered
27
+ with labels [self-hosted, linux, x64] will NOT match
28
+ runs-on: [self-hosted, linux, arm64] because it is missing the arm64 label,
29
+ even though it has two of the three required labels.
30
+
31
+ Common causes of permanent queueing:
32
+ - Combining labels from different runner types in one runs-on: array, expecting
33
+ any runner matching any label to pick up the job
34
+ - A typo in one label (e.g., "arm64" vs "aarch64") making the full set unmatchable
35
+ - Adding a new label requirement without ensuring at least one runner carries it
36
+ - Using a label that was renamed on the runner registration but not updated in workflows
37
+ - Combining GitHub-hosted runner identifiers with self-hosted labels
38
+ (e.g., [ubuntu-latest, self-hosted]) — GitHub-hosted runners do not carry
39
+ the self-hosted label, so this combination never matches any runner
40
+
41
+ The job queues indefinitely with "Waiting for a runner to pick up this job" and
42
+ never times out automatically unless job timeout-minutes or org-level timeout
43
+ limits are configured. The error message lists all required labels but does not
44
+ indicate which specific label is unmatched.
45
+ fix: |
46
+ Ensure at least one registered runner has EVERY label in the runs-on: array.
47
+ Check Settings > Actions > Runners to verify exact label sets on each runner.
48
+
49
+ For different runner types (e.g., x64 vs ARM), use separate jobs rather than
50
+ a single job with an impossible label combination. For OR semantics across
51
+ runner types, use a matrix strategy.
52
+
53
+ For GitHub-hosted runners, use a single label string (ubuntu-latest,
54
+ windows-latest, macos-latest) not an array.
55
+ fix_code:
56
+ - language: yaml
57
+ label: 'Use only labels that ALL exist on at least one registered runner'
58
+ code: |
59
+ jobs:
60
+ # WRONG: no single runner has both fast-ssd AND arm64 labels
61
+ # build:
62
+ # runs-on: [self-hosted, linux, arm64, fast-ssd]
63
+
64
+ # CORRECT: use only labels that exist together on one runner
65
+ build:
66
+ runs-on: [self-hosted, linux, arm64] # matches a runner with all three
67
+
68
+ # CORRECT for GitHub-hosted: single string label
69
+ test:
70
+ runs-on: ubuntu-latest
71
+ - language: yaml
72
+ label: 'Use matrix to target multiple runner types (OR semantics)'
73
+ code: |
74
+ jobs:
75
+ test:
76
+ strategy:
77
+ matrix:
78
+ runner:
79
+ - ubuntu-latest
80
+ - [self-hosted, linux, arm64]
81
+ runs-on: ${{ matrix.runner }}
82
+ steps:
83
+ - uses: actions/checkout@v4
84
+ - run: make test
85
+ prevention:
86
+ - 'Treat runs-on: arrays as requiring ALL labels on one runner simultaneously — never use them as OR matching'
87
+ - 'Keep self-hosted runner label sets minimal (2-3 labels) to reduce the risk of unmatched combinations'
88
+ - 'Audit all workflow runs-on: references when renaming or removing runner labels — old labels cause indefinite queueing'
89
+ - 'Verify exact label sets in GitHub Settings > Actions > Runners before writing runs-on: arrays'
90
+ - 'Set a job-level timeout-minutes to prevent stuck jobs from blocking runners indefinitely'
91
+ docs:
92
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-where-your-workflow-runs/choosing-the-runner-for-a-job#choosing-self-hosted-runners'
93
+ label: 'Choosing self-hosted runners — label matching behavior (AND semantics)'
94
+ - url: 'https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/using-labels-with-self-hosted-runners'
95
+ label: 'Using labels with self-hosted runners'
96
+ - url: 'https://github.com/orgs/community/discussions/25033'
97
+ label: 'GitHub Community: Self-hosted runner label AND matching — job queues indefinitely'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htekdev/actions-debugger",
3
- "version": "1.0.38",
3
+ "version": "1.0.40",
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",