Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions LIMITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
23 changes: 13 additions & 10 deletions THREAT-MODEL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading