Skip to content

Reject empty supervised executables before spawn (#314) - #315

Merged
peters merged 2 commits into
mainfrom
fix/314-reject-empty-executable
Sep 17, 2026
Merged

peters merged 2 commits into
mainfrom
fix/314-reject-empty-executable

Conversation

@peters

@peters peters commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Reject a zero-byte main executable before surge-supervisor spawns it
  • Exit with an actionable invalid/corrupt-executable error instead of logging successful child exits and retrying forever
  • When a pending restart handoff is present, keep it pending_restart with restart handoff invalid executable and do not mark supervisor restart confirmed
  • Keep valid shebang-script and clean-exit restart behavior

Behavior impact

On Linux, Unix command launch treats a zero-byte executable as an empty shell program. Command::spawn succeeds, the child exits 0 immediately, and the supervisor retried every two seconds indefinitely.

The supervisor now fails closed before spawn. A later spawn of an empty replacement executable (for example after an update swap) also exits the supervisor instead of looping. Valid non-empty scripts that exit 0 still restart with the existing backoff.

A general immediate-exit circuit breaker was considered and not added: clean_child_exit_triggers_restart_in_steady_state encodes the current contract that a valid child which exits 0 is relaunched.

Validation

  • cargo fmt --all -- --check
  • ./scripts/check-version-sync.sh
  • ./scripts/check-maintainability.sh
  • RUSTFLAGS="-D warnings" cargo test --workspace
  • cargo clippy --all-targets --all-features -- -D warnings
  • cargo clippy --workspace --lib --bins --examples -- -D warnings -D clippy::unwrap_used -D clippy::expect_used
  • dotnet format dotnet/Surge.slnx --verify-no-changes
  • dotnet test dotnet/Surge.slnx --configuration Release (59 passed)

Fixes #314

Unix spawn treats a zero-byte +x file as an empty shell program, so the
supervisor logged successful exits and retried forever. Fail closed
before spawn and keep pending restart handoff from converging.

Fixes #314
Copilot AI balanced review requested due to automatic review settings September 17, 2026 07:38
@peters peters added bug Something isn't working rust Pull requests that update rust code labels Sep 17, 2026
@peters peters self-assigned this Sep 17, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

The lifecycle caller overwrites the new invalid-executable status with a generic restart failure.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds zero-byte executable rejection to prevent infinite supervisor restart loops and records invalid restart handoffs.

Changes:

  • Validate executables before every spawn.
  • Preserve pending restart state for invalid executables.
  • Add regression tests for empty files and valid scripts.
File summaries
File Description
crates/surge-supervisor/src/main.rs Integrates validation and handoff reporting.
crates/surge-supervisor/src/handoff.rs Records unusable executable handoffs.
crates/surge-supervisor/src/child.rs Implements pre-spawn validation.
crates/surge-core/src/update/status/handoff.rs Defines the invalid-executable phase.
crates/surge-core/src/update/status.rs Exports the new phase constant.
Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread crates/surge-supervisor/src/main.rs
The post-update restart path only checked that the target existed, then
overwrote the supervisor's invalid-executable status with a generic
pid-file timeout. Reject an empty target before spawn so the persisted
pending-restart record keeps the specific phase.
@peters
peters merged commit bb1e16f into main Sep 17, 2026
15 checks passed
@peters
peters deleted the fix/314-reject-empty-executable branch September 17, 2026 08:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working rust Pull requests that update rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Supervisor treats an empty executable as repeated successful child exits

2 participants