diff --git a/LIMITS.md b/LIMITS.md index 18e7d1c..5b27671 100644 --- a/LIMITS.md +++ b/LIMITS.md @@ -97,25 +97,31 @@ floor. State these honestly; do not pretend they are free. -### 3a. Network — and no proxy support +### 3a. Network — and proxy support only through Node's opt-in `init` / `add` / `update` require a network. They require **no `git` binary at all**: pharn resolves the branch head over the GitHub REST API and downloads the repo tarball from `codeload.github.com`, extracting it itself (`src/lib/tar-extract.ts`). Nothing is spawned. There is no offline or air-gapped install path today. -**pharn does not use an HTTP proxy.** Every network call goes through Node's global `fetch`, which -reads **no** proxy environment variable — not `https_proxy`, not `HTTPS_PROXY`, not `no_proxy`, on -any platform. In a network where direct egress is blocked, `pharn` cannot fetch, and setting a proxy -variable will not change that. +**pharn has no proxy support of its own.** Every network call goes through Node's global `fetch`, +which by default reads **no** proxy environment variable — not `https_proxy`, not `HTTPS_PROXY`, not +`no_proxy`. Node 22.21+ and 24+ can opt in with `NODE_USE_ENV_PROXY=1` (22.21+ and 24.5+ also accept +`--use-env-proxy`, for example through `NODE_OPTIONS`); Node's `fetch` then reads `https_proxy`, +`HTTPS_PROXY`, `http_proxy`, `HTTP_PROXY`, in that order, and honours `NO_PROXY`. Node 20, 21, +22.0–22.20 and 23 have no opt-in: there, in a network where direct egress is blocked, `pharn` cannot +fetch, and setting a proxy variable will not change that. The exact rules are in +`docs/troubleshooting.md` → "Proxy environment variables". This is a **regression for one group of users**, and it is named here rather than left to be discovered: the previous clone path went through `degit`, which read `process.env.https_proxy` itself, so a user who had set exactly that lowercase spelling was proxied for the clone. They were already unproxied for `pharn update`'s and `status --no-drift`'s version checks, which were always plain `fetch` — so this makes one boundary consistent rather than newly broken, but it does break a -working setup. Every network-bearing command warns before fetching when it finds a proxy variable -set, so the failure is explained rather than silent. +working setup. +On a Node with the opt-in, turning it on restores proxying for every download, the clone included. +Every network-bearing command says, before it fetches, whether this Node will use the proxy it found +set, and if not, what would make it, so the failure is explained rather than silent. ### 3b. GitHub API rate limits diff --git a/THREAT-MODEL.md b/THREAT-MODEL.md index 18d8e70..bb04f9c 100644 --- a/THREAT-MODEL.md +++ b/THREAT-MODEL.md @@ -118,13 +118,15 @@ a test. ~2.4 MB tarball per distinct upstream commit, retained forever, each one an entry reusable by filename. Caches already on disk are inert but **not** removed — pharn deletes nothing outside the user's project; `docs/troubleshooting.md` says where they live and how to size them. -- **No proxy support, stated as a limit.** Node's global `fetch` reads **no** proxy environment - variable, on any platform. The previous dependency read `process.env.https_proxy` itself — only - that lowercase spelling, and never `no_proxy`. So a user behind a corporate proxy who succeeded - before will now fail; `pharn update` and `status --no-drift` already failed for the same reason, - since those were always plain `fetch`. This makes one boundary consistent rather than newly broken, - and it is a named limit (`LIMITS.md` §3a), warned about before the fetch rather than surfacing as - an unexplained timeout. +- **No proxy support of pharn's own, stated as a limit.** Node's global `fetch` reads **no** proxy + environment variable by default. Node 22.21+ and 24+ read them once the user opts in + (`NODE_USE_ENV_PROXY=1`; `--use-env-proxy` on 22.21+ and 24.5+), and then honour `NO_PROXY`; Node + 20, 21, 22.0–22.20 and 23 have no opt-in. The previous dependency read `process.env.https_proxy` + itself — only that lowercase spelling, and never `no_proxy`. So a user behind a corporate proxy + who succeeded before now fails unless they opt in, and on a Node without the opt-in they cannot; + `pharn update` and `status --no-drift` already behaved the same, since those were always plain + `fetch`. It is a named limit (`LIMITS.md` §3a), and every network-bearing command says which case + applies before the fetch rather than letting it surface as an unexplained timeout. - **No silent transport change.** The previous path could fall back from an HTTP tarball to a spawned `git clone`, or take the commit hash from cache, emitting `warn` events that `fetchRepo` registered no listener for — so the silence was pharn's. There are no fallbacks now: the download either @@ -199,9 +201,10 @@ a named per-field sanitizer, not a "the source repo is ours" assumption (P0). content. Extraction is also **not transactional** — a mid-extract rejection leaves a partial tree, which is why `fetchRepo` removes the temp dir on the error path rather than returning it. - **A named regression, not a hidden one.** Node's global `fetch` reads no proxy environment - variable, so a user behind a corporate proxy who succeeded via the old dependency's own - `https_proxy` read now fails. `LIMITS.md` §3a carries it, and every network-bearing command warns - before the fetch when a proxy is configured. + variable by default, so a user behind a corporate proxy who succeeded via the old dependency's + own `https_proxy` read now fails unless they opt in (`NODE_USE_ENV_PROXY=1`, Node 22.21+ and + 24+; no opt-in exists on Node 20, 21, 22.0–22.20 or 23). `LIMITS.md` §3a carries it, and every + network-bearing command says which case applies before the fetch. - **4c. The stored content-hashes cover only what pharn wrote, at the matching stamp.** pharn does keep a per-file sha256 baseline — [`pharn.records.json`](docs/reference/pharn-records.md), stamped with the