Skip to content

feat(hooks): bound every hook with a timeout and close its stdin - #1300

Merged
BryanFRD merged 2 commits into
mainfrom
feat/hook-timeout
Oct 10, 2026
Merged

BryanFRD merged 2 commits into
mainfrom
feat/hook-timeout

Conversation

@BryanFRD

Copy link
Copy Markdown
Contributor

Closes #801

A hook that never returned held the release, and .git/ferrflow.lock, until the CI job died on its wall-clock limit, with no output in the non-verbose path to say which hook it was.

  • timeout in hooks, in seconds, at workspace or package level (package wins), default 900. It sits next to onFailure and resolves the same way, through a new HookPolicy that run_hook now takes instead of a bare OnFailure.
  • On timeout the hook is killed with everything it started (own process group plus kill -KILL -<pgid> on Unix, taskkill /T /F on Windows) and reported as hook [x] failed (timed out after Ns), so onFailure applies as usual. onError keeps forcing continue.
  • stdin is /dev/null for every hook, which turns the npm login / gpg passphrase / git credential prompt cases into an immediate failure.
  • Heartbeat: a hook still running prints [point] still running after Ns every minute. Output is captured on separate threads, so a chatty hook cannot fill a pipe and deadlock the wait.
  • The process handling lives in src/hooks/runner/process.rs; runner.rs keeps the hook logic.

Schema (schema/ and its mirror under docs/site/data/schema/) and the EN/FR config docs describe timeout and the closed stdin.

One trade-off: on Unix the hook now runs in its own process group so the whole tree can be killed. A Ctrl+C on the terminal running ferrflow release therefore no longer reaches the hook directly. In CI that does not matter; interactively the hook is still bounded by its timeout.

Tests: a hook past its timeout is killed and reported with E6001 well before its own sleep ends; continue on a timed-out hook keeps the release going; a hook reading stdin gets EOF; on Unix, a background child started by the hook does not outlive the kill. Plus timeout resolution (default, workspace, package override). Full suite passes locally.

@ferrfleet ferrfleet Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One blocking finding: on unix, kill_tree shells out to kill instead of calling libc::kill. The repo already depends on libc and uses it in lock.rs, and if the binary is missing the hook's children survive. There's a suggestion inline. Three nits: the timeout doesn't cover pipe draining after the hook exits, Ctrl+C now leaves hooks orphaned, and timeout = 0 gets past serde. Apart from that the timeout resolution, the closed stdin and the tests look right.

Comment thread src/hooks/runner/process.rs Outdated
Comment thread src/hooks/runner/process.rs Outdated
Comment thread src/hooks/runner/process.rs
Comment thread src/config/types.rs Outdated

@ferrfleet ferrfleet Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bf118d3 fixes all four earlier findings, including the blocking one: kill_tree now uses libc::kill on the group, the drain respects the deadline, timeout is NonZeroU64, and the Ctrl+C trade-off is documented. One new nit: the docs say a hook orphaned by Ctrl+C is still bounded by its timeout. It isn't, because the deadline dies with FerrFlow.

Comment thread docs/site/docs-en/configuration/config-file.md
@BryanFRD
BryanFRD merged commit 932db1e into main Oct 10, 2026
33 checks passed
@BryanFRD
BryanFRD deleted the feat/hook-timeout branch October 10, 2026 09:10
ferrflow Bot added a commit that referenced this pull request Oct 10, 2026
## [7.29.0] - 2026-10-10

### Features

- feat(hooks): bound every hook with a timeout and close its stdin (#1300)

### Bug Fixes

- fix(docs): say an orphaned hook is no longer bounded after Ctrl+C (#1302)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(hooks): hooks have no timeout — a hung hook hangs the release indefinitely

1 participant