Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ axum = "0.8"
bytes = "1"
clap = { version = "4.5", features = ["derive", "env"] }
flate2 = "1"
# default-features off drops the `hashbrown` backend (and its allocator-api2 /
# foldhash / equivalent deps); the std `HashMap` backend is plenty for this.
lru = { version = "0.18", default-features = false }
prometheus = { version = "0.14", default-features = false }
subtle = "2"
tokio = { version = "1", features = [
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ Every flag has an environment-variable equivalent.
| `--fetch-ttl-seconds` | `GITCACHEPROXY_FETCH_TTL_SECONDS` | `10` | Skip upstream fetch if refreshed within this window (`0` = always fetch) |
| `--max-concurrent-requests` | `GITCACHEPROXY_MAX_CONCURRENT_REQUESTS` | `64` | Max concurrent in-flight requests; excess queue (`0` = unlimited) |
| `--max-decoded-body-mb` | `GITCACHEPROXY_MAX_DECODED_BODY_MB` | `512` | Cap on a decoded upload-pack request body, in MiB (bounds memory / gzip bombs) |
| `--cache-max-mb` | `GITCACHEPROXY_CACHE_MAX_MB` | `0` | Cap on total on-disk mirror cache, in MiB; evicts least-recently-used idle mirrors when exceeded (`0` = unlimited, no eviction) |
| `--git-binary` | `GITCACHEPROXY_GIT_BINARY` | `git` | Path to git |

Endpoints: `/healthz`, `/readyz`, `/metrics` (Prometheus).
Expand Down Expand Up @@ -206,8 +207,9 @@ explicit before you expose it:
not place it on an untrusted one without a token and TLS.
- **DoS knobs.** `--max-concurrent-requests` caps concurrent upstream
clone/fetch work and `--max-decoded-body-mb` bounds request-body memory
(defusing a decompression bomb). The on-disk cache still grows unbounded (no
eviction yet - see the roadmap), so isolate and monitor the cache volume.
(defusing a decompression bomb). `--cache-max-mb` bounds on-disk growth by
evicting least-recently-used idle mirrors; it defaults to `0` (unlimited), so
set it - or isolate and monitor the cache volume - on an untrusted network.
- **Read-only.** Only `git-upload-pack` (clone/fetch) is served; `git-receive-pack`
(push) is refused and upstream is only ever pulled from, never written.

Expand All @@ -233,7 +235,6 @@ rely on it.

Not yet implemented, in rough priority order:

- LRU disk eviction of idle mirrors (the cache currently grows unbounded).
- Per-repo latency histograms (fetch/serve durations); per-repo counters exist.
- A background/scheduled refresh option (today every `info/refs` triggers an
on-demand, TTL-coalesced fetch).
Expand Down
8 changes: 8 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ pub struct Config {
#[arg(long, env = "GITCACHEPROXY_MAX_DECODED_BODY_MB", default_value_t = 512)]
pub max_decoded_body_mb: u64,

/// Maximum total size, in MiB, of the on-disk mirror cache. When a clone or
/// fetch pushes the total over this, least-recently-used idle mirrors are
/// evicted in the background until it is back under; an evicted mirror is
/// transparently re-cloned on its next request. `0` = unlimited: no eviction
/// and no accounting, so the cache grows without bound (the default).
#[arg(long, env = "GITCACHEPROXY_CACHE_MAX_MB", default_value_t = 0)]
pub cache_max_mb: u64,

/// Path to the git binary.
#[arg(long, env = "GITCACHEPROXY_GIT_BINARY", default_value = "git")]
pub git_binary: String,
Expand Down
Loading