hoangsonww / hoangsonww/ReproVM-Virtual-Machine
Feature: Hermetic Sandboxing & Environment Fingerprinting for Truly Reproducible Runs
- Dominant language
- C
- Stars
- 11
- Forks
- 7
- PR merge metrics
- No merged PRs in 30d
Description
# Hermetic Sandboxing & Environment Fingerprinting for *Truly* Reproducible Runs
**Summary**
Introduce an optional **hermetic execution mode** that (a) sandboxes each task, and (b) fingerprints the execution environment (PATH, tool digests, env vars, locale, umask, time source, network policy). This closes the gap where “same inputs/commands” still yield divergent outputs due to ambient machine differences.
---
## Motivation
ReproVM’s content-addressed model makes tasks reproducible *given identical environments*. In practice, outputs can drift due to:
* Different compiler/interpreter versions found on `PATH`
* Leaking env vars (e.g., `LC_ALL`, `PYTHONHASHSEED`, `CC`, `TMPDIR`)
* Non-deterministic timestamps / umask / time zone
* Accidental network access or host files outside declared inputs
A hermetic option would make cache keys reflect the *actual* runtime environment and allow strict isolation when desired.
---
## Goals
* **Sandboxed execution** (opt-in): per-task filesystem and network isolation.
* **Environment fingerprinting**: record a normalized summary that participates in the task hash (configurable).
* **Repro toggles**: knobs for time freezing, umask, locale, and temp dirs.
* **Minimal deps**: use portable primitives first; gracefully degrade per OS.
---
## Non-Goals
* Full containerization replacement (Docker/Podman exist).
* Cross-platform kernel feature parity (we’ll detect & fall back).
---
## Design Overview
### 1) Environment Fingerprint (EF)
New structure captured pre-exec and (optionally) mixed into the **task hash**:
* **PATH map**: resolve each executable in `cmd` to absolute path + SHA-256 of the binary (first 2MB or full file, configurable).
* **Key env vars** (allowlist with override): `LANG`, `LC_*`, `TZ`, `SOURCE_DATE_EPOCH`, `PYTHONHASHSEED`, `CC`, `CFLAGS`, `LDFLAGS`, `HOME`, `TMPDIR`.
* **Umask** and **timezone/locale**
* **Tool versions** (best-effort): run `--version` for detected compilers/interpreters if cheap (time boxed).
* **Clock policy**: `frozen | monotonic | wall`
* **Network policy**: `deny | allowlist | allow`
* **Sandbox mode**: `none | namespaced | chroot | bwrap`
Persist EF alongside `.meta` and include a hash `env_hash` that can be *included or excluded* from the task hash via policy.
### 2) Sandboxing Options (CLI & per-task)
* `--sandbox=none|auto|chroot|bwrap|ns` (default `auto`)
* **Linux**: prefer user-ns/`unshare` + `mount --bind` (read-only), optional `bwrap` if available.
* **macOS**: try `sandbox-exec` profile (ro filesystem allowlist).
* **Fallback**: `chroot` if root & setup present; otherwise warn and run unsandboxed.
* **Network control**: `--net=deny|allow|allowlist=host,host` (Linux: `unshare -n`, macOS: pf anchor or no-op + warning).
* **FS policy**:
* Bind-mount declared `inputs` read-only.
* Create ephemeral rw workdir for declared `outputs`.
* Mount `/tmp` to a private directory.
* Optional allowlist mounts via `extra_mounts`.
* **Time**:
* `--time=frozen` uses `SOURCE_DATE_EPOCH` and sets envs (`TZ=UTC`, `LC_ALL=C`) + later normalize mtimes on produced outputs.
* `--time=wall` (default) leaves as is.
* **Umask/locale**: set to deterministic defaults unless disabled.
### 3) Hashing Policy
* New policy flag: `--hash-env=off|minimal|strict`
* **off**: current behavior (no EF in task hash).
* **minimal**: hash includes PATH resolution + selected envs.
* **strict**: includes full EF (tool digests, umask, locale, time/network policy).
* Per-task overrides via manifest, e.g.:
```
task build {
cmd = gcc -o hello hello.c
inputs = hello.c
outputs = hello
deps =
hash_env = strict
sandbox = auto
net = deny
}
```
### 4) Metadata & UX
* Extend `.reprovm/cache/.meta`:
```
env_hash:
env_mode: strict|minimal|off
sandbox: ns|bwrap|chroot|none
net: deny|allow|allowlist
umask: 0022
tz: UTC
locale: C
tools:
/usr/bin/gcc sha256=... version="gcc (GCC) 13.2"
/usr/bin/python3 sha256=... version="Python 3.11.7"
```
* CLI: show one-line hint when cache miss is due to env drift:
```
[!] env drift: PATH tool digest changed (/usr/bin/gcc)
```
---
## Acceptance Criteria
* [ ] New flags: `--sandbox`, `--net`, `--hash-env`, `--time`, `--umask`, `--locale`.
* [ ] Per-task manifest keys: `sandbox`, `net`, `hash_env`, `time`, `umask`, `locale`, `extra_mounts`.
* [ ] Linux: namespaced sandbox (no root) with RO inputs and private TMP; deny-net works.
* [ ] macOS: basic sandbox profile enforced or graceful warning fallback.
* [ ] EF recorded in `.meta`; `env_hash` included/excluded per policy.
* [ ] Deterministic run demo: changing compiler version flips cache under `strict` but not under `off`.
* [ ] Tests: EF hashing, sandbox FS allowlist, deny-net, time freezing (mtimes normalized), cache invalidation on env drift.
* [ ] Docs: README section “Hermetic Mode & Environment Fingerprints” with examples.
---
## Tasks
* [ ] EF collector (PATH resolve, tool digests, env allowlist, umask/locale).
* [ ] Hash policy plumbing in task-hash computation.
* [ ] Sandbox launcher abstraction with backends: ns/bwrap/chroot/none.
* [ ] Network policy implementation (Linux user-ns; macOS: warn/fallback).
* [ ] Time/umask/locale normalizers (and post-build mtime normalization for outputs when `--time=frozen`).
* [ ] Manifest parser updates + validation.
* [ ] Cache metadata schema extension + migration handling.
* [ ] Unit & integration tests (serial & parallel binaries).
* [ ] Documentation + examples (minimal vs strict).
---
## Risks & Mitigations
* **Portability variance** → detect features at runtime, print clear fallbacks.
* **Performance cost (tool hashing)** → cache per-binary digest with mtime/size heuristic, cap size, opt-out in `minimal`.
* **User friction** → default stays current behavior; hermetic mode is opt-in and per-task tunable.
Contributor guide
Assessment
This issue has not been assessed yet.