ADR-0026: Trust inventory and supply chain¶
Status: accepted (2026-08-14). Unlike most hardening, several items here are explicitly not parked on the ADR-0017 security clock: the wheel-consuming population already exists.
What a user trusts today, enumerated¶
Installing a comfy-env pack currently means trusting:
- The pack itself -- its
install.pyand node code execute with the user's privileges. Baseline ComfyUI-ecosystem trust, unchanged by comfy-env. -
The CUDA wheel farm -- native binaries served from a GitHub Pages index (Releases API fallback) run by this project, executing at import time inside the isolated env. Blast radius: arbitrary native code on every GPU machine running these packs.
Amended 2026-09: two of the three qualifiers below have since been fixed. The wheels are inside the lockfile -- inlined as direct-URL
pypi-dependencies-- and hash-verified wherever the index anchor carries a#sha256=fragment, which the default index does. The post-pixiuv pip install --no-depsside channel that put them outside the lock is deleted. What remains true, and is what decision 1 below is about: the index is mutable, a mirror set viaCOMFY_ENV_CUDA_WHEELS_INDEXneed not attach fragments at all, and nothing is signed. 3.[node_packs]transitive installs -- cloned repos'install.pyfiles run, and so does theinstall.pyof anything they declare, recursively. ADR-0016 rules that entries must be pinned to a git ref and thatregistry/versionentries are refused until the Comfy Registry can be verified. Neither rule is enforced in code yet -- ADR-0016's status line says so, and this item used to read as though it were done. Todayinstall_node_packsaccepts a bareowner/repo(tracking HEAD) and dispatchesregistry = "..."straight toinstall_from_registry, which downloads whateverapi.comfy.orgcurrently serves for that name and runs its install script (packages/node_packs.py, ). Blast radius is the same as item 1, at a source the pack author did not pin and the user never named. 4. The pinned pixi binary -- the one link done right: version pinned, sha256-verified against the release's own sums, refused on mismatch. This is the template for item 2. 5. The local IPC surface -- was unauthenticated (any local process could connect and feed pickles to the parent). Fixed in 0.4.18: a per-spawn authkey is verified as the worker's first frame, with anSO_PEERCREDsame-uid check on Linux AF_UNIX, and the address + authkey travel via the worker's environment, never argv. Residual gap to note for multi-user servers: on the Windows TCP-loopback fallback there is no peer-uid check, so the authkey (which lives in the child's environment block, readable by same-user processes) is the only gate there.
Decisions¶
- Wheel integrity: curation now, hashing/signing at the rollout
clock (revised 2026-08-15). The earlier ruling was "hash now"; on
reflection it is deferred, because pre-rollout the only attacker is
the maintainer's own compromised GitHub account -- the wheel
consumers are the maintainer's own packs, and sha256-pinning buys
tamper-defense against a threat the current era barely has while
imposing a permanent farm↔manifest hash-sync burden (a rebuilt
wheel whose hash was not re-synced fails a correct install).
Ordering:
(a)
Requires-Distcuration on the farm -- do now, but on its own merits (resolver-safe wheels, lockfile-visible inlining, successor-usable artifacts per the bus-factor point), not as security; (b) resolved wheel sha256 pinned into the generated manifest -- deferred to the rollout tripwire with the rest of the trust work, when strangers' machines make tamper-defense a real threat model; (c) signing/attestation (sigstore) -- rollout tripwire, after (b). - Release qualification for the farm: a wheel reaches the index only after a per-combo smoke test (import + one kernel launch) in farm CI; a staging index precedes the stable one. Rollback = index pointer flip over immutable per-release artifacts -- yanking a bad wheel must never require rewriting history.
- Bus factor, named: every binary in this ecosystem currently
flows through one personal GitHub account (index, releases, farm).
There is no technical fix for a bus factor of one; the mitigation
is (a) this sentence existing, (b)
Requires-Distcuration making the artifacts usable by a successor without the farm, and (c) "migrate index + farm to an org account" sitting on the 0017 rollout checklist with a date. - The pickle rung stays as-is until the sandbox milestone
(ADR-0011), per the
instrument-then-flip ruling: rung-5 hits get counted (the
SERIALIZEdebug category logs them), and opt-in-per-pack pickle is a precondition written into the sandbox work, because a sandboxed worker that can still hand the parent a pickle owns the parent.
Context¶
The 2026-08 reviews converged on one scoping error in 0017: "the security clock starts at external rollout" conflates two populations. External pack authors arrive at the rollout -- but external users of the author's own packs exist today, and they execute unhashed native binaries from a mutable single-maintainer index on every install. The trust-boundary argument that defers compat work does not defer artifact integrity. Hence this record, and hence its ordering: integrity (hashes) before authenticity (signing), both before any sandbox story.
Consequences¶
- The generated manifest becomes the integrity anchor: everything an
env installs is either pixi-locked or hash-pinned by us. Landed
(2026-09): the wheels are in the manifest, so the "load-bearing
coincidence" (
--as-issparing the side-channel wheels) is no longer load-bearing, and the side channel it protected is gone. - Farm CI grows a qualification stage; wheel publishing slows down by one smoke run. Accepted.
- ADR-0011's "no regression vs vanilla ComfyUI" remains true for code execution but was never true for the wheel channel (vanilla has no wheel channel); this ADR stops using that argument for item 2.