@htekdev/actions-debugger 1.0.29 → 1.0.30

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,78 @@
1
+ id: 'known-unsolved-030'
2
+ title: 'core.getInput cannot distinguish unset input from explicitly-empty input'
3
+ category: known-unsolved
4
+ severity: limitation
5
+ tags:
6
+ - toolkit
7
+ - core-getInput
8
+ - composite-action
9
+ - empty-string
10
+ - null-input
11
+ - fork-secrets
12
+ patterns:
13
+ - regex: 'core\.getInput\('
14
+ flags: 'i'
15
+ error_messages:
16
+ - 'No way to detect if input was provided vs set to empty string'
17
+ root_cause: |
18
+ The `core.getInput(name)` function in `@actions/core` always returns an empty string ('')
19
+ when an input is either not provided by the caller or explicitly set to the empty string.
20
+ There is no `core.hasInput(name)` API or other mechanism to distinguish these two cases.
21
+
22
+ This creates several practical problems for action authors:
23
+ - A required input set to '' passes the required: true check in getInput but is semantically absent
24
+ - Fork pull requests inject secrets as empty strings (secrets are unavailable); an action cannot tell
25
+ if a secret input was omitted vs provided-as-empty-because-fork
26
+ - Composite action callers cannot express "I intentionally leave this blank" vs "I don't provide this at all"
27
+ - YAML null or ~ values (e.g., with: my_val: ~) are coerced to '' by the runner before the action sees them
28
+
29
+ Upstream GitHub toolkit issue #940 has been open since 2022 with 22 upvotes and no fix planned.
30
+ fix: |
31
+ No direct fix exists — there is no core.hasInput() API. Workarounds depend on the use case:
32
+ - For sentinel detection: document a convention like 'none' or '__unset__' as the explicit absent value
33
+ and check getInput('x') === 'none'
34
+ - For fork secret detection: check github.event.pull_request.head.repo.fork == true and gate on that
35
+ rather than on whether the secret is empty
36
+ - For optional inputs: provide a well-documented default value in action.yml so callers always get a
37
+ predictable non-empty string when they omit the input
38
+ - For composite actions: use ${{ inputs.my_input != '' }} in if: conditions, documenting that
39
+ callers must pass a non-empty string to opt in
40
+ fix_code:
41
+ - language: yaml
42
+ label: 'Use sentinel value convention to detect absent input'
43
+ code: |
44
+ # action.yml — declare sentinel default
45
+ inputs:
46
+ deploy_env:
47
+ description: 'Target environment (leave blank to skip deployment)'
48
+ required: false
49
+ default: '__unset__'
50
+
51
+ # In composite action steps
52
+ steps:
53
+ - name: Deploy
54
+ if: ${{ inputs.deploy_env != '__unset__' && inputs.deploy_env != '' }}
55
+ run: echo "Deploying to ${{ inputs.deploy_env }}"
56
+ - language: yaml
57
+ label: 'Detect fork PR to guard secret-gated steps instead of empty-check'
58
+ code: |
59
+ steps:
60
+ - name: Publish (skip on fork PRs)
61
+ if: >-
62
+ ${{ github.event_name != 'pull_request' ||
63
+ github.event.pull_request.head.repo.full_name == github.repository }}
64
+ run: echo "$NPM_TOKEN" | npm login --registry https://registry.npmjs.org
65
+ env:
66
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
67
+ prevention:
68
+ - 'Document in action.yml that empty string and absent are treated identically by core.getInput'
69
+ - 'Use a non-empty sentinel default value (e.g. __unset__) instead of relying on empty-check logic'
70
+ - 'Never gate fork-secret logic on secret emptiness — use fork-detection via event context instead'
71
+ - 'For required inputs that must be non-empty, add an explicit validation step that fails with a helpful message'
72
+ docs:
73
+ - url: 'https://github.com/actions/toolkit/issues/940'
74
+ label: 'actions/toolkit#940: Impossible to detect unset inputs from inputs set as empty string'
75
+ - url: 'https://github.com/actions/toolkit/tree/main/packages/core'
76
+ label: 'actions/toolkit core package — getInput API'
77
+ - url: 'https://docs.github.com/en/actions/sharing-automations/creating-actions/metadata-syntax-for-github-actions#inputs'
78
+ label: 'GitHub Docs: Action metadata — inputs'
@@ -0,0 +1,90 @@
1
+ id: 'runner-environment-083'
2
+ title: 'Actions Runner Controller pods intermittently fail with "A task was cancelled" during large matrix jobs'
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - arc
7
+ - kubernetes
8
+ - matrix
9
+ - task-cancelled
10
+ - pod-eviction
11
+ - self-hosted
12
+ - keda
13
+ patterns:
14
+ - regex: 'A task was cancell?ed\.'
15
+ flags: 'i'
16
+ - regex: 'The operation was canceled\.'
17
+ flags: 'i'
18
+ error_messages:
19
+ - 'Error: A task was cancelled.'
20
+ - 'Error: The operation was canceled.'
21
+ root_cause: |
22
+ When using Actions Runner Controller (ARC) to run GitHub Actions on Kubernetes, ephemeral
23
+ runner pods can be evicted or preempted mid-job by the Kubernetes scheduler, producing
24
+ a "A task was cancelled" or "The operation was canceled" error with no application-level
25
+ log output before the failure.
26
+
27
+ Common causes:
28
+ - Kubernetes resource pressure: if a node is under memory or CPU pressure, the kubelet
29
+ evicts lower-priority pods. ARC runner pods have no PriorityClass by default and are
30
+ among the first to be evicted
31
+ - Node autoscaling: Cluster Autoscaler draining nodes for scale-down triggers eviction of
32
+ runner pods that have been running longer than the scale-down grace period
33
+ - KEDA queue-length scaling: KEDA scaling down the runner Deployment while jobs are
34
+ in-flight terminates runner pods before jobs complete
35
+ - OOM kills: matrix jobs that each consume significant memory can saturate node memory,
36
+ causing the OOM killer to terminate runner pods
37
+
38
+ The issue is especially common with large matrix builds (10+ parallel jobs) because the
39
+ aggregate resource demand spike can trigger autoscaler or eviction behavior. Because ARC
40
+ runner pods are ephemeral and have no restart policy, the job is permanently failed when
41
+ the pod is evicted.
42
+ fix: |
43
+ Assign a high PriorityClass to ARC runner pods so the Kubernetes scheduler avoids evicting
44
+ them during resource pressure. Also set adequate resource requests/limits and configure
45
+ terminationGracePeriodSeconds to at least the expected maximum job duration.
46
+ fix_code:
47
+ - language: yaml
48
+ label: 'Create a high-priority PriorityClass for ARC runner pods'
49
+ code: |
50
+ apiVersion: scheduling.k8s.io/v1
51
+ kind: PriorityClass
52
+ metadata:
53
+ name: github-runner-high
54
+ value: 1000000
55
+ globalDefault: false
56
+ description: 'High priority for GitHub Actions runner pods to prevent eviction'
57
+ - language: yaml
58
+ label: 'Reference PriorityClass and set resource limits in ARC AutoscalingRunnerSet values'
59
+ code: |
60
+ # helm values for actions-runner-controller AutoscalingRunnerSet chart
61
+ template:
62
+ spec:
63
+ priorityClassName: github-runner-high
64
+ # Allow jobs up to 1 hour to finish before pod is force-terminated
65
+ terminationGracePeriodSeconds: 3600
66
+ containers:
67
+ - name: runner
68
+ resources:
69
+ requests:
70
+ memory: '2Gi'
71
+ cpu: '500m'
72
+ limits:
73
+ memory: '4Gi'
74
+ cpu: '2000m'
75
+ prevention:
76
+ - 'Assign a PriorityClass to ARC runner pods to prevent eviction under resource pressure'
77
+ - 'Set terminationGracePeriodSeconds to at least the expected maximum single-job duration'
78
+ - 'Set explicit resource requests and limits to avoid OOM kills during large matrix builds'
79
+ - 'Configure KEDA scale-down stabilization windows to prevent scaling down while jobs run'
80
+ - 'Monitor node resource utilization and right-size cluster nodes for peak matrix concurrency'
81
+ - 'Enable PodDisruptionBudgets for runner workloads to reduce involuntary evictions during node drains'
82
+ docs:
83
+ - url: 'https://github.com/actions/runner/issues/3819'
84
+ label: 'actions/runner#3819: A lot of random "A task was cancelled" errors'
85
+ - url: 'https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/'
86
+ label: 'Kubernetes: Pod Priority and Preemption'
87
+ - url: 'https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/autoscaling-with-self-hosted-runners'
88
+ label: 'GitHub Docs: Autoscaling with self-hosted runners'
89
+ - url: 'https://github.com/actions/actions-runner-controller'
90
+ label: 'Actions Runner Controller (ARC) GitHub repository'
@@ -0,0 +1,83 @@
1
+ id: 'runner-environment-084'
2
+ title: 'Bash/sh script handler does not quote script path — fails when path contains spaces'
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - bash
7
+ - shell
8
+ - path-spaces
9
+ - job-hooks
10
+ - self-hosted
11
+ - macos
12
+ - tart-vm
13
+ patterns:
14
+ - regex: 'ACTIONS_RUNNER_HOOK_JOB_(?:STARTED|COMPLETED)'
15
+ flags: 'i'
16
+ - regex: 'bash.*No such file or directory'
17
+ flags: 'i'
18
+ error_messages:
19
+ - 'bash: /Volumes/My Shared Files/hook.sh: No such file or directory'
20
+ - 'sh: /path with spaces/script.sh: not found'
21
+ - '/path/with: not found'
22
+ root_cause: |
23
+ The GitHub Actions runner bash/sh script handler does not quote the script path
24
+ placeholder when building the shell invocation. The default bash arguments in
25
+ ScriptHandlerHelpers.cs are:
26
+ --noprofile --norc -e -o pipefail {0}
27
+ When {0} is replaced with a path containing spaces — e.g.,
28
+ /Volumes/My Shared Files/hook.sh
29
+ bash receives the path as two separate arguments due to word splitting:
30
+ bash --noprofile --norc -e -o pipefail /Volumes/My Shared Files/hook.sh
31
+ This causes a "No such file or directory" error for the first word-split token.
32
+
33
+ By contrast, the PowerShell and cmd handlers correctly quote the path:
34
+ pwsh: -command "& '{0}'"
35
+ powershell: -command ". '{0}'"
36
+ cmd: /D /E:ON /V:OFF /S /C "CALL "{0}""
37
+ Only bash and sh are affected (runner#4404, unresolved as of June 2026).
38
+
39
+ Practical impact:
40
+ - Job hooks (ACTIONS_RUNNER_HOOK_JOB_STARTED, ACTIONS_RUNNER_HOOK_JOB_COMPLETED) placed in
41
+ shared directories with spaces — common on macOS Tart VMs mounted at /Volumes/My Shared Files/
42
+ - Self-hosted runner workspaces on paths containing spaces (less common but possible)
43
+ - Any run: step using a working-directory with spaces in the resolved path
44
+ fix: |
45
+ Ensure hook script paths and runner working directories never contain spaces.
46
+ On macOS Tart VMs, place hook scripts under a path without spaces (e.g., /Users/runner/hooks/).
47
+
48
+ Use a wrapper script at a space-free path that exec-delegates to the actual script if
49
+ it must reside under a shared mount with spaces in its path.
50
+
51
+ Monitor actions/runner#4404 for the upstream fix and upgrade when a patched runner ships.
52
+ fix_code:
53
+ - language: yaml
54
+ label: 'Configure job hook at a space-free path (environment variable)'
55
+ code: |
56
+ # In the runner .env file (e.g., /home/runner/actions-runner/.env):
57
+ # Point hook variables to a path WITHOUT spaces
58
+ ACTIONS_RUNNER_HOOK_JOB_STARTED=/Users/runner/hooks/job-started.sh
59
+ ACTIONS_RUNNER_HOOK_JOB_COMPLETED=/Users/runner/hooks/job-completed.sh
60
+ #
61
+ # Avoid paths like:
62
+ # /Volumes/My Shared Files/hooks/ ← spaces cause bash word-splitting error
63
+ - language: yaml
64
+ label: 'Wrapper script at space-free path delegates to actual hook in shared mount'
65
+ code: |
66
+ #!/bin/bash
67
+ # /Users/runner/hooks/job-started.sh (space-free path — registered as the hook)
68
+ #
69
+ # Exec-delegates to the actual hook that lives under a shared volume with spaces.
70
+ # Using exec preserves exit codes and avoids a subprocess layer.
71
+ exec "/Volumes/My Shared Files/hooks/actual-job-started.sh" "$@"
72
+ prevention:
73
+ - 'Never place runner hooks, workspace paths, or working-directories in paths containing spaces'
74
+ - 'On macOS Tart VMs, configure shared mounts to use space-free mount points (e.g., /Volumes/SharedFiles)'
75
+ - 'Test runner hook invocations explicitly on macOS or Windows deployments with shared mounts'
76
+ - 'Watch actions/runner#4404 for the upstream fix; upgrade the runner version when it ships'
77
+ docs:
78
+ - url: 'https://github.com/actions/runner/issues/4404'
79
+ label: 'actions/runner#4404: Bash script handler does not quote script path — breaks with spaces'
80
+ - url: 'https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/running-scripts-before-or-after-a-job'
81
+ label: 'GitHub Docs: Running scripts before or after a job (hooks)'
82
+ - url: 'https://github.com/actions/runner/blob/main/src/Runner.Worker/Handlers/ScriptHandlerHelpers.cs'
83
+ label: 'Runner source: ScriptHandlerHelpers.cs (unquoted bash path template)'
@@ -0,0 +1,109 @@
1
+ id: 'runner-environment-082'
2
+ title: 'Self-hosted runner gets stuck "Waiting for a runner to pick up this job" between jobs in the same workflow'
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - self-hosted
7
+ - runner
8
+ - multi-job
9
+ - queued
10
+ - stuck
11
+ - windows
12
+ - auto-update
13
+ patterns:
14
+ - regex: 'Waiting for a runner to pick up this job'
15
+ flags: 'i'
16
+ error_messages:
17
+ - 'Waiting for a runner to pick up this job...'
18
+ root_cause: |
19
+ After completing the first job in a multi-job workflow, a self-hosted runner sometimes
20
+ fails to pick up subsequent jobs in the same workflow run. The subsequent jobs remain
21
+ in queued status indefinitely, with no timeout and no automatic retry.
22
+
23
+ Common root causes:
24
+ - Runner auto-update race condition: when the runner auto-updates between jobs, the post-job
25
+ cleanup of the first job can leave the runner in a state where it reports idle to the
26
+ broker but cannot accept new job messages
27
+ - Windows service restart latency: on Windows hosts, if the runner was auto-updated or
28
+ the service restarted between jobs, the new process may not have fully re-registered
29
+ with the GitHub Actions broker before the second job is dispatched
30
+ - JIT token expiry: in ephemeral/JIT runner setups, the registration token can expire
31
+ between jobs if the first job runs for a long time, and the runner cannot re-register
32
+ - Broker disconnect: a transient network interruption between jobs severs the long-poll
33
+ connection; the runner reconnects but the already-dispatched job message is missed
34
+
35
+ Manually cancelling and re-running the workflow, or restarting the runner service,
36
+ resolves the issue immediately, confirming the runner is functional but lost broker contact.
37
+ fix: |
38
+ Immediate workaround: cancel the stuck workflow run and re-trigger it, or restart the
39
+ runner service:
40
+ Windows: Restart-Service "actions.runner.*"
41
+ Linux: sudo systemctl restart actions.runner.*.<name>.service
42
+
43
+ Long-term fixes:
44
+ - Disable runner auto-update during active workflows by setting RUNNER_ALLOW_RUNASROOT
45
+ environment variable and pinning a specific runner version
46
+ - Use ephemeral runners (--ephemeral flag) so each job dispatches a fresh runner that
47
+ registers anew with the broker, eliminating the between-job reconnect window
48
+ - Split long workflows into separate workflow files triggered via workflow_run or
49
+ repository_dispatch so each workflow gets an independent runner session
50
+ - On Windows: ensure the runner service account has the "Log on as a service" right
51
+ and that antivirus is not blocking runner binary updates
52
+ fix_code:
53
+ - language: yaml
54
+ label: 'Use ephemeral runners to avoid stuck-between-jobs on self-hosted'
55
+ code: |
56
+ # When configuring the runner, use the --ephemeral flag:
57
+ # ./config.sh --url https://github.com/OWNER/REPO --token TOKEN --ephemeral
58
+ #
59
+ # For ARC (Actions Runner Controller), set runnerScaleSetSettings:
60
+ # spec:
61
+ # template:
62
+ # metadata:
63
+ # labels:
64
+ # ephemeral: 'true'
65
+ #
66
+ # Each job gets a freshly-registered runner; no between-job broker reconnect issues.
67
+ - language: yaml
68
+ label: 'Split multi-job workflow into two workflows triggered by workflow_run'
69
+ code: |
70
+ # phase1.yml
71
+ on:
72
+ push:
73
+ jobs:
74
+ build:
75
+ runs-on: [self-hosted, linux]
76
+ steps:
77
+ - uses: actions/checkout@v4
78
+ - run: make build
79
+ - uses: actions/upload-artifact@v4
80
+ with:
81
+ name: build-output
82
+ path: dist/
83
+
84
+ # phase2.yml (fresh runner registration — no stuck-between-jobs risk)
85
+ on:
86
+ workflow_run:
87
+ workflows: [phase1.yml]
88
+ types: [completed]
89
+ jobs:
90
+ test:
91
+ if: ${{ github.event.workflow_run.conclusion == 'success' }}
92
+ runs-on: [self-hosted, linux]
93
+ steps:
94
+ - uses: actions/download-artifact@v4
95
+ with:
96
+ name: build-output
97
+ - run: make test
98
+ prevention:
99
+ - 'Use ephemeral runners (--ephemeral) to ensure each job gets a fresh broker registration'
100
+ - 'Configure the runner service with Restart=on-failure to auto-recover from crashes between jobs'
101
+ - 'Pin runner versions and suppress auto-updates in production to prevent mid-workflow upgrades'
102
+ - 'Monitor for stuck runs via the GitHub Actions API and alert or auto-cancel them'
103
+ docs:
104
+ - url: 'https://github.com/actions/runner/issues/3609'
105
+ label: 'actions/runner#3609: Self-hosted runner stuck on "Waiting for a runner to pick up this job"'
106
+ - url: 'https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners'
107
+ label: 'GitHub Docs: About self-hosted runners'
108
+ - url: 'https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/autoscaling-with-self-hosted-runners'
109
+ label: 'GitHub Docs: Autoscaling with self-hosted runners'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htekdev/actions-debugger",
3
- "version": "1.0.29",
3
+ "version": "1.0.30",
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",