Skip to content

Commit 33ccf45

Browse files
authored
Reduce Freebuff VPN false positives with Spur (#714)
1 parent 87f14aa commit 33ccf45

19 files changed

Lines changed: 7922 additions & 36 deletions

common/src/types/freebuff-session.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,31 @@ export type FreebuffIpPrivacySignal =
6565
| 'hosting'
6666
| 'service'
6767

68+
export type FreebuffSpurStatus =
69+
| 'not_checked'
70+
| 'clean'
71+
| 'suspicious'
72+
| 'failed'
73+
74+
export type FreebuffPrivacyDecision =
75+
| 'allowed_clean'
76+
| 'ipinfo_suspicious_spur_clean'
77+
| 'corroborated_block'
78+
| 'cloudflare_tor_block'
79+
| 'spur_failed_limited'
80+
| 'ipinfo_failed_limited'
81+
| 'limited_other'
82+
83+
export type FreebuffPrivacyProviderDecision =
84+
| 'not_checked'
85+
| 'cloudflare_tor'
86+
| 'ipinfo_clean'
87+
| 'ipinfo_failed'
88+
| 'ipinfo_only'
89+
| 'spur_failed'
90+
| 'corroborated_soft'
91+
| 'corroborated_hard'
92+
6893
export interface FreebuffLimitedModeReason {
6994
/** Present for limited access so the model picker can explain why the
7095
* reduced model set is shown without re-running geo/IP logic locally. */

docs/environment-variables.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- Server secrets: validated in `packages/internal/src/env-schema.ts` (used via `@codebuff/internal/env`).
77
- Runtime/OS env: pass typed snapshots instead of reading `process.env` throughout the codebase.
88
- `IPINFO_TOKEN` is required; free-mode country gating uses it to check IPinfo privacy signals for VPN/proxy/Tor/relay/hosting traffic.
9+
- `SPUR_TOKEN` is required; hard VPN/proxy/Tor/residential-proxy free-mode blocks require Spur Context API corroboration. In allowlisted countries, a successful clean Spur result overrides IPinfo privacy signals back to full access, while a Spur lookup failure falls back to limited access.
910
- `CODEBUFF_FULL_TELEMETRY=true` or `CODEBUFF_FULL_TELEMETRY_IDS=user-id,email@example.com`
1011
disables client analytics sampling for targeted debugging. Use sparingly because it can send full CLI log payloads.
1112

docs/freebuff-waiting-room.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ All endpoints authenticate via the standard `Authorization: Bearer <api-key>` or
181181
- Existing active+unexpired row, **different model** → reject with `model_locked` (HTTP 409); `active_instance_id` is **not** rotated so the other CLI stays valid. Client must DELETE the session before switching.
182182
- Existing active+expired row → reset to queued with fresh `queued_at` and the requested `model` (re-queue at back).
183183

184-
Before any of those state transitions, the handler requires a resolved allowlisted country and a successful IPinfo privacy check. IPinfo `anonymous`, `vpn`, `proxy`, `tor`, `relay`, `res_proxy`, `hosting`, and `service` signals are blocked; privacy lookup failures fail closed.
184+
Before any of those state transitions, the handler requires a resolved country and successful IPinfo/Spur privacy checks. Unsupported countries enter limited Freebuff access. In allowlisted countries, IPinfo privacy signals still receive full access when Spur returns clean context, fall back to limited access when Spur lookup fails, and hard-block only when Spur corroborates VPN/proxy/Tor/residential-proxy traffic. IPinfo lookup failures fail closed into limited access.
185185

186186
Response shapes:
187187

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE "free_mode_country_access_cache" ADD COLUMN "spur_ip_privacy_signals" text[];--> statement-breakpoint
2+
ALTER TABLE "free_mode_country_access_cache" ADD COLUMN "spur_status" text;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE "free_mode_country_access_cache" ADD COLUMN "privacy_decision" text;--> statement-breakpoint
2+
ALTER TABLE "free_mode_country_access_cache" ADD COLUMN "privacy_provider_decision" text;

0 commit comments

Comments
 (0)