…rk is reachable, drops replays and hides refs/mirror
An independent read of the opt-in kind-30618 mirror found four gaps:
- trailLists only checked profile and states, so a blocktrails.json copied from
any other repository and listing the marked commit passed. The trail's
pubkeyBase must now carry the followed agent's x-only key.
- the marked commit was never required to be the moved-to commit or in its
history; merge-base --is-ancestor now checks it after the fetch.
- a validly signed older state could roll branches back when a newer one had
been held by the rate limit. The record keeps newestSeenAt and drops anything
older; an equal one (the catch-up resend) is kept.
- a state with a partial or garbled chain/txo/commit read as "no mark", which
switches the trail check off. It now reads as no state.
Also: refs/mirror/ joins uploadpack.hideRefs, because the fetch lands every
branch there before any verdict and a held branch was still fetchable by name.
The verdict text no longer implies chain verification. Two existing tests are
updated for the stricter rules; four cases added. 150 forge tests pass.
Co-Authored-By: jjohare <github@thedreamlab.uk>
What
Four hardening fixes to the opt-in kind-30618 mirror (40efb47, bd55eda, 80a83d9). The mirror is off unless config.mirror is set, so default installs are unaffected. These came out of porting the mirror to Rust (solid-pod-rs, solid-pod-rs-forge) and having it reviewed independently.
Also: refs/mirror/ is added to uploadpack.hideRefs. The fetch lands every branch there before any verdict, so a branch the mirror held back was still fetchable by name from the served repo. The verdict text no longer reads as chain verification (the chain is not consulted; the stance that the browser checks it is unchanged).
Not in this PR
Residual items left alone: DNS rebinding between the host check and git's own resolution, no fetch size cap beyond the 60 s timeout, and apply being awaited inside the socket loop.
Tests
node --test --test-concurrency=1 forge/test.js: 150 pass (was 149). Two existing tests are updated for the stricter rules (the verdict test now supplies a key; the replay test expects the new reason). Added: partial/garbled marks read as null, foreign trail refused, unreachable mark refused, trailBelongsTo cases.