This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Anonymous verification
This implements the human-session portion of the public-service remediation. It is an opt-in deployment mode, not completion of the public-launch plan.
Set these environment variables on gbb-server:
| Variable | Value |
|---|---|
GBB_HUMAN_ENABLED |
true |
GBB_PUBLIC_ORIGIN |
Canonical HTTPS origin, e.g. https://build.example.com, without a trailing slash |
GBB_TURNSTILE_SITE_KEY |
Public Turnstile widget key |
GBB_TURNSTILE_SECRET |
Server secret, injected from a Secret |
GBB_HUMAN_REDIS_URL |
Private Redis URL, e.g. rediss://verification:password@redis.internal:6379/0 |
Redis is also a first-class redis: block in the config file. GBB_HUMAN_REDIS_URL
remains supported and is what existing deployments use; the block's discrete
fields (redis.host, redis.user, redis.password_file, redis.db,
redis.tls.*) are the alternative, and keep the ACL password out of the
environment. Connection timeouts and retry policy are the same either way.
redis.db is how two deployments share one instance, since the key prefixes are
fixed.
| GBB_HUMAN_TRUSTED_PROXIES | Space-separated immediate Traefik source CIDRs; empty trusts no headers |
Use a dedicated Redis ACL identity restricted to gbb:human:*. The client
requires PING, EVAL, INCR, PEXPIRE, EXISTS, SET, GET, PTTL, TIME,
ZREMRANGEBYSCORE, ZCARD, ZADD, ZSCORE, and ZREM, plus its connection
handshake commands (AUTH, HELLO, SELECT when selecting a database, CLIENT SETINFO).
Scripts run on standalone Redis; a Redis Cluster needs a common hash-slot namespace
before it can be used. Redis errors fail protected requests closed. Startup checks
connectivity; it does not prove that every scripted command is ACL-authorized.
Validate the exchange in staging with the actual ACL before deployment.
Traefik must overwrite X-Real-IP with the canonical client address derived from
its trusted Cloudflare chain. Only requests arriving from the configured immediate
proxy ranges can use that header. Never trust a range that includes public clients.
Origin isolation, Cloudflare authenticated origin connections, and Authelia are
separate deployment work; setting these variables does not establish that boundary.
Configure Turnstile for the origin hostname. The widget uses action public-action.
If a Content Security Policy is deployed, allow the Turnstile script and frame from
https://challenges.cloudflare.com according to Cloudflare's integration guidance.
Following Cloudflare’s server-side validation requirements,
the provider is called server-side with a ten-second deadline. Success requires
matching hostname/action and a challenge no older than five minutes. Provider
configuration failures/outages return retryable 503, not an invalid-human verdict.
API and browser behavior
GET /api/v1/human-sessionreturns enabled/verified, remaining seconds, public site key, and action. Disabled mode returns{"enabled":false}.POST /api/v1/human-sessionaccepts{"token":"<Turnstile response>"}and requires an exact matching Origin header. Five exchanges per IP per minute are allowed by an atomic Redis counter, before contacting Turnstile.- Successful exchange sets separate
__Host-gbb-browser(30 days) and__Host-gbb-human(15 minutes) Secure, HttpOnly, SameSite=Strict cookies. Redis stores only hashes of capabilities and of browser/IP bindings. The browser cookie alone grants no verification. Ownership cancellation is not yet implemented; this cookie is reserved for that later migration. - Sessions have a fixed 15-minute Redis TTL. Reads do not extend it. Browser/IP mismatches require another challenge; IPv4-mapped IPv6 addresses are normalized. Token reuse cannot mint another session, including across concurrent replicas.
- Builds and each download request require verification in anonymous mode, even when an API token or old session is supplied. Builds also require matching Origin. Already admitted builds continue when verification expires.
- The frontend removes the token gate in anonymous mode and opens an accessible modal when a build or download needs verification. Canceling or failing the challenge leaves the mounted build form intact. No verification tokens enter local storage. Valid build drafts persist across reloads in browser local storage; restored selections are checked against the current catalog.
- Build lists/details use an explicit public field allowlist. Raw errors, module repository URLs/ref overrides, expert arguments, and worker identities are omitted. Sanitized public progress is served from PostgreSQL with resumable SSE and shared Redis stream limits. Raw logs and cancellation remain administrator-only pending durable browser ownership. The existing token-authenticated admin API remains in place.
- Downloads stream through the API, require a succeeded job and listed artifact,
and set
Cache-Control: no-store. No storage URL is returned in anonymous mode. This does not yet provide the separately deployed gateway, ranges, concurrency leases, periodic ban checks, or idle transfer deadlines from the full plan.
Remaining launch requirements
Do not treat verification as build quota enforcement. Anonymous jobs do not use legacy per-token quotas. Durable per-IP admission quotas, bans/revocation and ban-index recovery, shared general request limits, IPv6 prefix aggregation, Authelia, browser cancellation ownership, full shared diagnostic archives, the gateway, and Kubernetes execution isolation are outstanding. Existing ingress/application request limits should remain enabled; supplied credentials no longer bypass the application's pre-authentication IP limiter. The local CLI remains unchanged.
Validation
Run go test ./..., then run the real Redis suite against an isolated test Redis:
GBB_TEST_REDIS_URL=redis://127.0.0.1:6379/0 go test -race ./internal/human
The test uses its own random key namespace and removes only those keys. It checks cross-browser/IP rejection, fixed expiry, replay races, the pre-provider exchange limit, and failure after Redis disconnect. HTTP tests cover cookie attributes, Origin checks, IP normalization, proxy-header trust, and credential bypass. Provider tests mock Siteverify; production Turnstile keys and the real ingress chain still require a browser acceptance test in the target environment.
Shared request enforcement
Anonymous deployments now always wire a Redis pre-authentication request limiter,
independent of the legacy per-replica limiter switch. All /api/ requests,
including invalid authentication and verification attempts, use canonical client
IP subjects from the configured trusted proxy chain. Each address has a shared
10 requests/second bucket with burst 40. IPv6 traffic must also fit a separate
10 requests/second, burst-40 bucket for its /64. Prefix throttling does not ban
addresses. Artifact requests (including ranges and failed verification) also
consume a rolling allowance of ten requests per minute per exact IP.
All applicable limits are checked and consumed in one Redis script using Redis server time. Rejections return 429 with rounded-up Retry-After; Redis failure returns 503 with Retry-After: 5, without falling back to local enforcement. Health probes and static assets remain outside this application limiter. The existing four-stream lease limit remains independent of request throttles.
Allow the dedicated Redis ACL access to gbb:enforcement:* in addition to the
human-session namespace, and commands EVAL, TIME, HMGET, HSET, PEXPIRE,
ZREMRANGEBYSCORE, ZCARD, ZRANGE and ZADD. Request keys contain hashed subjects
and expire after sixty seconds of inactivity. Use a standalone Redis endpoint;
the multi-subject scripts are not Redis Cluster cross-slot compatible.
Durable abuse events, escalating bans, administrative unblocking and atomic
build quotas are described in abuse enforcement. The
download gateway enforces shared transfer concurrency.
Ingress limits and origin restrictions still require deployment configuration. Configure defaults with GBB_PUBLIC_REQUEST_RPS (10),
GBB_PUBLIC_REQUEST_BURST (40), and GBB_DOWNLOAD_REQUESTS_PER_MINUTE (10).
All replicas must use identical settings. Values must be positive integers.
With unusually low refill rates or large bursts, idle bucket TTLs grow to the
time needed to refill the bucket so expiry cannot reset its allowance early.
For separate protected delivery and API cutover, see the download gateway.
Guide
- Home
- Getting Started
- Building Godot
- Configuration
- Modules and Administration
- API
- Architecture
- Deployment and Operations
- Security
- Troubleshooting
- Development
Reference
- API
- Architecture
- Modules
- Module registry
- Admin
- Artifacts
- Deployment
- Kubernetes execution
- Durable execution store
- Immutable build configuration
- Download gateway
- Public logs
- Anonymous verification
- Abuse enforcement
- Public service remediation
- Authelia administration
- CI/CD
- macOS SDK