feat(install,remove,upgrade): enable chroot confinement with upfront privilege abort
Author:
Chris Tusa <chris.tusa@leafscale.com>
Date:
Jul 05, 2026 17:35
Changeset:
20e96d779dee115542c500bf41935c0a3b2c9d64
Branch:
default
Changed files:
Diff
diff -r 6a5359a64b22 -r 20e96d779dee src/commands/install.reef --- a/src/commands/install.reef Sun Jul 05 17:20:31 2026 -0500 +++ b/src/commands/install.reef Sun Jul 05 17:35:42 2026 -0500 @@ -40,6 +40,7 @@ import util.version as ver import types import util.color +import util.priv import exitcodes as ec export @@ -387,9 +388,17 @@ end if let install_root = get_root(cfg) - // Phase 1: chroot disabled (chroot_scripts=false), so ctx.do_chroot is always false; - // this exports $CORAL_ROOT to scripts. Phase 2 replaces the args with cfg + is_root(). - let script_ctx = package.resolve_script_ctx(install_root, false, true) + // Resolve script execution context; abort early if confinement is required but impossible. + // Defense-in-depth: main.reef already bars non-root for all non-query commands, so this abort + // is currently unreachable via the CLI. Kept so confinement fails safely if that global gate is + // ever relaxed. + if package.script_wants_chroot(install_root, config.get_chroot_scripts(cfg)) and not priv.is_root() + color.print_error("--root " + install_root + " runs maintainer scripts confined to the target via chroot, which requires root privileges.") + color.print_error("Re-run as root, or pass --no-chroot-scripts to run them on the host (unconfined).") + cleanup_extract_dir(extract_dir) + return false + end if + let script_ctx = package.resolve_script_ctx(install_root, config.get_chroot_scripts(cfg), priv.is_root()) if is_upgrade // Upgrade flow: pre-upgrade → remove old files → install new files → post-upgrade diff -r 6a5359a64b22 -r 20e96d779dee src/commands/remove.reef --- a/src/commands/remove.reef Sun Jul 05 17:20:31 2026 -0500 +++ b/src/commands/remove.reef Sun Jul 05 17:35:42 2026 -0500 @@ -35,6 +35,7 @@ import util.color import fs.stat import fs.ops +import util.priv import exitcodes as ec export @@ -143,7 +144,7 @@ mut all_success = true i = 0 while i < pkg_count - if not remove_package(packages[i], root_path) + if not remove_package(packages[i], root_path, cfg) color.print_error("Failed to remove: " + packages[i]) all_success = false end if @@ -183,7 +184,7 @@ println(" coral remove --force libfoo") end print_usage -fn remove_package(pkg_name: string, root_path: string): bool +fn remove_package(pkg_name: string, root_path: string, cfg: config.Config): bool // Check if package is installed (use rooted version if root is set) if not check_installed(pkg_name, root_path) color.print_error(pkg_name + " is not installed") @@ -192,10 +193,17 @@ color.print_action("Removing " + pkg_name + "...") - // Phase 1: chroot disabled (chroot_scripts=false), so ctx.do_chroot is always false; - // this exports $CORAL_ROOT to scripts. Phase 2 replaces the args with cfg + is_root(). let install_root = get_actual_root(root_path) - let script_ctx = package.resolve_script_ctx(install_root, false, true) + // Resolve script execution context; abort early if confinement is required but impossible. + // Defense-in-depth: main.reef already bars non-root for all non-query commands, so this abort + // is currently unreachable via the CLI. Kept so confinement fails safely if that global gate is + // ever relaxed. + if package.script_wants_chroot(install_root, config.get_chroot_scripts(cfg)) and not priv.is_root() + color.print_error("--root " + install_root + " runs maintainer scripts confined to the target via chroot, which requires root privileges.") + color.print_error("Re-run as root, or pass --no-chroot-scripts to run them on the host (unconfined).") + return false + end if + let script_ctx = package.resolve_script_ctx(install_root, config.get_chroot_scripts(cfg), priv.is_root()) // Get package info (use rooted version if root is set) let pkg = get_installed_pkg(pkg_name, root_path)