Document portable limits primitives

ober

b96df2921a9d16f80c6a07a799b691d503356eda

diff --git a/docs/limits.md b/docs/limits.md
new file mode 100644
index 0000000..ace84e5
--- /dev/null
+++ b/docs/limits.md
@@ -0,0 +1,442 @@
+# Portable Limits and Capability Primitives
+
+This document lists the Jerboa-side work needed to support capability-wrapped launchers such as `jsh` wrappers for Node/npm-backed AI tools. The goal is to provide portable, low-level security and process primitives in Jerboa. User-facing policy syntax, comma-prefixed launch-script directives, profiles, and tool-specific wrappers should live in `jsh`.
+
+## Scope
+
+Jerboa should provide:
+
+- portable sandbox enforcement
+- portable process supervision
+- portable resource limits
+- executable identity inspection
+- filesystem access tracing
+- network allowlist/proxy helpers
+- environment and secret handling
+- temporary home/cache helpers
+- structured audit data
+
+Jerboa should not provide:
+
+- `jsh` comma-rule syntax
+- tool profiles such as `codex`, `claude`, or `opencode`
+- npm-specific policy decisions
+- transactional source workspace UX
+
+Those belong in `jsh` or higher-level applications.
+
+## Threat Model
+
+The motivating case is a trusted Jerboa program launching an untrusted or semi-trusted child process, especially a runtime with supply-chain exposure such as Node/npm. The child may:
+
+- read broad filesystem locations looking for secrets
+- run install scripts or nested package managers
+- spawn subprocesses
+- modify project files, shell config, Git hooks, or tool config
+- open arbitrary network connections
+- consume unbounded CPU, memory, pids, disk, or output
+
+The trusted parent must prepare a narrow execution environment, start the child with limited authority, monitor it, and produce an audit trail.
+
+Important constraint: once kernel sandboxing is installed in a process, access can generally only become stricter. Broader access requires the trusted parent to start a new child with a broader policy.
+
+## 1. Unified Sandbox API
+
+Jerboa already has platform pieces under modules such as `(std os sandbox)`, `(std os seccomp)`, `(std os landlock)`, `(std security sandbox)`, `(std security landlock)`, `(std security seccomp)`, `(std security capsicum)`, and `(std security seatbelt)`. The missing piece is a single capability-oriented API with consistent semantics.
+
+Proposed module:
+
+```scheme
+(import (std os limits sandbox))
+```
+
+Responsibilities:
+
+- accept read, write, execute, and network policy
+- apply the strongest available backend for the current OS
+- report exact support level before launch
+- distinguish full, partial, unavailable, and degraded enforcement
+- expose structured errors for unsupported policy features
+
+Required platform backends:
+
+| Platform | Filesystem | Syscalls/Process | Notes |
+| --- | --- | --- | --- |
+| Linux | Landlock | seccomp | best target for full support |
+| OpenBSD | unveil | pledge | good model for shrink-only policy |
+| FreeBSD | Capsicum | rlimit/process controls | requires pre-opened resources |
+| macOS | Seatbelt profile | rlimit/process controls | private/limited APIs; support may be partial |
+| Other | none or partial | rlimit only | must report degraded mode |
+
+Support query should be first-class:
+
+```scheme
+(sandbox-capabilities)
+;; => alist/record describing fs, exec, net, syscall, trace, limits support
+```
+
+The API should make degraded behavior explicit. A caller must be able to say "fail closed if full filesystem confinement is unavailable."
+
+## 2. Process Supervision
+
+Jerboa needs a portable process supervisor that can launch and control child process trees. This is the foundation for timeouts, tracing, audit, and tree kill.
+
+Proposed module:
+
+```scheme
+(import (std os supervise))
+```
+
+Required features:
+
+- launch a child in a new process group/session where supported
+- pass an explicit environment
+- set cwd
+- wire stdin/stdout/stderr
+- wait for structured exit status
+- kill one child or the whole process group
+- apply timeout from the parent
+- collect basic resource and process-tree metadata
+
+Suggested result shape:
+
+```scheme
+(process-result
+  status: 0
+  signal: #f
+  pid: 1234
+  command: '("/usr/bin/node" "tool.js")
+  elapsed-ms: 1250
+  stdout-bytes: 4096
+  stderr-bytes: 512)
+```
+
+Tracking subprocesses is platform-specific. Jerboa should expose the best available method and report precision:
+
+- exact tree tracking
+- process-group only
+- best-effort sampling
+- unavailable
+
+## 3. Resource Limits
+
+`jsh` currently has memory limiting logic. Jerboa should generalize this into a portable stdlib facility.
+
+Proposed module:
+
+```scheme
+(import (std os limits))
+```
+
+Limit types:
+
+- memory bytes
+- CPU seconds
+- wall-clock milliseconds
+- process count
+- open file descriptors
+- file size
+- stdout/stderr byte count
+- core dump size
+
+Backends:
+
+- Linux cgroup v2 for memory, pids, CPU, and process-tree containment
+- `setrlimit` fallback on Linux/BSD/macOS
+- parent-side output counters for stdout/stderr limits
+- parent-side wall-clock timeout
+
+Important caveats:
+
+- `RLIMIT_AS` is not the same as physical memory.
+- `RLIMIT_NPROC` may affect a user, not just a tree.
+- cgroup setup may require permissions or delegated controllers.
+- output limits are best enforced by the supervising parent.
+
+The API should return which limits were actually installed.
+
+## 4. Executable Identity
+
+Name-based policy is ergonomic but weak. Jerboa needs an executable identity API so callers can flag `node`, `npm`, `npx`, `bun`, etc. by resolved identity.
+
+Proposed module:
+
+```scheme
+(import (std os exec-id))
+```
+
+Required operations:
+
+- resolve a command name through an explicit `PATH`
+- return absolute path
+- canonicalize via realpath
+- stat device/inode
+- compute optional SHA-256 hash
+- detect symlinks
+- preserve original argv name for audit
+
+Suggested identity shape:
+
+```scheme
+(exec-id
+  argv0: "node"
+  path: "/usr/local/bin/node"
+  realpath: "/opt/homebrew/bin/node"
+  dev: 16777234
+  ino: 12345678
+  sha256: "...")
+```
+
+This lets higher-level tools implement rules such as "flag anything resolving to this Node binary as hostile" without relying only on process name.
+
+## 5. Filesystem Access Tracing
+
+Jerboa should expose a portable `tracefs` API that records file and directory access by a supervised command and its subprocesses.
+
+Proposed module:
+
+```scheme
+(import (std os tracefs))
+```
+
+Common event format:
+
+```scheme
+(fs-event
+  pid: 1234
+  ppid: 1200
+  exe: "/usr/bin/node"
+  op: 'read
+  path: "/repo/package.json"
+  cwd: "/repo"
+  fd: #f
+  result: 'ok
+  errno: #f
+  timestamp-ms: 123456789)
+```
+
+Operations to classify:
+
+- read/open
+- write/open
+- create
+- delete
+- rename
+- metadata/stat/access
+- directory listing
+- symlink/readlink
+- execute
+
+The tracer must maintain enough process state to resolve relative paths:
+
+- cwd per process
+- fd table per process
+- fd inheritance across fork/clone
+- `openat` directory fd mappings
+- exec identity changes
+
+Backends:
+
+| Platform | Prototype | Better backend | Notes |
+| --- | --- | --- | --- |
+| Linux | `strace -f -e trace=file` parser | native `ptrace`, optional eBPF | best practical starting point |
+| macOS | `dtrace` where allowed | EndpointSecurity | SIP/entitlements may restrict support |
+| FreeBSD | `truss`/`ktrace` | native ktrace parser | good fit for process tracing |
+| OpenBSD | `ktrace`/`ktruss` if available | native parser | combine with pledge/unveil denial info |
+
+If deep tracing is unavailable, Jerboa should expose degraded modes:
+
+- sandbox denial events only
+- wrapper-level explicit file opens only
+- final directory diff
+- unsupported
+
+The output format must stay the same even when event completeness differs.
+
+## 6. Network Allowlist Support
+
+Kernel sandbox APIs are usually good at "network yes/no" but poor at portable host allowlists. Jerboa should provide a small local proxy toolkit so callers can deny direct network in the child and allow only proxy-mediated destinations.
+
+Proposed module:
+
+```scheme
+(import (std net allow-proxy))
+```
+
+Required features:
+
+- HTTP CONNECT proxy
+- optional SOCKS5 proxy
+- allow `host:port`
+- deny IP literals
+- deny loopback, link-local, private, and local network ranges
+- resolve DNS in the trusted parent/proxy
+- re-check resolved addresses against deny rules
+- structured connection audit events
+
+Typical flow:
+
+1. parent starts allowlist proxy on loopback or Unix socket
+2. parent denies direct child network through sandbox policy
+3. parent injects `HTTPS_PROXY`, `HTTP_PROXY`, or tool-specific proxy env
+4. proxy allows only configured destinations
+
+The proxy should be a library primitive, not a `jsh`-only feature.
+
+## 7. Environment and Secret Broker
+
+Jerboa needs helpers to construct a clean child environment from an allowlist and inject explicit secrets safely.
+
+Proposed module:
+
+```scheme
+(import (std security env))
+```
+
+Required features:
+
+- create environment from scratch
+- allow selected variables
+- deny patterns such as `*TOKEN*`, `*KEY*`, `AWS_*`
+- inject named secrets
+- redact secrets from logs and audit output
+- optionally mark secrets as runtime-only, not install-phase
+
+Secret storage itself can remain caller-provided. Jerboa should provide safe transport, redaction, and environment construction primitives.
+
+Useful helpers:
+
+- redact a string by registered secret values
+- redact an alist/env vector
+- produce an audit-safe environment summary
+- detect accidental secret leakage in command arguments
+
+## 8. Temporary Home and Cache Helpers
+
+Jerboa should provide standard helpers for fake home and per-run cache directories.
+
+Proposed module:
+
+```scheme
+(import (std os temp-home))
+```
+
+Required features:
+
+- create isolated fake `HOME`
+- create named cache directories
+- choose cleanup or preserve-on-error behavior
+- copy selected config files into fake home
+- produce paths suitable for sandbox read/write grants
+- record all generated paths in audit metadata
+
+This keeps Node/npm-like tools away from the real home directory by default.
+
+## 9. Structured Audit Model
+
+All primitives should emit compatible audit records. Higher-level applications should not need to parse human text.
+
+Proposed module:
+
+```scheme
+(import (std security audit-log))
+```
+
+Record types:
+
+- process start/exit
+- sandbox installed/degraded/failed
+- limit installed/degraded/failed
+- executable resolved
+- filesystem event
+- network event
+- environment summary
+- secret injected/redacted
+- policy violation
+
+Formats:
+
+- in-memory list/stream of records
+- JSON Lines writer
+- human summary renderer
+
+Audit data must avoid leaking secret values.
+
+## 10. Policy-Neutral Data Types
+
+Jerboa should define policy-neutral records that `jsh` can consume:
+
+- sandbox policy
+- sandbox capability report
+- limit policy
+- limit installation result
+- executable identity
+- process launch spec
+- process result
+- filesystem event
+- network event
+- audit event
+
+These records should avoid `jsh` terms such as comma rules or profiles. Jerboa is the enforcement substrate; `jsh` is one frontend.
+
+## 11. Testing Requirements
+
+Each module needs platform-aware tests with skip/degraded behavior.
+
+Core tests:
+
+- sandbox denies unreadable path
+- sandbox allows explicitly readable path
+- sandbox denies writes outside allowlist
+- process supervisor kills entire process group
+- wall timeout works
+- output byte limit works
+- executable identity resolves symlinks
+- fake home prevents reading real home config
+- env broker strips token-like variables
+- redaction removes registered secret values
+- tracefs sees basic open/stat/exec events where supported
+- proxy allows configured host and denies localnet
+
+Tests should assert support reports, not pretend every platform has every backend.
+
+## 12. Implementation Order
+
+Recommended order:
+
+1. Capability reports for existing sandbox/limit modules.
+2. Process supervisor with process-group kill and structured status.
+3. General resource limit API using existing cgroup/rlimit code.
+4. Executable identity API.
+5. Environment/secret broker and redaction helpers.
+6. Temporary home/cache helpers.
+7. Network allowlist proxy.
+8. Tracefs API with Linux `strace` prototype.
+9. Native tracing backends.
+10. Unified audit record model across all pieces.
+
+This order gives `jsh` useful building blocks early, before the hardest portable tracing work is complete.
+
+## 13. Relationship to jsh
+
+`jsh` should use these primitives to implement:
+
+- comma-prefixed launch-script rules
+- named profiles
+- named directory capabilities
+- Node/npm shims
+- transactional workspace mode
+- user-facing commands such as `,read`, `,write`, `,net`, `,limit`, and `,tracefs`
+
+Jerboa should not know about those user-facing commands. Jerboa should only know how to enforce and report portable limits.
+
+## 14. Non-Goals
+
+- Perfect confinement on every OS.
+- Live sandbox loosening after a child starts.
+- Replacing AppArmor, SELinux, or platform MAC systems.
+- Root-only tracing as the only path.
+- npm-specific logic in the Jerboa stdlib.
+
+The design should be honest about partial support. A caller must be able to require fail-closed behavior when degraded enforcement is not acceptable.
+