The replication object-set computation is duplicated across two live post-receive paths, and both are fail-closed visibility filters, so a one-sided change to one silently diverges what gets replicated to public IPFS/Pinata on the other.
The duplication
Both functions in crates/gitlawb-node/src/api/repos.rs inline the same pipeline:
replication_withheld_set(...) -> (announce, withheld)
- fail-closed on
None (not announceable -> pin nothing)
resolve_candidates_for_push(...)
if pin_set.full_scan { fail_closed_full_scan_objects(...) } else { replicable_objects(pin_set.candidates, &withheld_set) }
resolve_drain_object_list (def ~L896), tail L923-988
pinata_object_list_for_refs (def ~L1021), tail L1031-1081
The full-scan branch is duplicated with the same fail_closed_full_scan_objects call/args shape, and the delta branch is line-for-line identical (replicable_objects(pin_set.candidates, &withheld_set) at L986 and L1080). No shared helper wraps the tail; the doc comment on pinata_object_list_for_refs even says it is "Exactly like resolve_drain_object_list."
Both are live, non-test callers:
resolve_drain_object_list -> the coalesced-drain worker (~L880)
pinata_object_list_for_refs -> the detached Pinata replication task in the push handler (~L2037)
Why it matters
These functions decide what content leaves the node for public replication. A future visibility-rule change to the withheld/candidate/full-scan logic applied to one and missed in the other changes replication on one push path only. Concrete: a stricter full-scan variant applied to resolve_drain_object_list but not pinata_object_list_for_refs -> a non-coalesced push whose candidate resolution is a full scan replicates a withheld blob to Pinata/public IPFS on the Pinata path, while the drain path correctly withholds it. It would pass any test that exercises only the drain path.
Fix
Extract the (withheld -> candidates -> full_scan-vs-delta) tail into one shared helper both call, so the fail-closed decision lives in one place.
Not a live leak today (both copies currently agree); this is drift prevention. Surfaced during the #174 F2 review (the Pinata re-derivation added the second copy).
The replication object-set computation is duplicated across two live post-receive paths, and both are fail-closed visibility filters, so a one-sided change to one silently diverges what gets replicated to public IPFS/Pinata on the other.
The duplication
Both functions in
crates/gitlawb-node/src/api/repos.rsinline the same pipeline:replication_withheld_set(...)->(announce, withheld)None(not announceable -> pin nothing)resolve_candidates_for_push(...)if pin_set.full_scan { fail_closed_full_scan_objects(...) } else { replicable_objects(pin_set.candidates, &withheld_set) }resolve_drain_object_list(def ~L896), tail L923-988pinata_object_list_for_refs(def ~L1021), tail L1031-1081The full-scan branch is duplicated with the same
fail_closed_full_scan_objectscall/args shape, and the delta branch is line-for-line identical (replicable_objects(pin_set.candidates, &withheld_set)at L986 and L1080). No shared helper wraps the tail; the doc comment onpinata_object_list_for_refseven says it is "Exactly likeresolve_drain_object_list."Both are live, non-test callers:
resolve_drain_object_list-> the coalesced-drain worker (~L880)pinata_object_list_for_refs-> the detached Pinata replication task in the push handler (~L2037)Why it matters
These functions decide what content leaves the node for public replication. A future visibility-rule change to the withheld/candidate/full-scan logic applied to one and missed in the other changes replication on one push path only. Concrete: a stricter full-scan variant applied to
resolve_drain_object_listbut notpinata_object_list_for_refs-> a non-coalesced push whose candidate resolution is a full scan replicates a withheld blob to Pinata/public IPFS on the Pinata path, while the drain path correctly withholds it. It would pass any test that exercises only the drain path.Fix
Extract the
(withheld -> candidates -> full_scan-vs-delta)tail into one shared helper both call, so the fail-closed decision lives in one place.Not a live leak today (both copies currently agree); this is drift prevention. Surfaced during the #174 F2 review (the Pinata re-derivation added the second copy).