Skip to content

[eslint-factory] Cover execFileSync in require-execsync-try-catch (throwing child_process sync sibling) #47211

Description

@github-actions

Summary

require-execsync-try-catch (the newest rule, added since the last refiner run) requires execSync(...) calls to be wrapped in try/catch because execSync throws a ChildProcessError on non-zero exit or signal termination. But its throwing sibling execFileSync — which has identical throw-on-failure semantics — is not covered by any rule:

  • require-execsync-try-catch matches only execSync.
  • require-spawnsync-error-check targets spawnSync, which does not throw (it returns { status, error }), so it is the wrong home for execFileSync.

This leaves an unguarded gap: an unwrapped execFileSync that exits non-zero crashes the action with no useful diagnostic — exactly the failure mode the execSync rule was created to prevent.

Grounding in actions/setup/js/**

execFileSync is used in several live (non-test) action scripts, and the maintainers already manually wrap it in try/catch — direct evidence that the invariant matters and that a lint guard would prevent regressions:

  • merge_remote_agent_github_folder.cjs:181,185,194,199,202 — all inside a try block (correctly protected).
  • evaluate_outcomes.cjs:81 — inside try (correctly protected).
  • safeoutputs_cli.cjs:41 — inside try (correctly protected).

A site that is not directly wrapped:

  • build_checkout_manifest.cjs:44 and :48execFileSync("git"/"gh", ...) inside default-arg factory lambdas (options.runGit || ((args) => execFileSync(...))), with no surrounding try. Whether every call site protects these depends on callers; a rule would make the requirement explicit rather than implicit.

All wrapped sites would remain true-negatives under the extended rule; only unprotected execFileSync would be newly flagged.

Proposed change

Cover execFileSync with the same try/catch requirement. Two acceptable shapes — pick whichever fits repo conventions:

  1. Extend require-execsync-try-catch to also match execFileSync. The existing scope-resolution machinery already handles const { execSync } = require("child_process"), cp.execSync(...), const execSync = cp.execSync, and the ESM import { execSync } from "child_process" forms — generalizing the matched-method name from a single "execSync" to a Set(["execSync", "execFileSync"]) is a small change. Emit a method-specific diagnostic (Wrap execFileSync(...) in try/catch ...).
  2. Add a sibling rule require-execfilesync-try-catch — consistent with how require-mkdirsync-try-catch was split out from require-fs-sync-try-catch (one rule per method family). This reuses try-catch-rule-utils (isInsideTryBlock, findEnclosingStatement, buildTryCatchSuggestion).

Acceptance criteria

  • execFileSync(...) (destructured, namespaced cp.execFileSync, aliased const execFileSync = cp.execFileSync, and ESM import { execFileSync }) sourced from child_process / node:child_process is flagged when not inside an enclosing try with a catch handler.
  • execFileSync inside a protective try { ... } catch { ... } is NOT flagged (regression tests mirroring the existing execSync valid cases).
  • execFileSync from a non-child_process module is ignored (scope-resolution parity with the execSync rule).
  • Suggestion wraps the enclosing statement using buildTryCatchSuggestion with an execFileSync-specific TODO/error prefix.
  • Re-verify against the corpus: build_checkout_manifest.cjs:44/48 flagged; merge_remote_agent_github_folder.cjs, evaluate_outcomes.cjs:81, safeoutputs_cli.cjs:41 remain clean.
  • Docs/README note the new coverage; decide explicitly whether execFile (async, callback/promise) is in or out of scope and document it.

Filed by the ESLint Refiner daily review. Grounded statically against non-test .cjs in actions/setup/js/** (no live lint available in this environment).

Generated by 🤖 ESLint Refiner · age00 312 AIC · ⌖ 12.9 AIC · ⊞ 4.6K ·

  • expires on Jul 28, 2026, 10:18 PM UTC-08:00

Metadata

Metadata

Labels

cookieIssue Monster Loves Cookies!eslint

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions