RFC Update
This commit is contained in:
@@ -2,39 +2,157 @@
|
||||
|
||||
## 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.
|
||||
|
||||
## 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
|
||||
|
||||
Pear’s 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.
|
||||
- Define a packaging profile for CLI/desktop delivery.
|
||||
- Evaluate `pear://` links for domain and plugin deep-linking.
|
||||
|
||||
## Non-Goals
|
||||
## Original non-goals
|
||||
|
||||
- Replacing Node runtime in this phase.
|
||||
- Shipping production installers immediately.
|
||||
|
||||
## Migration Plan
|
||||
## Original migration plan (abandoned)
|
||||
|
||||
1. Document portability blockers and required shims.
|
||||
2. Create minimal packaging prototype with current feature subset.
|
||||
3. Add compatibility matrix (macOS/Linux/Windows) by feature.
|
||||
4. Decide phased rollout for packaged distributions.
|
||||
1. ~~Document portability blockers and required shims.~~ Done; blockers are fundamental.
|
||||
2. ~~Create minimal packaging prototype with current feature subset.~~ Done; subset insufficient.
|
||||
3. ~~Add compatibility matrix by feature.~~ Done ([PEAR_COMPAT.md](../PEAR_COMPAT.md)).
|
||||
4. ~~Decide phased rollout for packaged distributions.~~ **Rollout rejected.**
|
||||
|
||||
## Risks
|
||||
## Risks (realized)
|
||||
|
||||
- Native networking and privileged port behavior may differ by runtime.
|
||||
- Increased support surface for packaging artifacts.
|
||||
- Native networking and privileged port behavior **does** differ by runtime — macOS Pear path cannot match Node without root or repeated admin auth.
|
||||
- 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.
|
||||
|
||||
Reference in New Issue
Block a user