Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
65ba137
feat(node,git): cap concurrent served git ops with a 503 load-shed (#62)
Jul 10, 2026
db4de84
feat(node,config): add write-pool and per-caller read-cap knobs (#62)
Jul 10, 2026
2434dde
fix(node,git): isolate authed pushes in a dedicated write pool (#62)
Jul 10, 2026
fc4c206
fix(node,git): per-caller concurrency sub-cap on the read pool (#62)
Jul 10, 2026
2c264e0
fix(node,git): bound and reap the info/refs advertisement (#62)
Jul 10, 2026
57c6e01
fix(node,git): bound and reap the withheld-blob pack build (#62)
Jul 10, 2026
6336657
docs(node,config): reconcile the concurrency-cap comments with the fi…
Jul 10, 2026
5069cd1
fix(node,concurrency): resolve #174 code-review findings
Jul 10, 2026
3b1fa54
docs(config): add GITLAWB_MAX_CONCURRENT_GIT_OPS to .env.example (#174)
Jul 10, 2026
362ee34
fix(node,git): bound the rev-list stage under drive_git_child so a hu…
Jul 11, 2026
4983b85
fix(node): key the per-caller read cap on source IP, not the signed D…
Jul 12, 2026
e444bc0
fix(node): draw the receive-pack advertisement from the write pool (#…
Jul 12, 2026
71389e6
fix(node): bound the withheld-blob walk at the shared blob_paths seam…
Jul 12, 2026
ab0ea24
docs(node): correct the git-service-timeout coverage note (#174)
Jul 12, 2026
87a7e40
fix(review): close the withheld-walk watchdog reused-pgid race (#174)
Jul 12, 2026
e750c30
fix(review): cap the receive-pack advertisement per source so anon ca…
Jul 12, 2026
c35452e
test(node): vet the withheld-walk bound end to end; use the configure…
Jul 12, 2026
454e59b
docs(node): the withheld-walk is bounded by the service timeout, not …
Jul 12, 2026
79b9ee5
fix(node): shed the served-git pool before the DB and cap per-source …
Jul 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,32 @@ GITLAWB_MAX_PACK_BYTES=2147483648

# Max seconds a served git upload-pack / receive-pack (clone / push) may run
# before it is aborted with a 504. Bounds a hung git that would otherwise pin a
# worker and, on push, the repo write lock. Does NOT cover the info/refs
# advertisement or the withheld-blob path, which remain unbounded. Default 600.
# worker and, on push, the repo write lock. Also bounds the info/refs
# advertisement and the withheld-blob pack build (#174). Default 600.
GITLAWB_GIT_SERVICE_TIMEOUT_SECS=600

# Max concurrent git read ops (upload-pack + info/refs advertisements) served at
# once, a global pool separate from the push pool below. Over-cap sheds a clean
# 503 + Retry-After. Anonymous reads draw from here, so pair it with
# GITLAWB_MAX_CONCURRENT_READS_PER_CALLER (below) so one caller cannot monopolize
# the pool. Default 128.
GITLAWB_MAX_CONCURRENT_GIT_OPS=128

# Max concurrent git-receive-pack (push) operations, in a pool separate from the
# read pool (GITLAWB_MAX_CONCURRENT_GIT_OPS) so anonymous reads cannot shed an
# authenticated push at admission. Over-cap sheds a 503 + Retry-After. Default 32.
GITLAWB_MAX_CONCURRENT_GIT_PUSHES=32

# Max concurrent read ops (upload-pack + info/refs advertisements) a single caller
# may hold, so one caller cannot monopolize the read pool. Keyed per-DID when
# signed, else per-source-IP. The per-IP key is only as granular as
# GITLAWB_TRUSTED_PROXY below: left unset, a node behind an edge/NAT keys all
# anonymous callers on the edge IP and this collapses to one global anonymous cap.
# Set GITLAWB_TRUSTED_PROXY for per-client keying; a high-fanout caller (CI behind
# one NAT) should authenticate for a per-DID budget or the operator raises this.
# Default 16.
GITLAWB_MAX_CONCURRENT_READS_PER_CALLER=16

Comment thread
coderabbitai[bot] marked this conversation as resolved.
# ── Push rate limiting (git-receive-pack flood brake) ─────────────────────
# Max receive-pack requests (info/refs advertisement + push POST) per client
# IP per hour. 0 disables. Default 600.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ Important node settings:
| `GITLAWB_REQUIRE_SIGNED_PEER_WRITES` | Require signed peer announce/sync writes. |
| `GITLAWB_AUTO_SYNC` | Enable automatic sync from known peers. |
| `GITLAWB_MAX_PACK_BYTES` | Max git pack body size for smart-HTTP routes. |
| `GITLAWB_GIT_SERVICE_TIMEOUT_SECS` | Max seconds a served git upload-pack/receive-pack may run before it is aborted (504). Default 600. Does not bound `info/refs` or the withheld-blob path. |
| `GITLAWB_GIT_SERVICE_TIMEOUT_SECS` | Max seconds a served git upload-pack, receive-pack, or `info/refs` advertisement may run before it is aborted (504). Default 600. Also bounds the withheld-blob classification walk (on both the upload-pack serve and receive-pack replication paths), which is reaped at the deadline. |
| `GITLAWB_TIGRIS_BUCKET` | Optional S3/Tigris shared repo storage bucket. |
| `GITLAWB_PINATA_JWT` | Optional Pinata/IPFS warm-storage pinning. |
| `GITLAWB_IRYS_URL` | Optional Irys/Arweave permanent anchoring. |
Expand Down
12 changes: 9 additions & 3 deletions crates/gitlawb-node/src/api/ipfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use std::str::FromStr;
use crate::auth::AuthenticatedDid;
use crate::error::{AppError, Result};
use crate::git::store;
use crate::git::visibility_pack::{allowed_blob_set_for_caller, has_path_scoped_rule};
use crate::git::visibility_pack::{allowed_blob_set_for_caller_bounded, has_path_scoped_rule};
use crate::state::AppState;
use crate::visibility::{visibility_check, Decision};

Expand Down Expand Up @@ -142,10 +142,16 @@ pub async fn get_by_cid(
let is_public = repo.is_public;
let owner = repo.owner_did.clone();
let caller_for_walk = caller_owned.clone();
// Full-history walk shells out to git — keep it off the async runtime.
let git_bin = state.git_bin.clone();
let walk_timeout =
std::time::Duration::from_secs(state.config.git_service_timeout_secs);
// Full-history walk shells out to git — keep it off the async runtime,
// bounded and reaped like the served-git ops (#174).
let walk = tokio::task::spawn_blocking(move || {
allowed_blob_set_for_caller(
allowed_blob_set_for_caller_bounded(
&rp,
&git_bin,
walk_timeout,
&r,
is_public,
&owner,
Expand Down
Loading
Loading