# Coral RFE: chroot maintainer scripts under `--root`

**Status:** Draft — ready to file with the Coral team
**Filed against:** Coral 0.4.2 (`reef.toml` version = "0.4.2")
**Reporter:** Chris Tusa <chris.tusa@leafscale.com>
**Consumer:** zyginstall (the Hammerhead system installer) — installs the OS into a
target root via `coral install --root /mnt ...` from an ISO live environment.

## Summary

When `coral install --root <dir>` (and the remove/upgrade paths) run a package's
maintainer scripts, the scripts execute against the **live host filesystem** with the
real `/` as root. Only the file *payload* is written under `<dir>`; the scriptlets are
not confined to it. There is no flag, config key, or env var to change this.

For an OS installer that stages a target root and then installs packages into it, a
package's `post-install.sh` that assumes it runs inside the installed system will
instead act on the host (the ISO live environment) — silently corrupting the host or
no-op'ing incorrectly. This makes package maintainer scripts unusable for
`--root` installs.

## Current behavior (evidence)

- File placement correctly honors `--root`: `install_files` writes every file to
  `path.join_path(root, rel_path)` (`src/core/package.reef:307`). ✅
- Script execution does **not**: the single executor `run_script`
  (`src/core/package.reef:508-536`) builds `zsh "<extract_dir>/.SCRIPTS/<name>.sh" <args>`
  and hands it to `process_spawn_shell` — no `chroot`, no `cd`, and `<root>` is never
  passed in. The hook wrappers `run_pre_install` / `run_post_install`
  (`package.reef:539-565`) take only `(pkg_dir, version)`; `run_stored_script`
  (`package.reef:624-651`) takes `(scripts_dir, script_name, script_args)` and the stored
  hook wrappers (`run_stored_pre_remove` etc., `package.reef:654+`) take
  `(scripts_dir, version)` — the target root is architecturally invisible to all of them.
- Call sites confirm the split: scripts run with `extract_dir`, files install with
  `install_root` (`src/commands/install.reef:443` / `:452` / `:461`).
- No `chroot` anywhere in `src/` (only the standalone `tools/mkchroot/` helper).
- No `$ROOT`/`$PKGROOT` env var is exported to scripts, so a script cannot even manually
  honor the root today (only `$VERSION`/`$OLD_VERSION`/`$NEW_VERSION` are passed
  positionally).

## Requested change

1. **Chroot maintainer scripts when the install root is non-`/`.** Thread the install
   root into the hook functions (`run_pre_install`, `run_post_install`,
   `run_pre_remove`, `run_post_remove`, `run_pre_upgrade`, `run_post_upgrade`,
   `run_stored_*` — all currently `(pkg_dir, version)`) and have `run_script` /
   `run_stored_script` emit `chroot "<root>" zsh /.SCRIPTS/<name> <args>`, with the
   `.SCRIPTS` dir staged inside `<root>` so it's reachable post-chroot.

2. **An explicit control** — e.g. a `--chroot-scripts` / `--no-chroot-scripts` flag or a
   `chroot_scripts` config key — since none exists today. Define the fallback when
   `chroot(2)` isn't permitted (non-root caller): fail loudly rather than silently
   running against the host.

3. **Until (1) ships, a safety note** in the docs that `coral install --root <dir>`
   stages *files* under `<dir>` but runs maintainer scripts against the host, and,
   as a stopgap, **export a `$CORAL_ROOT` env var** to scripts so a maintainer can
   defensively prefix paths.

## Impact on zyginstall (context for prioritization)

Not an immediate hard blocker for the first two packages: `hammerhead-kernel` and
`hammerhead-userland` have only one post-install script (a `svccfg import` guarded on
`svc.configd` running) which no-ops on a Hammerhead/zyginit system. But it is a
correctness landmine for any future package with a real post-install action, and the
installer would otherwise have to special-case / manually re-run scripts under
`chroot /mnt` itself. A stopgap `$CORAL_ROOT` env var (item 3) would let the installer
proceed safely before the full chroot work lands.
