Replace .unwrap() with proper error handling in run()#689
Replace .unwrap() with proper error handling in run()#689LEDazzio01 wants to merge 3 commits intomicrosoft:mainfrom
Conversation
Replace panic-inducing .unwrap() calls in the `run()` function with proper error handling using `anyhow::Context`, so users get actionable error messages instead of panics when the environment is not set up correctly. Changes: - Add `anyhow::Context` import - Replace `.unwrap()` on `std::path::absolute()` with `.with_context()` - Replace `.unwrap()` on `path.metadata()` with `.with_context()` - Replace `.unwrap()` on `Mode::from_bits()` with `.ok_or_else()` - Update docstring from "Panics" to "Errors" section Fixes #650
There was a problem hiding this comment.
Pull request overview
This PR aims to prevent panic-on-misconfiguration in litebox_runner_linux_userland::run() by replacing several host-OS-facing .unwrap() calls with contextual anyhow errors, improving the user experience when the environment or paths are not set up as expected (Fixes #650).
Changes:
- Import
anyhow::Contextand add contextual error messages for failures when resolving the program’s absolute path and reading path metadata. - Replace
.unwrap()onMode::from_bits(...)with an error-producing path. - Update the
run()docstring from a# Panicssection to a# Errorssection.
| let mode = litebox::fs::Mode::from_bits(metadata.st_mode()) | ||
| .ok_or_else(|| anyhow!("Invalid file mode bits {:#o} for '{}'", metadata.st_mode(), path.display()))?; |
There was a problem hiding this comment.
Mode::from_bits(metadata.st_mode()) is very unlikely to ever return None here: Mode is defined with const _ = !0 (accepting all remaining bits), so this new ok_or_else error path appears unreachable. Either drop the check, or (if the intent is to validate/sanitize mode bits) mask/truncate to the permission/sticky/setuid bits before constructing Mode.
| let mode = litebox::fs::Mode::from_bits(metadata.st_mode()) | |
| .ok_or_else(|| anyhow!("Invalid file mode bits {:#o} for '{}'", metadata.st_mode(), path.display()))?; | |
| let mode = litebox::fs::Mode::from_bits_truncate(metadata.st_mode()); |
| let prog = std::path::absolute(Path::new(&cli_args.program_and_arguments[0])) | ||
| .with_context(|| format!("Could not resolve absolute path for program '{}'", &cli_args.program_and_arguments[0]))?; | ||
| let ancestors: Vec<_> = prog.ancestors().collect(); |
There was a problem hiding this comment.
Please add a regression test covering the reported scenario (missing/unresolvable program path) to ensure run() returns a contextual Err instead of panicking. This crate already has an integration test suite under litebox_runner_linux_userland/tests, and a test here would prevent #650 from regressing.
| /// # Errors | ||
| /// | ||
| /// Can panic if any particulars of the environment are not set up as expected. Ideally, would not | ||
| /// panic. If it does actually panic, then ping the authors of LiteBox, and likely a better error | ||
| /// message could be thrown instead. | ||
| /// Returns an error if the program path cannot be resolved, directories along the path are | ||
| /// inaccessible, or the initial filesystem cannot be set up. |
There was a problem hiding this comment.
The docstring now implies run() returns errors for environment/setup problems, but the function can still panic (e.g., remaining .unwrap()s and panic!() paths during filesystem setup / syscall rewriting). Either update the docs to mention remaining panic conditions, or convert those remaining panics into Result errors so the # Errors section is accurate.
| let prog = std::path::absolute(Path::new(&cli_args.program_and_arguments[0])) | ||
| .with_context(|| format!("Could not resolve absolute path for program '{}'", &cli_args.program_and_arguments[0]))?; |
There was a problem hiding this comment.
There is still a host-OS-facing std::path::absolute(...).unwrap() later in run() (around the "We need to get the file path before enabling seccomp" block). This means the runner can still panic in the same class of environment issues this PR is addressing, and it also contradicts the PR description claiming all relevant absolute() unwraps were replaced. Consider applying the same with_context + ? handling there too (or reusing the already-resolved prog).
- Use `from_bits_truncate` instead of `ok_or_else` for Mode (comment 1) - Add regression test for nonexistent program path (comment 2) - Update docstring to mention remaining panic conditions (comment 3) - Fix third missed `.unwrap()` on `std::path::absolute` (comment 4)
|
Thanks for the thorough review, @copilot! All four comments have been addressed in commit f2f38c7:
|
The test now also asserts that stderr contains a contextual error message (e.g., "Could not resolve absolute path" or "Could not read metadata") rather than just checking for the absence of a panic.
LEDazzio01
left a comment
There was a problem hiding this comment.
All four review comments have been addressed in the latest commit:
Mode::from_bits→from_bits_truncate— Applied as suggested, sinceModeaccepts all bits viaconst _ = !0.- Regression test — Added
tests/error_handling.rswithtest_nonexistent_program_returns_error_not_panic()that verifies the runner returns a contextual error (not a panic) for nonexistent program paths. - Docstring accuracy — Updated to include both
# Errors(for the new contextual errors) and# Panics(for remaining internal panics from in-memory filesystem operations). - Missed
.unwrap()in seccomp block — Replaced with.with_context()+?so it returns a proper error instead of panicking.
Summary
Replace panic-inducing
.unwrap()calls in therun()function with proper error handling usinganyhow::Context, so users get actionable error messages instead of panics when the environment is not set up correctly.Fixes #650
Problem
Running
litebox_runner_linux_userland echo yayon a stock Ubuntu installation causes a panic:The function's own docstring acknowledges this:
Changes
anyhow::Contextimport for.with_context()support.unwrap()onstd::path::absolute()(2 occurrences) with.with_context()providing the program name in the error.unwrap()onpath.metadata()with.with_context()explaining which path was inaccessible.unwrap()onMode::from_bits()with.ok_or_else()reporting the invalid mode bits# Panicsto# Errorssection reflecting the new behaviorScope
This PR intentionally focuses on host-OS-facing
.unwrap()calls only — the ones that interact with the real filesystem and are likely to fail from environment issues (which is the scenario reported in #650). The remaining.unwrap()calls operate on the in-memory filesystem and are left untouched to keep this change focused and reviewable.Before / After
Before: A raw panic with a cryptic stack trace
After: A clear, contextual error message