mirror of
https://github.com/Twigpine/node.git
synced 2026-11-10 13:11:37 -10:00
An external review found three costs that outlive the request or the boot that paid for them. The scan token was sealed with a key minted per boot, so a restart or a rolling deploy made every outstanding continuation undecryptable and the handler reads an unopenable token as absent. A caller walking a large inventory could be sent back to the front indefinitely. The key is now derived from the node's Ed25519 seed with HKDF, so it is the same after a reload, under a distinct salt and info string so it is not the signing key and cannot be turned against signatures. Rotation is a version bump in the info string. An earlier comment rejected derivation on the grounds that surviving restarts bought nothing; that is exactly what it buys, and the comment now says so. The rule byte ceiling was summed after the page had already been fetched, so it truncated the request without bounding the work: the allocation and the transfer had happened. The budget now bounds the query itself. The cut lands on a repo boundary, which is not cosmetic: a mid-repo cut leaves a partial rule set, and a partial rule set at the gate is indistinguishable from a repo with no rules, so it would fail open and serve an object those rules withheld. Only fully loaded repos are gated. The query always admits the first rule-carrying repo of a page, so the bound is the budget plus one repo rather than the budget; without that a single oversized repo would put the cut at the cursor and every retry would reproduce the same page. The old check carried a not-exhausted condition so a short final page could not turn a complete scan into a permanent shed. That condition is gone because the taint no longer keys on page length; it keys on the query having left repos unloaded. A short final page that fits produces no cut and still 404s, and one that is cut is honestly incomplete and resumable. Discovery paged the whole repo table and stat'd every warm repo to pick a sixteen candidate window. Its comment called that acceptable because the cost was paid once, which was true when the sweep ran once per boot. This round made the sweep periodic, so an upgraded node with one unrepairable row paid a full table scan on every run, forever. The load now stops once the window is full. It collects one candidate past the cap so that running out still distinguishes a warm set that fits from one that does not, which is what the reset arm needs now that the total count is no longer known. Ordering is unchanged, so an attacker who mints repos still cannot move the boundary. Verified by mutation: a per-boot key strands a continuation across a restart, using the signing seed directly defeats the domain separation, summing bytes after the fetch materializes the whole page, paging to exhaustion buys pages the window cannot use, and reading the fit under cap from the window length loses the reset.