1 Reference Abuse Enforcement
picklemustard edited this page 2026-09-07 15:49:27 -04:00
This file contains ambiguous Unicode characters

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 admission and abuse enforcement

Anonymous submissions use one PostgreSQL admission lock for queue capacity, three accepted submissions per rolling 24 hours, and one outstanding build per canonical IP. Failures and cancellations count. The waiting limit is twenty. Idempotency-Key (16–128 letters, digits, underscores or hyphens) is scoped to the browser ownership hash; replaying the same normalized request returns the original job, while changing it returns 409. Rejections insert no build.

The browser's separate 30-day HttpOnly cookie owns cancellation. Verification alone grants no cancellation authority. Cancellation requires the configured Origin and either ownership or administrative authentication. Public DTOs expose only can_cancel, never ownership hashes or quota IPs. Responses are not cached. GET /api/v1/admission-status reports the current IP's allowance and queue use.

Migrations 0005 and 0006 preserve historical jobs, specs, and artifacts. Anonymous admission records are removed after 30 days; audit IP columns are anonymized after 30 days by API maintenance. External access-log retention must also be configured to 30 days. Structured audit logging no longer emits IPs.

Bans and recovery

Twenty request-rate rejections in sixty seconds, or ten invalid/replayed verification attempts in five minutes, trigger an abuse event. Quotas, queue saturation, expired verification, and dependency failures do not cause strikes. PostgreSQL serializes strikes and unblocks. Strike durations within thirty days are one hour, twenty-four hours, then seven days; later strikes remain seven days. Requests during a current ban do not extend its duration.

The API and gateway share a complete Redis ban snapshot with a fifteen-second lifetime. Readiness and entries reside in one hash, so eviction cannot leave an independent ready marker authorizing a missing ban. Missing state must be fully rebuilt from committed PostgreSQL history before admission resumes. Rebuilds and administrative changes share a database lock. Index/dependency errors fail closed.

Verified sessions are indexed by IP for revocation. Session issuance checks the ban snapshot atomically; it cannot race a strike to create an unrevoked session. Public log streams and downloads recheck enforcement at lease renewal. Unblocking does not restore sessions or reset quotas. Administrative listing/unblocking is available at /api/v1/admin/bans and /api/v1/admin/bans/unblock, with durable actor-attributed audit records. The UI is /admin/bans.

Deployment changes

Deploy API and gateway together with gbb:human:v2: session state. This deliberately requires existing browsers to verify again; historical records are unaffected. The gateway's PostgreSQL role now needs SELECT on jobs, plus SELECT/INSERT/UPDATE/ DELETE on abuse_strikes and abuse_audit, and USAGE on their sequences. It must not modify jobs or catalog/schema objects. S3 credentials remain read-only. Apply migrations with the API/database migration role before starting gateways.

Redis ACLs need the existing request/lease commands plus HGET, HSET, DEL, SADD, SMEMBERS, and session-index ZRANGE/ZADD/ZREMRANGEBYSCORE. Restrict keys to gbb:enforcement:* and the appropriate gbb:human:v2:* namespace; the API's log leases also use gbb:human:log-stream:*. Multi-key scripts require standalone Redis rather than Redis Cluster cross-slot operation.

Real PostgreSQL/Redis tests cover concurrent admission, rolling quotas, idempotency, ownership, escalation, unblocking, retention, session revocation, and complete/partial Redis index loss. Full Kubernetes execution and ingress acceptance remain separate work.