You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
prefer-actions-exec-over-child-process targets child_process calls used for output capture (exec, execSync, execFile, execFileSync) and deliberately excludes spawn/spawnSync, reasoning (per the rule's own source comments) that spawn-family APIs are for "long-running, detached, or interactively-streamed" processes that @actions/exec has no equivalent for.
That rationale doesn't hold for how spawnSync is actually used in this codebase: it's used synchronously, purely to capture git command output (stdout/stderr/status), in exactly the same shape as the execFileSync calls the rule already flags elsewhere. OUTPUT_CAPTURING_METHODS in the rule source is new Set(["exec", "execSync", "execFile", "execFileSync"]) — spawnSync is simply never checked, so these call sites are a silent false negative rather than an intentional exemption.
Grounded evidence
Live call sites (both inside github-script modules, both output-capturing)
This function's own doc comment even says "Safely execute git command using spawnSync with args array" — it is functionally identical to the execFileSync pattern the rule already flags (synchronous, blocking, captures stdout/stderr/exit status, then throws on non-zero).
Same pattern: synchronous git invocation for output capture, no streaming/detached/long-running behavior involved.
Both files carry the /// <reference types="@actions/github-script" /> marker the rule uses to gate on @actions/exec availability (isGitHubScriptModule), so both are squarely in-scope for the rule's intended domain — they're just missed because spawnSync isn't in the tracked method set.
Why this matters
The rule's exclusion of spawn/spawnSync is a blanket method-name exemption, not a behavior-based one. It doesn't distinguish "spawnSync used for long-running/streaming work" (a legitimate exemption) from "spawnSync used exactly like execFileSync, for one-shot synchronous output capture" (the rule's stated target). As written, anyone can dodge this diagnostic entirely just by picking spawnSync over execFileSync — same functionality, no lint signal.
Acceptance criteria
Extend detection to spawnSync (and spawn when its result is used synchronously / awaited in a way that captures output, if such a pattern exists) using the existing resolveChildProcessOutputMethodBinding/resolveChildProcessOutputMethod machinery, OR add a narrower heuristic: flag spawnSync calls whose result is used to read .stdout/.stderr/.status (i.e., genuinely used for output capture) while still exempting spawn/spawnSync invocations that only check .pid, attach .on(...) listeners, or otherwise indicate a long-running/streamed process.
Add test cases mirroring git_helpers.cjs's execGitSync shape (spawnSync + destructured result.stdout/result.status handling) as an "invalid" case, and a genuine long-running spawn(...) with event-listener usage (see trace_graders.cjs's sidecar spawn(process.execPath, [serverPath], {...})) as a "valid" (unflagged) case to lock in the boundary.
Re-run the rule statically (via Grep, since lint can't execute in this sandbox) against git_helpers.cjs:131 and apply_samples.cjs:99-100 to confirm both now report preferActionsExecSyncContext/preferActionsExec as appropriate.
Overview
prefer-actions-exec-over-child-processtargetschild_processcalls used for output capture (exec,execSync,execFile,execFileSync) and deliberately excludesspawn/spawnSync, reasoning (per the rule's own source comments) that spawn-family APIs are for "long-running, detached, or interactively-streamed" processes that@actions/exechas no equivalent for.That rationale doesn't hold for how
spawnSyncis actually used in this codebase: it's used synchronously, purely to capture git command output (stdout/stderr/status), in exactly the same shape as theexecFileSynccalls the rule already flags elsewhere.OUTPUT_CAPTURING_METHODSin the rule source isnew Set(["exec", "execSync", "execFile", "execFileSync"])—spawnSyncis simply never checked, so these call sites are a silent false negative rather than an intentional exemption.Grounded evidence
Live call sites (both inside github-script modules, both output-capturing)
actions/setup/js/git_helpers.cjs:131—execGitSync():This function's own doc comment even says "Safely execute git command using spawnSync with args array" — it is functionally identical to the
execFileSyncpattern the rule already flags (synchronous, blocking, capturesstdout/stderr/exit status, then throws on non-zero).actions/setup/js/apply_samples.cjs:99-100:Same pattern: synchronous git invocation for output capture, no streaming/detached/long-running behavior involved.
Both files carry the
/// <reference types="@actions/github-script" />marker the rule uses to gate on@actions/execavailability (isGitHubScriptModule), so both are squarely in-scope for the rule's intended domain — they're just missed becausespawnSyncisn't in the tracked method set.Why this matters
The rule's exclusion of spawn/spawnSync is a blanket method-name exemption, not a behavior-based one. It doesn't distinguish "spawnSync used for long-running/streaming work" (a legitimate exemption) from "spawnSync used exactly like execFileSync, for one-shot synchronous output capture" (the rule's stated target). As written, anyone can dodge this diagnostic entirely just by picking
spawnSyncoverexecFileSync— same functionality, no lint signal.Acceptance criteria
spawnSync(andspawnwhen its result is used synchronously / awaited in a way that captures output, if such a pattern exists) using the existingresolveChildProcessOutputMethodBinding/resolveChildProcessOutputMethodmachinery, OR add a narrower heuristic: flagspawnSynccalls whose result is used to read.stdout/.stderr/.status(i.e., genuinely used for output capture) while still exemptingspawn/spawnSyncinvocations that only check.pid, attach.on(...)listeners, or otherwise indicate a long-running/streamed process.git_helpers.cjs'sexecGitSyncshape (spawnSync + destructuredresult.stdout/result.statushandling) as an "invalid" case, and a genuine long-runningspawn(...)with event-listener usage (seetrace_graders.cjs's sidecarspawn(process.execPath, [serverPath], {...})) as a "valid" (unflagged) case to lock in the boundary.git_helpers.cjs:131andapply_samples.cjs:99-100to confirm both now reportpreferActionsExecSyncContext/preferActionsExecas appropriate.References:
Warning
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
api.anthropic.comTo allow these domains, add them to the
network.allowedlist in your workflow frontmatter:See Network Configuration for more information.