Skip to content

Replication/pin path exports withheld-subtree tree objects to public IPFS (write-side of #135) #172

Description

@beardthelion

Summary

The replication/pin path passes every non-blob object through unconditionally, so a withheld subtree's tree object is pinned to IPFS on push (Kubo or Pinata). Once pinned, the CID is announced to the public IPFS DHT and served by bitswap to any peer, disclosing the withheld subtree's child filenames and child oids off-node — bypassing the get_by_cid gate #135 adds. This is the write-side counterpart of #135 (which covers only the on-node GET /ipfs/{cid} read).

Where

  • crates/gitlawb-node/src/git/visibility_pack.rs:353replicable_objects_fail_closed filters !all_blob_oids.contains(oid) || allowed_blobs.contains(oid); trees are never in all_blob_oids, so they always pass. The doc comment states the now-wrong assumption: "commits and trees are structural, never content-withheld."
  • Candidate set includes trees: crates/gitlawb-node/src/git/push_delta.rs:178 list_all_objects (git cat-file --batch-all-objects); the delta path uses rev-list --objects.
  • Both pin backends consume the filtered set: crates/gitlawb-node/src/ipfs_pin.rs (Kubo), crates/gitlawb-node/src/pinata.rs (Pinata).
  • The pin CID is content-sha256 (crates/gitlawb-core/src/cid.rs:32), independent of repo object format.

Why it matters

This is live independent of the reachability caveat that makes get_by_cid dormant: repos init --object-format=sha1 (crates/gitlawb-node/src/git/store.rs:15), so get_by_cid cannot resolve a sha256 CID today — but the pin path pins by content-sha256 regardless, so the withheld tree bytes are fetchable by CID on the public IPFS network. Exposure is off-node and persists until GC/unpin; via Pinata it reaches public gateways. The confidentiality boundary is the same one get_tree and #135 protect (subtree child names + oids).

Confirmed: a withheld subtree's tree oid survives replicable_objects_fail_closed into the replicable/pinned set, while blob withholding is unaffected.

Scope

Write-side of the same KTD3 divergence as #135. The fix reuses #135's tree-reachability machinery: gate the replicable set on an anonymous replicable_tree_set (the caller = None allowed-tree-set), dropping withheld-subtree tree oids from replication exactly as blobs are handled via replicable_blob_set. Best done after #135 lands tree_paths.

Live only when a pin backend (GITLAWB_IPFS_API or GITLAWB_PINATA_JWT) is configured; both default empty.

Metadata

Metadata

Assignees

No one assigned

    Labels

    crate:nodegitlawb-node — the serving node and REST APIkind:securityVulnerability fix or hardeningsev:highMajor break or real security/trust risk, no easy workaroundsubsystem:storageBlob/object store, Arweave, IPFS, archivessubsystem:visibilityPath-scoped visibility and content withholding

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions