RFC Update

This commit is contained in:
Raven Scott
2026-05-28 20:11:09 -04:00
parent 2fe3d9fba5
commit 9e931b1f4d
+134 -16
View File
@@ -2,39 +2,157 @@
## Status ## Status
Draft **Rejected — not viable for production distribution.**
## Problem After a full packaging and runtime porting effort (Pear stage/release, Bare shims, OTA bootstrap, macOS privileged-port workarounds), p2ns cannot be delivered via `pear run` in a way that matches the Node.js experience without unacceptable user friction. **Node.js remains the supported distribution path.**
P2NS distribution currently assumes direct Node.js runtime usage. Broader packaging and deployment options are limited. See also [docs/PEAR_COMPAT.md](../PEAR_COMPAT.md) for the compatibility matrix that motivated this decision.
## Proposal ## Problem (original)
P2NS distribution assumed direct Node.js runtime usage. Broader packaging and deployment options were limited.
## Proposal (original)
Define a staged packaging strategy for Pear/Bare-compatible distribution without disrupting the current Node entrypoint. Define a staged packaging strategy for Pear/Bare-compatible distribution without disrupting the current Node entrypoint.
## Scope ## What was built
Substantial work landed on a feature branch / release staging path:
- Pear `package.json` block, static ESM entry (`index.mjs`), bootstrap split (`lib/bootstrap.mjs`, `lib/p2ns-entry.js`)
- Bare import map and compat layers (`*_compat.js`, `lib/pear-bare-deps.js`, `lib/pear-runtime.mjs`)
- User data under `~/.config/p2ns/` (storage, certs, caches, `.env`)
- OTA updater/runner wiring
- Linux `setcap` helper for privileged ports on the Pear binary
- macOS **pf** redirect (53/443/80 → high ports), **launchd** socket activation (Node-only), osascript admin helpers for pf and virtual interfaces
- Compatibility docs and parity gates
The app could be staged and started under Pear, but **not** in a form suitable for normal users on standard ports and interfaces.
## Why this RFC failed
### 1. Pear bundling is incompatible with normal Node module graphs
Pear DriveBundler only includes modules reachable via **static imports** from declared `pear.stage.entrypoints`. Anything loaded dynamically is omitted from the bundle.
**Observed failures:**
| Symptom | Cause |
|---------|--------|
| `MODULE_NOT_FOUND ./lib/bootstrap.js` | Dynamic `createRequire` / untraced require chain |
| `MODULE_NOT_FOUND fs` | Bare dep not in lockfile / not statically traced |
| Missing privileged-port or cache modules at runtime | Module not in entrypoint closure |
**Required workarounds:** Every boot path must be a static import chain (`index.mjs``bootstrap.mjs``p2ns-entry.js` → …). Every file the daemon touches must be listed in `pear.stage.entrypoints`. This is fragile: a single new dynamic require breaks the Pear build silently until runtime.
### 2. Privileged ports (53 / 443 / 80) cannot be solved cleanly under Pear on macOS
p2ns must listen on standard DNS and web ports. On macOS, binding even to `127.0.0.1` on ports < 1024 requires root **or** a system mechanism (pf, launchd) outside the app process.
**Approaches tried and why they fail for Pear users:**
| Approach | Intended benefit | Failure under `pear run` |
|----------|------------------|---------------------------|
| **`sudo pear run`** | Simple | Defeats non-root distribution; poor UX; Pear/Bare subprocess quirks with `sudo` |
| **Linux `setcap`** | Bind without root | Works on Linux only; must target the actual Pear/Bare binary; macOS has no equivalent |
| **pf redirect** (high ports + `pfctl`) | App runs as user; system redirects 53/443/80 | Requires **admin password** to install anchor rules; rules must cover **lo0 and en0**; still not transparent to all clients; user rejected this as too complex |
| **launchd socket activation** | Proper macOS service pattern; no root in app | **Does not work with Pear:** launchd passes socket FDs only to the process it execs (`pear`). Pear spawns a **Bare worker child**; `launch_activate_socket()` is unavailable or empty inside the worker. Would require **upstream Pear** to forward inherited FDs |
Net result: Pear users either run as root, tolerate pf + high ports, or get broken DNS/HTTPS on standard ports.
### 3. Unacceptable admin-password prompt churn
macOS Pear runs without a TTY, so privileged operations use **osascript** (`do shell script … with administrator privileges`), writing a temp script under `~/.config/p2ns/admin/run.sh`.
**Multiple independent prompts on a normal boot** (each can appear separately):
1. Install / refresh **pf** anchor (`/etc/pf.anchors/com.p2ns`, `/etc/pf.conf`)
2. Create **virtual IP aliases** on `lo0` (`ifconfig lo0 alias …`) for P2P domain routing
3. Install **split-DNS resolver** files (`/etc/resolver/p2ns.admin`)
These are repetitive, easy to dismiss or deny, and must be re-approved when rules drift or on new machines. Quoting bugs in early osascript integration caused silent pf install failures. This level of friction is **not acceptable** for a consumer-facing `pear run pear://…` install.
### 4. Virtual interfaces and Holesail binding do not work as non-root
p2ns assigns domains to virtual IPs (e.g. `192.168.3.x` on `lo0`) and runs Holesail/tunnel listeners on those addresses.
**Issues observed:**
- `sudo ifconfig lo0 alias …` fails when Pear runs as a normal user; admin prompt is the only workaround (another password).
- **Cleanup / port checks** (`checkPortAvailability`) attempt to bind TCP/UDP on virtual IPs for ports like **22**; without root this yields `EACCES` / “permission denied” and noisy false failures (e.g. “Port 22 on 192.168.3.x: permission denied”) even when no cleanup was needed.
- **HTTPS on virtual IPs:** Bare runtime binds HTTPS on `0.0.0.0:443` when possible, but per-IP TLS and interface-specific behavior differ from Node; pf/launchd do not fix alias creation.
Privileged-port workarounds for the **main** DNS/HTTP/HTTPS servers do not extend to **arbitrary privileged ports** on virtual interfaces used by Holesail services.
### 5. Path, env, and module-load ordering bugs exposed by Pear
Pears cwd, bundle layout, and early module evaluation surfaced bugs that Node dev mode masked:
- Default `./certs`, `./cache`, `./my-storage` paths invalid in a bundle → moved to `~/.config/p2ns/` with migration
- **Cache paths frozen at module load** in `admin-backend/cache.js``ENOENT` for `peer_metrics.json` / `peer_history.json` until lazy resolution was added
- **Config dir split:** code default `~/config/p2ns/.env` vs user-maintained `~/.config/p2ns/.env` caused env drift
- TLS CA load order: certs env had to run before `certificate_authority` module init
Each fix added Pear-specific boot complexity (`applyCertsEnv`, `applyCacheEnv`, `applyStorageEnv`, privileged-port bootstrap before core).
### 6. Support and maintenance cost vs. benefit
- Large compat surface (`net`, `dgram`, `http`, `tls`, `child_process`, `crypto`, …) with behavioral differences on Bare
- Pear staging/release (`stage-release.sh`) must be run as the normal user, not root; static entrypoint discipline enforced on every change
- Features gated or degraded on Bare (e.g. `sharp` avatars, some TLS/SNI paths)
- Users still need platform docs for setcap, pf, launchd, resolver, and CA trust
**Benefit delivered:** OTA `pear://` link and a partial Bare port. **Benefit required:** same “install and use on 53/443/80 with P2P domains” experience as `node p2ns.js`. The gap is not closable without Pear platform changes and/or accepting root/admin prompts.
## Decision
| Goal | Verdict |
|------|---------|
| Ship p2ns as primary **`pear run`** distribution | **No** |
| Recommend **`node p2ns.js`** (or systemd/launchd service on Node) for production | **Yes** |
| Keep Pear staging code for experimentation / OTA prototype | Optional; not supported for end users |
| macOS non-root standard ports | Use **`./scripts/install-macos-launchd.sh`** with **Node**, not Pear |
| macOS Pear dev/testing | **`sudo pear run`** or high ports + manual pf if explicitly accepted |
## Original scope (for reference)
- Identify Node runtime assumptions blocking Pear/Bare portability. - Identify Node runtime assumptions blocking Pear/Bare portability.
- Define a packaging profile for CLI/desktop delivery. - Define a packaging profile for CLI/desktop delivery.
- Evaluate `pear://` links for domain and plugin deep-linking. - Evaluate `pear://` links for domain and plugin deep-linking.
## Non-Goals ## Original non-goals
- Replacing Node runtime in this phase. - Replacing Node runtime in this phase.
- Shipping production installers immediately. - Shipping production installers immediately.
## Migration Plan ## Original migration plan (abandoned)
1. Document portability blockers and required shims. 1. ~~Document portability blockers and required shims.~~ Done; blockers are fundamental.
2. Create minimal packaging prototype with current feature subset. 2. ~~Create minimal packaging prototype with current feature subset.~~ Done; subset insufficient.
3. Add compatibility matrix (macOS/Linux/Windows) by feature. 3. ~~Add compatibility matrix by feature.~~ Done ([PEAR_COMPAT.md](../PEAR_COMPAT.md)).
4. Decide phased rollout for packaged distributions. 4. ~~Decide phased rollout for packaged distributions.~~ **Rollout rejected.**
## Risks ## Risks (realized)
- Native networking and privileged port behavior may differ by runtime. - Native networking and privileged port behavior **does** differ by runtime — macOS Pear path cannot match Node without root or repeated admin auth.
- Increased support surface for packaging artifacts. - Support surface for packaging artifacts **increased** without a viable user-facing outcome.
## Rollback ## Rollback / current recommendation
Keep current Node-based distribution as default path. - **Default distribution:** Node.js (`node p2ns.js`, npm scripts, existing docs).
- **macOS service (non-root, standard ports):** Node + launchd (`scripts/install-macos-launchd.sh`), not Pear.
- **Linux privileged ports:** `setcap` on the **node** binary or `scripts/setup-linux-setcap.sh`.
- **Do not** document `pear run pear://…` as the primary install path until Pear supports socket inheritance to workers and p2ns can avoid multi-step macOS admin setup.
Pear/Bare-related code may remain in the tree for reference; it is **not** a supported production delivery channel for p2ns.
## Open upstream dependencies (if revisiting)
For Pear distribution to become viable later, at minimum:
1. **Inherited FD forwarding** from Pear parent to Bare worker (launchd / systemd socket activation).
2. **Bundling** that does not require hand-maintained static entrypoint closure for every transitive require.
3. A **single**, documented privileged-port story on macOS that does not require pf anchors + virtual-interface admin prompts per install.
Until those exist, RFC 0003 remains rejected.