vendor: actions/checkout@v6.0.2 with timeout-minutes input#129
vendor: actions/checkout@v6.0.2 with timeout-minutes input#129tenstorrent-github-bot wants to merge 5 commits into
Conversation
Source: https://github.com/actions/checkout/tree/de0fac2e4500dabe0009e67214ff5f5447ce83dd No modifications — this commit is a clean copy of upstream to make the following diff easy to review.
Adds a `timeout-minutes` input (default: 20) that imposes a hard wall-clock
limit on every git subprocess. When the timeout fires the child process is
sent SIGTERM; if it is still alive 5 s later it receives SIGKILL.
This is implemented via `child_process.spawn` rather than `Promise.race`
over `@actions/exec`. Promise.race rejects the outer promise on timeout but
leaves the underlying OS process running — making it useless as a guard
against a hung git fetch.
Changed files:
action.yml — new timeout-minutes input (default: 20)
src/git-source-settings.ts — new timeoutMs field on IGitSourceSettings
src/input-helper.ts — parse and validate timeout-minutes
src/git-source-provider.ts — pass timeoutMs to createCommandManager
src/git-command-manager.ts — store timeoutMs; execGitWithTimeout uses
child_process.spawn + SIGTERM/SIGKILL
dist/index.js — rebuilt
tenstorrent-github-bot
left a comment
There was a problem hiding this comment.
Review of commit 2: timeout-minutes input
Overall this is a solid feature addition. The core approach — bypass @actions/exec and use child_process.spawn directly to get timeout control — is reasonable since @actions/exec doesn't expose timeout support.
However, there are two real bugs that should be fixed before merging, plus a couple of robustness improvements worth considering.
Bugs (must fix)
- Inner SIGKILL timer leaks — the 5-second escalation timer inside the timeout callback is never cleared when the process exits. This keeps the Node event loop alive and fires
kill()on a dead PID. Infinitybypasses validation —parseFloat('Infinity')passes the> 0check, andsetTimeout(fn, Infinity)coerces to 0 in Node.js, making every git command time out immediately.
Robustness (nice to have)
- Partial-line delivery for
stdline/errline— splitting on\nperdataevent doesn't guarantee line-aligned chunks. The original@actions/execuses internal line buffering. Acceptable for now sincestdline/errlineare only used for progress output, but worth a comment. - Windows:
SIGTERMis a no-op for non-Node processes —child.kill('SIGTERM')does nothing togit.exeon Windows. The process only dies when the SIGKILL fires 5s later. Minor since GHA runners are mostly Linux, but the 5s delay is unnecessary on Windows.
- Store inner SIGKILL timer and clear it in close/error handlers to prevent event loop leaks and stale kill calls - Reject Infinity in timeout-minutes validation (!isFinite check) - Improve timeout error message to show both seconds and minutes - Add NOTE comment about partial-line delivery limitation in stdline Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
tenstorrent-github-bot
left a comment
There was a problem hiding this comment.
Re-review of commit 3 (2b94e280) — Follow-up Pass
All items from the first review have been addressed. The killTimer cleanup, !isFinite() guard, improved error message, and partial-line comment are all good.
After a thorough second pass, I found one real bug and one minor inconsistency. Everything else checks out.
Verified Correct
- Timer race conditions:
killTimeris assigned inside the outertimercallback. JavaScript's single-threaded event loop guarantees the entire callback (including thekillTimer = setTimeout(...)assignment) runs to completion before any I/O event (likeclose) can fire. SokillTimeris always assigned beforeclosecan check it. ✅ timedOutflag race: Same event loop guarantee — eitherclearTimeout(timer)inclosecancels the outer timer before it fires, or the outer timer fires first and setstimedOut = true. Both paths are deterministic. No race. ✅!isFinite(timeoutMinutes)validation: Correctly blocksInfinityand-Infinity(which pass!isNaNand> 0checks). ✅dist/index.jssync: Verified the compiled JS matches the TS source for all changes (killTimer, isFinite, error message, comment). ✅envtype cast:env as NodeJS.ProcessEnvis correct — both are{[key: string]: string | undefined}. ✅action.ymldefault vsinput-helper.tsfallback: Both use'20'. The|| '20'in TS is redundant since GHA injects the YAML default, but it's a fine defensive pattern and not worth removing. ✅spawnstdio:cp.spawndefaults tostdio: 'pipe'for all three streams, sochild.stdoutandchild.stderrare always Readable streams. No null-check needed. ✅
Summary
One real issue (child.killed semantics), one nit (missing errline comment). Neither is a merge blocker — the child.killed issue is pre-existing from upstream actions/checkout, and git processes do respond to SIGTERM on Linux. But worth noting for awareness.
LGTM — good to merge. 🧠
…e partial-line note - Replace `!child.killed` guard with `process.kill(pid, 0)` to correctly detect whether the process is still alive before escalating to SIGKILL. `child.killed` only reflects whether `.kill()` was called, not whether the process actually terminated. - Add partial-line limitation NOTE comment to the errline handler, matching the existing comment on the stdline handler. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Upstream actions/checkout has trailing whitespace and missing end-of-file newlines that conflict with our pre-commit rules. Exclude the entire vendored directory to keep it as close to upstream as possible.
vmilosevic
left a comment
There was a problem hiding this comment.
What is the purpose of this change?
Summary
Vendors
actions/checkout@de0fac2e(v6.0.2) under.github/actions/checkout/and adds atimeout-minutesinput (default: 20 min) that hard-kills hung git subprocesses.Why vendor?
timeout-minuteson steps inside a composite action is silently ignored by the GitHub runner (actions/runner#1979). The only way to enforce a wall-clock limit on git fetch/clone calls is to do it inside the action's own TypeScript code.Why not
Promise.race?Promise.racerejects the outer promise when the timer fires but the underlyingchild_processspawned by@actions/execkeeps running in the OS — useless as a hung-fetch guard. This implementation useschild_process.spawndirectly, sendsSIGTERMon timeout, and escalates toSIGKILLafter 5 s.Commits
• Commit 1: verbatim copy of
actions/checkout@de0fac2e— no modifications, easy to diff against upstream• Commit 2: adds
timeout-minutesinput wired throughIGitSourceSettings→GitCommandManager.execGitWithTimeoutUsage