Fix sync exec timeout detection for defaulted option spreads - #54749
Conversation
PR Triage
|
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
Great work on this fix! 🎯 This PR closes a significant gap in the Summary of Changes:
Coverage:
This is ready for review. 🟢
|
PR TriageCategory: Draft. Fixes lint rule detection gap for require-sync-exec-timeout. Small (206/12, 4 files). No CI runs yet. Automated triage — run 32572524009
|
There was a problem hiding this comment.
Pull request overview
Improves sync child-process timeout detection for local wrappers and hardens checkout manifest commands.
Changes:
- Analyzes defaulted options spreads and same-file call sites.
- Adds regression coverage.
- Applies configured timeouts to
gitandghlookups.
Show a summary per file
| File | Description |
|---|---|
eslint-factory/src/rules/require-sync-exec-timeout.ts |
Adds wrapper call-site analysis. |
eslint-factory/src/rules/require-sync-exec-timeout.test.ts |
Adds spread-wrapper cases. |
actions/setup/js/build_checkout_manifest.cjs |
Adds command timeouts. |
actions/setup/js/build_checkout_manifest.test.cjs |
Verifies timeout propagation. |
Review details
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
Suppressed comments (2)
eslint-factory/src/rules/require-sync-exec-timeout.ts:234
- The parameter default is being treated as if it applied to every invocation. In JavaScript, a caller such as
runGit(args, {})replaces a default{ timeout: 5000 }, so this early return misses a real timeout-free call; an omitted argument should instead inspect the default. Evaluate the actual argument per direct call and use the default object only when that call omits it or passes an unshadowedundefined.
if (hasPositiveTimeoutProperty(defaultObject.objectExpression)) return true;
eslint-factory/src/rules/require-sync-exec-timeout.ts:240
- The binding can be reassigned, but calls after that reassignment are still attributed to this wrapper. For example,
let runGit = wrapper; runGit = external; runGit(args, {})makes this rule report the original wrapper even though it is never invoked. Keep this analysis conservative by rejecting bindings with non-initializer writes before collecting their direct calls.
const binding = getFunctionBindingVariable(containingFunction, sourceCode);
if (!binding) return null;
const directCalls = getDirectCalls(binding);
- Files reviewed: 4/4 changed files
- Comments generated: 1
- Review effort level: Balanced
| function callSiteArgumentSuppliesTimeout(argument: TSESTree.CallExpressionArgument | undefined, sourceCode: TSESLint.SourceCode): boolean { | ||
| if (!argument) return false; | ||
| if (argument.type === AST_NODE_TYPES.ObjectExpression) return objectArgumentSuppliesTimeout(argument); |
require-sync-exec-timeouttreated any options-object spread as sufficient, missing same-file wrappers where a defaulted options parameter was spread intoexecFileSyncwithout any caller-provided timeout.ESLint rule
execOptions = {}.timeout.Regression coverage
Manifest hardening
build_checkout_manifest.cjsgit and gh lookups.