Skip to content

Conversation

@fhunleth
Copy link
Member

@fhunleth fhunleth commented Jul 18, 2025

The docs contain everything to enable it and will work on all Nerves systems. For firmware validation, nerves_system_qemu_aarch64 is the only one that requires validation by default today. 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 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

@fhunleth fhunleth force-pushed the auto-validate branch 2 times, most recently from da00524 to 0fef454 Compare August 19, 2025 20:28
@fhunleth fhunleth force-pushed the auto-validate branch 4 times, most recently from 8f712d0 to c1b692e Compare December 8, 2025 15:24
@fhunleth fhunleth requested a review from Copilot December 8, 2025 15:31
@fhunleth fhunleth marked this pull request as ready for review December 8, 2025 15:31
@fhunleth fhunleth requested a review from a team as a code owner December 8, 2025 15:31
Copy link

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

Copilot reviewed 7 out of 8 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@fhunleth fhunleth force-pushed the auto-validate branch 3 times, most recently from 06af76c to 062a3e3 Compare December 8, 2025 15:56
@fhunleth fhunleth requested a review from Copilot December 8, 2025 15:56
Copy link

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

Copilot reviewed 7 out of 8 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Mimic.copy(Nerves.Runtime.StartupGuard)
Mimic.copy(Nerves.Runtime.Heart)

ExUnit.start()
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The Logger.configure(level: :error) line was removed but not replaced. This may cause tests to output more verbose logs than intended. Consider adding it back or replacing it with an appropriate log level configuration for tests.

Suggested change
ExUnit.start()
ExUnit.start()
Logger.configure(level: :error)

Copilot uses AI. Check for mistakes.
Comment on lines +27 to +30
System.cmd("mix", ["test" | options],
into: IO.stream(:stdio, :line),
env: [{"ERL_FLAGS", "-nostick"}]
)
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The run_test/1 function doesn't return the exit status from System.cmd/3. When mix test is run with ERL_FLAGS not set, the function will return the result of System.cmd/3 (a tuple {output, exit_code}), but Mix tasks expect specific return values. Consider handling the exit code appropriately, such as calling System.halt(exit_code) if the command fails.

Suggested change
System.cmd("mix", ["test" | options],
into: IO.stream(:stdio, :line),
env: [{"ERL_FLAGS", "-nostick"}]
)
{_output, exit_code} =
System.cmd("mix", ["test" | options],
into: IO.stream(:stdio, :line),
env: [{"ERL_FLAGS", "-nostick"}]
)
System.halt(exit_code)

Copilot uses AI. Check for mistakes.
@fhunleth fhunleth force-pushed the auto-validate branch 2 times, most recently from 5e54ae4 to eef0d20 Compare December 8, 2025 16:18
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.

2 participants