Skip to content

Conversation

fhunleth
Copy link
Member

This is draft since it's a little large for one PR and I may split up for easier review. However, since people are starting to try out auto fail-back with the Raspberry Pi (currently in branches too), it would be nice to start getting feedback on a trimmed down startup guard for automatically validating new firmware images.

The docs really contain everything to enable it and you'll need to use custom systems, so this takes a little work to actually use now. The TL;DR for this code is:

Add the following to your Nerves project's target.exs or config.exs:

config :nerves_runtime, startup_guard_enabled: true

Add then add the following to your project's rel/vm.args.eex:

## Require an initialization handshake within 10 minutes
-env HEART_INIT_TIMEOUT 600

@fhunleth fhunleth requested a review from Copilot July 18, 2025 13:01
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces a minimal firmware validator called StartupGuard that monitors system startup and automatically validates firmware for simple use cases. The validator waits for all OTP applications to start, then validates unvalidated firmware, with a 15-minute timeout and heart callback protection against hangs.

  • Adds Nerves.Runtime.StartupGuard module with heart integration for automatic firmware validation
  • Enhances firmware validation status checking with new firmware_validation_status/0 function
  • Improves KV module error handling to prevent crashes when the GenServer isn't running

Reviewed Changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
lib/nerves_runtime/startup_guard.ex New module implementing firmware validation with heart callbacks and application startup monitoring
lib/nerves_runtime/application.ex Conditionally starts StartupGuard based on configuration
lib/nerves_runtime.ex Adds firmware_validation_status/0 function and get_expected_started_apps/0 helper
lib/nerves_runtime/kv.ex Adds safe_call wrapper to handle GenServer crashes gracefully
test/nerves_runtime/startup_guard_test.exs Comprehensive test suite for StartupGuard functionality
test/nerves_runtime_test.exs Updates tests to use new firmware_validation_status/0 function
test/test_helper.exs Adds Mimic setup for mocking Erlang modules
mix.exs Adds Mimic dependency and custom test runner for Erlang module mocking
README.md Updates documentation to reflect new StartupGuard functionality and configuration


defp get_uptime_minutes() do
{total, _last_call} = :erlang.statistics(:wall_clock)
div(total, 60_000)
Copy link
Preview

Copilot AI Jul 18, 2025

Choose a reason for hiding this comment

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

[nitpick] The magic number 60_000 should be defined as a module attribute or constant to improve code clarity and maintainability.

Suggested change
div(total, 60_000)
div(total, @milliseconds_per_minute)

Copilot uses AI. Check for mistakes.

Since it's going to be possible in the official Nerves systems to try
out firmware that needs logic to validate it, there needs to be a simple
way for new users to use it. This is a really basic startup guard that
waits for all OTP applications in the start script to be running and
then validates the running firmware.

Applications not starting result in a reboot after 15 minutes which will
either revert or go through the process again. A warning message is
printed every minute to hopefully clue people into what's happening
since it's guaranteed that 15 minutes won't work for everyone.
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.

1 participant