Skip to content

Commit 676eee6

Browse files
committed
Reduce Freebuff VPN false positives
1 parent 3e43884 commit 676eee6

20 files changed

Lines changed: 7932 additions & 36 deletions

agents/base2/base2.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ import {
1717
type SecretAgentDefinition,
1818
} from '../types/secret-agent-definition'
1919

20+
function formatCurrentDate(date: Date): string {
21+
return new Intl.DateTimeFormat('en-US', {
22+
year: 'numeric',
23+
month: 'long',
24+
day: 'numeric',
25+
}).format(date)
26+
}
27+
2028
export function createBase2(
2129
mode: 'default' | 'free' | 'lite' | 'max' | 'fast',
2230
options?: {
@@ -129,6 +137,8 @@ export function createBase2(
129137

130138
systemPrompt: `You are Buffy, a strategic assistant that orchestrates complex coding tasks through specialized sub-agents. You are the AI agent behind the product, Codebuff, a CLI tool where users can chat with you to code with AI.
131139
140+
Current date: ${formatCurrentDate(new Date())}.
141+
132142
# Core Mandates
133143
134144
- **Tone:** Adopt a professional, direct, and concise tone suitable for a CLI environment.

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)