mirror of
https://github.com/Twigpine/node.git
synced 2026-11-08 17:55:53 -10:00
* fix(node): reconcile public-read messaging with per-repo enforcement GITLAWB_PUBLIC_READ is read nowhere except a startup warning, while read enforcement actually happens per repository through is_public and path-scoped visibility rules. The flag's help text, the startup warning, .env.example, and the readiness audit all still claimed private-read enforcement was unwired. The help and warning now state the flag is reserved and inert, and point at the real per-repo control. A config test asserts the rendered help neither claims enforcement is missing nor omits that the flag does nothing. Closes #338. * docs: drop the stale private-read priority entry * chore: refresh PR head
373 lines
23 KiB
Bash
373 lines
23 KiB
Bash
# Twigpine 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. Must name a key file, not a
|
|
# directory: a trailing slash, a final `.` or `..`, and `..` traversal are
|
|
# refused so the path cannot retarget a parent. A `~/` value must stay under
|
|
# home after expansion. Bare `identity.pem` is still legal.
|
|
# Generate with: gl identity new
|
|
GITLAWB_KEY=/data/keys/identity.pem
|
|
|
|
# Path to the node's persistent libp2p identity key file. Must include a
|
|
# directory, because the node will not keep its p2p identity key in the working
|
|
# directory. A value that cannot name a securable key file (a bare filename,
|
|
# `..` traversal, a trailing slash, the filesystem root, or a `~/` path that
|
|
# escapes home) is refused before the node binds, so the process exits.
|
|
# Anything wrong with the storage itself (a symlinked or non-directory parent,
|
|
# an unsafe cwd or ancestor, an unreadable or malformed key) leaves p2p off
|
|
# while HTTP keeps serving, logged at error as p2p_identity_key_load_failed and
|
|
# counted by the gitlawb_p2p_identity_key_load_failed metric. /health still
|
|
# reports healthy in that state, so alert on the event or the metric. Fixing
|
|
# the storage and restarting restores the same PeerId.
|
|
# On Unix it is created 0600 inside a 0700 directory. A key directory that
|
|
# grants access beyond its owner is tightened to 0700 on start; one closed too
|
|
# far is refused with a chmod 700 remedy rather than widened. On other
|
|
# platforms no permissions are enforced.
|
|
# If the node logs that it tightened a key directory that was GROUP OR WORLD
|
|
# WRITABLE, treat the key that was sitting there as possibly exposed: delete
|
|
# it so a fresh identity is generated on the next start. An ordinary 0755
|
|
# directory is tightened too, but others could not read a 0600 key or replace
|
|
# its directory entry, so do not rotate for that case. A directory that was
|
|
# merely closed too far is refused, not tightened, and no key in it was ever
|
|
# exposed.
|
|
# Keep it on a persistent volume so the PeerId survives redeploys.
|
|
# Default: ~/.gitlawb/p2p.key
|
|
#GITLAWB_P2P_KEY=/data/keys/p2p.key
|
|
|
|
# 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=48
|
|
# Maximum connections in the DEDICATED advisory-lock pool, separate from the
|
|
# pool above. Every in-flight repo write pins one connection here for its whole
|
|
# duration, so this is a hard ceiling on simultaneous writes node-wide: size it
|
|
# to expected peak concurrent writers, not small. Keeping it separate is what
|
|
# stops a push burst from starving ordinary request handlers. Budget
|
|
# (GITLAWB_DB_MAX_CONNECTIONS + this) per node against the server's
|
|
# max_connections, times node count, plus admin tooling.
|
|
GITLAWB_DB_LOCK_POOL_MAX_CONNECTIONS=40
|
|
# Upper bound, in seconds, on any object-storage transfer that runs while a
|
|
# per-repo write lock is HELD (the archive download inside acquire_write and the
|
|
# upload inside release). These were free before the lock's connection was
|
|
# pinned to the guard; now an unbounded stall holds a lock-pool slot, and enough
|
|
# stalls deny every write on the node. The bound applies PER SPAN and there are
|
|
# two (the acquire-side refresh, which covers the existence check and download
|
|
# together, and the release-side upload), so worst-case slot occupancy is about
|
|
# twice this value plus the git work between them. Read it together with the pool
|
|
# size above and with GITLAWB_GIT_SERVICE_TIMEOUT_SECS.
|
|
GITLAWB_LOCK_HELD_TRANSFER_TIMEOUT_SECS=300
|
|
# 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 a peer write to prove its DID on every transport: RFC 9421 signatures
|
|
# on the announce/sync routes, and an Ed25519 payload signature on gossip
|
|
# ref-update events. Keep false during rolling upgrades so existing live nodes
|
|
# can still communicate. Upgrade every gossip-publishing peer to a build that
|
|
# signs events before setting this true, or their updates are dropped on
|
|
# arrival with no error visible on their side.
|
|
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
|
|
# mint a key, derive its DID and sign, so with this off every signed caller may
|
|
# push to every repository, private ones included. On by default.
|
|
#
|
|
# Set to false only for a rolling upgrade whose pushers are not yet the repo
|
|
# owner. Note that delegated and CI keys count as non-owners: UCAN git/push is
|
|
# verified but not yet honored for authorization, so they cannot push while this
|
|
# is on. See docs/RUN-A-NODE.md.
|
|
GITLAWB_ENFORCE_OWNER_PUSH=true
|
|
|
|
# Comma-separated libp2p multiaddrs.
|
|
# Example: /ip4/1.2.3.4/udp/7546/quic-v1/p2p/12D3KooW...
|
|
GITLAWB_P2P_BOOTSTRAP=
|
|
|
|
# ── Access control ────────────────────────────────────────────────────────
|
|
# Reserved and currently inert. Repo reads are gated per repository by
|
|
# is_public and path-scoped visibility rules; this flag changes nothing.
|
|
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. Also bounds both info/refs
|
|
# advertisements, the withheld-blob pack build, and the push-side candidate
|
|
# discovery (rev-list / cat-file), all reaped via process-group teardown (#174).
|
|
# On the path-scoped upload-pack path the withheld-blob classification walk and
|
|
# the pack serve share ONE deadline, so this value bounds their COMBINED duration
|
|
# rather than giving each stage a full budget: a walk that consumes it leaves the
|
|
# serve nothing and the clone gets a 504. Serving large path-scoped repos may
|
|
# need a higher value here than when each stage was budgeted separately.
|
|
# Must be 1..=3153600000 (100 years): the node derives deadlines from this value,
|
|
# and a larger one cannot be represented. Default 600.
|
|
GITLAWB_GIT_SERVICE_TIMEOUT_SECS=600
|
|
|
|
# Max seconds the storage-ACQUISITION phase of a served git op may run before the
|
|
# request is shed with a 503, separate from the git-run timeout above. A
|
|
# concurrency permit is taken before this phase and GITLAWB_GIT_SERVICE_TIMEOUT_SECS
|
|
# only starts once git spawns, so without this a stalled backend (a hung Tigris
|
|
# HEAD/GET, or a hung pg advisory-lock iteration on push) pins the permit and drains
|
|
# the pool until every later request 503s. On expiry the permit is released
|
|
# (fail-closed). Kept separate because acquisition and git execution are distinct
|
|
# cost centers. Must be positive; set very large to effectively disable. Default 30.
|
|
GITLAWB_GIT_ACQUIRE_TIMEOUT_SECS=30
|
|
|
|
# Max concurrent git READ ops (upload-pack + the upload-pack info/refs
|
|
# advertisement) served at once, a global pool separate from the push pool below.
|
|
# The anon receive-pack info/refs advertisement has its OWN pool (see below), not
|
|
# this one. 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) POST operations, in a pool separate from
|
|
# the read pool (GITLAWB_MAX_CONCURRENT_GIT_OPS) so anonymous reads cannot shed an
|
|
# authenticated push at admission. The anon receive-pack info/refs advertisement
|
|
# runs in a SEPARATE pool of the same size (disjoint from this one), so an
|
|
# advertisement flood cannot shed a push either. Over-cap sheds a 503 +
|
|
# Retry-After. Default 32.
|
|
GITLAWB_MAX_CONCURRENT_GIT_PUSHES=32
|
|
|
|
# Max pushes PARKED at once waiting for the per-repo write lease of the SAME repo.
|
|
# A parked push holds its already-buffered pack body in memory, so this bounds that
|
|
# memory for a hot repo. Past the cap the newest push sheds a clean 503 +
|
|
# Retry-After ("repo is busy with another push") instead of joining the queue; a
|
|
# push to a DIFFERENT repo is never affected. The lease holder is not counted.
|
|
# Raising GITLAWB_MAX_CONCURRENT_GIT_PUSHES does not raise this; set it explicitly.
|
|
# Default 8.
|
|
GITLAWB_REPO_LEASE_MAX_WAITERS=8
|
|
|
|
# Max concurrent post-push pin loops (IPFS + Pinata pin_new_objects) across all
|
|
# repos. The per-repo encrypt-task set caps the pin-task COUNT; this caps how many
|
|
# of those loops RUN CONCURRENTLY, and so how much MB-scale object-id list memory is
|
|
# held WHILE BEING PINNED. It does not bound retained memory in general: on the local
|
|
# IPFS path the caller builds its list before this pool is entered, so a loop parked
|
|
# waiting for a permit still holds its full list, and how many park is capped only
|
|
# per repo. Do not size memory from this knob alone. A loop DEFERS (waits) when the
|
|
# pool is full, never drops a pin. Default 8.
|
|
GITLAWB_MAX_CONCURRENT_PIN_TASKS=8
|
|
|
|
# Max concurrent read ops (upload-pack + the upload-pack info/refs advertisement)
|
|
# a single caller may hold, so one caller cannot monopolize the read pool. Keyed
|
|
# on the resolved SOURCE IP, never the DID: a signature does not move a caller off
|
|
# this cap. The source-IP key is only as granular as GITLAWB_TRUSTED_PROXY below:
|
|
# left unset, a node behind an edge/NAT keys all callers on the edge IP and this
|
|
# collapses to one global cap. Set GITLAWB_TRUSTED_PROXY for per-client keying; a
|
|
# high-fanout caller (CI behind one NAT) then needs the operator to raise this.
|
|
# Default 16.
|
|
GITLAWB_MAX_CONCURRENT_READS_PER_CALLER=16
|
|
|
|
# Two further per-source concurrency caps exist on the PUSH side but have NO
|
|
# environment variable of their own: both are DERIVED as
|
|
# GITLAWB_MAX_CONCURRENT_GIT_PUSHES / 8, with a floor of 1. They are not settable
|
|
# independently, so raising the push pool raises both proportionally, and the
|
|
# default push pool of 32 gives each a cap of 4.
|
|
# * The anon receive-pack info/refs advertisement cap: one source IP may hold at
|
|
# most this many slots in the dedicated advert pool, so saturating that pool
|
|
# takes ~8 distinct source IPs.
|
|
# * The authenticated receive-pack POST cap: one source IP may hold at most this
|
|
# many WRITE-pool slots. This one is load-bearing for push availability, since
|
|
# it is acquired before the global write permit: without it, one host minting
|
|
# disposable did:key identities could open enough slow pushes to monopolize the
|
|
# write pool and 503 every other source (the push rate limiter caps arrival
|
|
# rate, not in-flight concurrency, and owner enforcement can be turned off for
|
|
# a rolling upgrade).
|
|
# Keyed on the resolved source IP, never the DID, so a DID farm does not defeat
|
|
# them; keying granularity follows GITLAWB_TRUSTED_PROXY like the read cap above.
|
|
|
|
# ── 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
|
|
|
|
# ── /ipfs/{cid} visibility-walk admission (#174) ──────────────────────────
|
|
# GET /ipfs/{cid} runs a per-repo full-history git walk in a blocking thread to
|
|
# decide whether the caller may read a path-scoped blob. It is publicly reachable,
|
|
# so it is bounded to keep a permissionless caller from fanning out unbounded
|
|
# concurrent walks and exhausting blocking-pool threads + PIDs.
|
|
# Max concurrent /ipfs walks across all callers (a pool of its own, disjoint from
|
|
# the served-git pools). Over-cap sheds a 503. Default 32.
|
|
GITLAWB_MAX_CONCURRENT_IPFS_WALKS=32
|
|
# Max concurrent /ipfs walks a single SOURCE IP may hold (keyed like the git
|
|
# per-caller caps via GITLAWB_TRUSTED_PROXY; reject-before-insert bounded map).
|
|
# Default 4.
|
|
GITLAWB_IPFS_WALK_PER_SOURCE=4
|
|
# Max legacy (NULL-provenance) repos probed per single /ipfs request, bounding the
|
|
# scan-fallback fan-out (git cat-file per candidate repo) for an anonymous caller. A
|
|
# truncated scan sheds a retryable 503, never a false 404. Default 256.
|
|
GITLAWB_IPFS_MAX_LEGACY_PROBES=256
|
|
# Max repo ROWS one /ipfs request's legacy scan may read from the database. The probe
|
|
# ceiling above only counts once a probe runs, and quarantined or private repos are
|
|
# denied before that, so without this an all-denying inventory paged the whole repo
|
|
# table for one anonymous request. A truncated scan sheds a retryable 503 carrying a
|
|
# sealed `continuation` token; echo it as ?scan= to resume, so a holder buried past the
|
|
# ceiling is reachable in ceil(repos / ceiling) + 1 requests. Raising this also raises
|
|
# the per-caller /ipfs work allowance, since each page is charged to it. Lowering it
|
|
# sharpens a coarse oracle: laddering to the end reveals the node's total repo count to
|
|
# within one ceiling. Default 2048.
|
|
GITLAWB_IPFS_MAX_LEGACY_SCAN_ROWS=2048
|
|
# Max EXPENSIVE path-scope visibility walks per single /ipfs request (only a
|
|
# blob in a path-scoped repo costs a full-history walk). Over-cap repos are
|
|
# skipped without a verdict and the scan continues; if the object is then found
|
|
# nowhere the request sheds a retryable 503 instead of a false 404. The effective
|
|
# cap is the tighter of this value and the node's internal per-request ceiling of
|
|
# 17, so values above 17 have no effect; lower values do tighten it. Default 64.
|
|
GITLAWB_IPFS_MAX_REPOS_WALKED=64
|
|
# Ceiling on repos one /ipfs request may VISIT past the visibility gate. Each
|
|
# visit costs a repo acquire — on a Tigris cache miss a full archive download,
|
|
# so this is also the worst-case object-store fetch count per request — plus a
|
|
# cat-file probe. On exhaustion the scan stops and sheds a retryable 503.
|
|
# Default 1024.
|
|
GITLAWB_IPFS_MAX_REPO_VISITS=1024
|
|
# Absolute wall-clock budget for one admitted /ipfs request's acquire+walk
|
|
# lifetime (all stages of the whole scan). Per-stage clamps bound the acquire
|
|
# and walk stages to the remaining budget, and no stage starts once it is
|
|
# exhausted (the scan then sheds a retryable 503). The object-type probe and
|
|
# content-read cat-file subprocesses are budget-checked before starting AND each
|
|
# run under their own deadline (the lesser of GITLAWB_GIT_SERVICE_TIMEOUT_SECS and
|
|
# the remaining budget), reaped via process-group teardown, so a hung cat-file
|
|
# cannot hold the request's walk slot past it. One hang path is still unbounded:
|
|
# the probe's object-store readability check is a plain filesystem sweep with
|
|
# nothing to reap, so a wedged filesystem can hold the slot past the deadline.
|
|
# Must be 1..=3153600000 (100 years): the node derives an Instant deadline from
|
|
# this value, and a larger one cannot be represented. Default 600.
|
|
GITLAWB_IPFS_REQUEST_BUDGET_SECS=600
|
|
# Shorter budget (seconds) for the pre-walk CID resolve: the lookup that maps a
|
|
# requested CID to its git oid(s), which runs while the scarce walk admission is
|
|
# already held. A well-formed CID with no pin row does no probe and no walk work,
|
|
# so without this a stalled lookup could hold a walk slot for the whole request
|
|
# budget while nothing walked. The effective deadline is the lesser of this and
|
|
# the remaining request budget; walk and probe work stay on the request budget,
|
|
# so a slow but progressing scan is never shed by it.
|
|
# Must be 1..=3153600000 (100 years). Default 10.
|
|
GITLAWB_IPFS_RESOLVE_BUDGET_SECS=10
|
|
# Max /ipfs/{cid} requests per client IP per hour (route flood brake, distinct
|
|
# from the concurrency caps above). 0 disables. Default 600.
|
|
GITLAWB_IPFS_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
|