mirror of
https://github.com/Twigpine/node.git
synced 2026-11-09 05:20:05 -10:00
* fix(node): add per-IP flood brake to repo/agent creation endpoints The recurring spam-repo floods are not bypassing the iCaptcha gate — they pass it. The enforced level (3) draws only machine-solvable deterministic challenges (arithmetic/algebra/sequence), and the /v1/challenge API lets the caller pin the easy type, so a bot mints a fresh throwaway did:key, solves a real proof bound to that DID, and creates a repo. The per-DID creation limiter never trips because each DID makes a single create call. Add a per-client-IP rate limiter to the creation route group (repos, register, fork, issues, pulls), reusing the same IpRateLimiter the push path already uses against the identical DID-farm bypass. It wraps the auth layer (outermost) so flood traffic is rejected before signature verification. Default 120/hour/IP, GITLAWB_CREATE_RATE_LIMIT overrides, 0 disables. * docs(env): document GITLAWB_CREATE_RATE_LIMIT in .env.example * fix: apply CodeRabbit auto-fixes Fixed 1 file(s) based on 1 unresolved review comment. Co-authored-by: CodeRabbit <[email protected]> * test(node): unit-test the per-IP creation brake runs before auth The route-level coverage (repo_creation_is_rate_limited_by_ip) is #[sqlx::test] and needs Postgres, so it is skipped in the plain unit-test pass. Add a DB-free middleware test that layers the per-IP creation limiter over an always-401 auth stand-in and asserts an exhausted IP is rejected with 429 before auth runs — the ordering the DID-farm flood defense relies on. --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: CodeRabbit <[email protected]>
171 lines
9.3 KiB
Bash
171 lines
9.3 KiB
Bash
# gitlawb node — environment variables
|
|
# Copy to .env and fill in your values.
|
|
# All variables are optional unless marked REQUIRED.
|
|
|
|
# ── Node identity ─────────────────────────────────────────────────────────
|
|
# Path to the node's Ed25519 keypair PEM file.
|
|
# Generate with: gl identity new
|
|
GITLAWB_KEY=/data/keys/identity.pem
|
|
|
|
# Publicly reachable URL of this node (used in peer announcements)
|
|
GITLAWB_PUBLIC_URL=https://your-node.example.com
|
|
|
|
# ── Server ────────────────────────────────────────────────────────────────
|
|
GITLAWB_HOST=0.0.0.0
|
|
GITLAWB_PORT=7545
|
|
|
|
# ── Storage ───────────────────────────────────────────────────────────────
|
|
GITLAWB_REPOS_DIR=/data/repos
|
|
|
|
# PostgreSQL connection URL. Required.
|
|
# When using the bundled docker-compose, this is wired automatically.
|
|
DATABASE_URL=postgresql://gitlawb:changeme@localhost:5432/gitlawb
|
|
|
|
# ── Database pool & startup resilience ────────────────────────────────────
|
|
# Maximum connections in the PostgreSQL pool. A cap, not a floor —
|
|
# connections open lazily. Size against the DB server's max_connections,
|
|
# remembering admin tooling opens its own pool.
|
|
GITLAWB_DB_MAX_CONNECTIONS=20
|
|
# Seconds a request waits for a pool connection before failing with 503.
|
|
GITLAWB_DB_ACQUIRE_TIMEOUT_SECS=5
|
|
# Upper bound on each startup connect+migrate attempt, in seconds. Keep it
|
|
# generous enough for a peer instance to finish migrating (the migration
|
|
# advisory lock is held across a deploy); on expiry the attempt is retried.
|
|
GITLAWB_DB_CONNECT_TIMEOUT_SECS=60
|
|
# Startup retry backoff while the database is unavailable: first delay and
|
|
# ceiling, in seconds. The node stays up serving 503s (with a truthful
|
|
# /ready) instead of crash-looping.
|
|
GITLAWB_DB_RETRY_INITIAL_SECS=5
|
|
GITLAWB_DB_RETRY_MAX_SECS=60
|
|
|
|
# ── IPFS pinning (Pinata) ─────────────────────────────────────────────────
|
|
# Get a JWT at https://app.pinata.cloud/developers/api-keys
|
|
GITLAWB_PINATA_JWT=
|
|
GITLAWB_PINATA_UPLOAD_URL=https://uploads.pinata.cloud/v3/files
|
|
|
|
# ── Arweave permanent anchoring (Irys devnet) ─────────────────────────────
|
|
# Leave empty to disable Arweave anchoring.
|
|
GITLAWB_IRYS_URL=https://devnet.irys.xyz
|
|
|
|
# ── Base L2 smart contracts ───────────────────────────────────────────────
|
|
GITLAWB_CHAIN_RPC_URL=https://sepolia.base.org
|
|
GITLAWB_CONTRACT_DID_REGISTRY=0x8046284116C5ac6724adbBf860feBeA85692d574
|
|
GITLAWB_CONTRACT_NAME_REGISTRY=0x73094B9DAb2421878A20Abed1497001fbD51302c
|
|
|
|
# $GITLAWB ERC20 token (Base mainnet).
|
|
GITLAWB_TOKEN=0x5F980Dcfc4c0fa3911554cf5ab288ed0eb13DBa3
|
|
|
|
# ── On-chain PoS (operators — required to earn rewards) ───────────────────
|
|
# Set both of the next two to enable Proof-of-Stake mode. With both set, the
|
|
# node verifies its registration on startup and posts heartbeats automatically.
|
|
# Leave empty to run without on-chain PoS (local dev / pre-launch).
|
|
|
|
# Deployed GitlawbNodeStaking contract address.
|
|
GITLAWB_CONTRACT_NODE_STAKING=
|
|
|
|
# Operator wallet private key (0x-prefixed hex). Used to sign heartbeats.
|
|
# Use a dedicated wallet with only enough ETH for gas — not your treasury.
|
|
GITLAWB_OPERATOR_PRIVATE_KEY=
|
|
|
|
# If true, the node refuses to start unless registered and currently active.
|
|
# Leave false while bootstrapping; flip to true once your stake is confirmed.
|
|
GITLAWB_OPERATOR_STRICT_MODE=false
|
|
|
|
# Heartbeat cadence in hours. Must be < 24 with headroom. Default: 20.
|
|
GITLAWB_HEARTBEAT_INTERVAL_HOURS=20
|
|
|
|
# ── docker-compose Postgres password ──────────────────────────────────────
|
|
# Only used when running via `docker compose up` with the bundled Postgres.
|
|
POSTGRES_PASSWORD=changeme
|
|
|
|
# ── P2P networking ────────────────────────────────────────────────────────
|
|
GITLAWB_P2P_PORT=7546
|
|
# Comma-separated HTTP peer URLs to announce to on startup.
|
|
# The binary also ships with bootstrap-peers.json; set
|
|
# GITLAWB_BOOTSTRAP_DISABLE_SEEDS=true for isolated dev/test networks.
|
|
GITLAWB_BOOTSTRAP_PEERS=
|
|
GITLAWB_BOOTSTRAP_DISABLE_SEEDS=false
|
|
# Require signatures on peer announce/sync write routes. Keep false during
|
|
# rolling upgrades so existing live nodes can still communicate.
|
|
GITLAWB_REQUIRE_SIGNED_PEER_WRITES=false
|
|
|
|
# Require the authenticated pusher to be the repo owner on git-receive-pack.
|
|
# A valid did:key signature is authentication, not authorization: anyone can
|
|
# sign as their own DID. When true, pushes from a non-owner DID are rejected.
|
|
# Keep false until the repo owner is ready for owner-only writes.
|
|
GITLAWB_ENFORCE_OWNER_PUSH=false
|
|
|
|
# Comma-separated libp2p multiaddrs.
|
|
# Example: /ip4/1.2.3.4/udp/7546/quic-v1/p2p/12D3KooW...
|
|
GITLAWB_P2P_BOOTSTRAP=
|
|
|
|
# ── Access control ────────────────────────────────────────────────────────
|
|
# Reserved for private-read mode. Public/private repo read enforcement is not
|
|
# wired in the current live release; do not rely on this for private repositories.
|
|
GITLAWB_PUBLIC_READ=true
|
|
|
|
# Maximum git smart-HTTP pack request size, in bytes.
|
|
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.
|
|
GITLAWB_GIT_SERVICE_TIMEOUT_SECS=600
|
|
|
|
# ── 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.
|
|
GITLAWB_PUSH_RATE_LIMIT=600
|
|
|
|
# ── Creation rate limiting (repo/agent/issue/PR flood brake) ──────────────
|
|
# Max creation requests (POST /api/v1/repos, /api/register, fork, issues,
|
|
# pulls) per client IP per hour, in addition to the per-DID limit. The per-DID
|
|
# limit alone is bypassed by a did:key farm (one throwaway identity per repo),
|
|
# which is how spam-repo floods slip past it and the iCaptcha gate; the per-IP
|
|
# brake caps a single-source flood. Uses GITLAWB_TRUSTED_PROXY below to resolve
|
|
# the client IP. 0 disables. Default 120.
|
|
GITLAWB_CREATE_RATE_LIMIT=120
|
|
|
|
# ── Peer-sync rate limiting (per client IP, uses GITLAWB_TRUSTED_PROXY below) ─
|
|
# /api/v1/peers/announce and /api/v1/sync/notify accept unsigned requests from
|
|
# known peers and run at higher frequency, so a generous bucket. Separate from
|
|
# the trigger bucket so an unsigned notify flood can't drain trigger's quota.
|
|
# 0 disables. Default 600.
|
|
GITLAWB_PEER_WRITE_RATE_LIMIT=600
|
|
# /api/v1/sync/trigger requires a signature and fans out to every peer per call,
|
|
# so it gets a tight bucket. 0 disables. Default 60.
|
|
GITLAWB_SYNC_TRIGGER_RATE_LIMIT=60
|
|
|
|
# Which forwarded header the edge is trusted to set, used to resolve the real
|
|
# client IP for the push limiter. One of:
|
|
# (unset) — no trusted proxy: key on the socket peer address, ignore headers.
|
|
# fly — behind Fly's edge (trust Fly-Client-IP).
|
|
# x-forwarded-for — behind a single reverse proxy like Caddy/NGINX (trust the
|
|
# rightmost X-Forwarded-For hop).
|
|
# Only set this when a proxy you control actually fronts the node; trusting a
|
|
# forwarded header on a directly-exposed node lets clients spoof the key.
|
|
GITLAWB_TRUSTED_PROXY=
|
|
|
|
# ── Sync ─────────────────────────────────────────────────────────────────
|
|
# Enable automatic background sync from known peers
|
|
GITLAWB_AUTO_SYNC=false
|
|
|
|
# ── iCaptcha proof-of-intelligence gate ───────────────────────────────────
|
|
# Optional gate on create_repo + register: require callers to present an
|
|
# iCaptcha proof (X-ICaptcha-Proof header) earned at icaptcha.gitlawb.com.
|
|
# Default off = fully inert (no behavior change).
|
|
# off - gate disabled (default)
|
|
# shadow - verify + log would-be rejections, but always allow
|
|
# enforce - reject requests without a valid, strong-enough proof
|
|
ICAPTCHA_MODE=off
|
|
# Optional base64url Ed25519 public key override; if unset it is fetched from
|
|
# ICAPTCHA_URL/v1/pubkey at startup. Recommended in production: pinning the key
|
|
# removes the startup dependency on the iCaptcha service being reachable and
|
|
# avoids silently running inert if that one-time fetch fails.
|
|
ICAPTCHA_PUBKEY=
|
|
# Minimum proof difficulty level required to pass.
|
|
ICAPTCHA_REQUIRED_LEVEL=3
|
|
# Base URL of the iCaptcha service.
|
|
ICAPTCHA_URL=https://icaptcha.gitlawb.com
|