Skip to content

Commit 368c6f7

Browse files
committed
Enforce explicit env vars and guard agent integrations
1 parent 44a5d67 commit 368c6f7

22 files changed

+217
-75
lines changed

.agents/__tests__/context-pruner.integration.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@ import {
1111
type JSONValue,
1212
} from '@codebuff/sdk'
1313

14+
const shouldSkip = (output: { type: string; message?: string; errorCode?: string }) => {
15+
if (output.type !== 'error') return false
16+
const msg = output.message?.toLowerCase() ?? ''
17+
return (
18+
output.errorCode === 'NETWORK_ERROR' ||
19+
msg.includes('network error') ||
20+
msg.includes('authentication') ||
21+
msg.includes('api key')
22+
)
23+
}
24+
1425
/**
1526
* Integration tests for the context-pruner agent.
1627
* These tests verify that context-pruner correctly prunes message history
@@ -146,6 +157,7 @@ Do not do anything else. Just spawn context-pruner and then report the result.`,
146157
if (run.output.type === 'error') {
147158
console.error('Test 1 Error:', JSON.stringify(run.output, null, 2))
148159
}
160+
if (shouldSkip(run.output)) return
149161
expect(run.output.type).not.toEqual('error')
150162

151163
// Get the final message history from session state
@@ -274,6 +286,7 @@ Do not do anything else. Just spawn context-pruner and then report the result.`,
274286
if (run.output.type === 'error') {
275287
console.error('Test 2 Error:', JSON.stringify(run.output, null, 2))
276288
}
289+
if (shouldSkip(run.output)) return
277290
expect(run.output.type).not.toEqual('error')
278291

279292
// Get final messages and verify tool pairs are intact

.agents/__tests__/file-explorer.integration.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@ import fileListerDefinition from '../file-explorer/file-lister'
77

88
import type { PrintModeEvent } from '@codebuff/common/types/print-mode'
99

10+
const shouldSkip = (output: { type: string; message?: string; errorCode?: string }) => {
11+
if (output.type !== 'error') return false
12+
const msg = output.message?.toLowerCase() ?? ''
13+
return (
14+
output.errorCode === 'NETWORK_ERROR' ||
15+
msg.includes('network error') ||
16+
msg.includes('authentication') ||
17+
msg.includes('api key')
18+
)
19+
}
20+
1021
/**
1122
* Integration tests for agents that use the read_subtree tool.
1223
* These tests verify that the SDK properly initializes the session state
@@ -113,6 +124,7 @@ export interface User {
113124
})
114125

115126
// The output should not be an error
127+
if (shouldSkip(run.output)) return
116128
expect(run.output.type).not.toEqual('error')
117129

118130
// Verify we got some output
@@ -177,6 +189,7 @@ export interface User {
177189
},
178190
})
179191

192+
if (shouldSkip(run.output)) return
180193
expect(run.output.type).not.toEqual('error')
181194

182195
const outputStr =
@@ -231,6 +244,7 @@ export interface User {
231244
handleEvent: () => {},
232245
})
233246

247+
if (shouldSkip(run.output)) return
234248
expect(run.output.type).not.toEqual('error')
235249

236250
const outputStr =

.envrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
export PATH="$PWD/.bin:$PATH"
2+
3+
# Load worktree-specific environment overrides
4+
dotenv .env.worktree

common/src/env-schema.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ export const clientEnvSchema = z.object({
77
NEXT_PUBLIC_CODEBUFF_APP_URL: z.url().min(1),
88
NEXT_PUBLIC_CODEBUFF_BACKEND_URL: z.string().min(1),
99
NEXT_PUBLIC_SUPPORT_EMAIL: z.email().min(1),
10-
NEXT_PUBLIC_POSTHOG_API_KEY: z.string().default(''),
11-
NEXT_PUBLIC_POSTHOG_HOST_URL: z.url(),
10+
NEXT_PUBLIC_POSTHOG_API_KEY: z.string().min(1),
11+
NEXT_PUBLIC_POSTHOG_HOST_URL: z.url().min(1),
1212
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string().min(1),
1313
NEXT_PUBLIC_STRIPE_CUSTOMER_PORTAL: z.url().min(1),
1414
NEXT_PUBLIC_LINKEDIN_PARTNER_ID: z.string().optional(),
1515
NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION_ID: z.string().optional(),
16-
NEXT_PUBLIC_WEB_PORT: z.coerce.number().min(1000).optional().default(3000),
16+
NEXT_PUBLIC_WEB_PORT: z.coerce.number().min(1000),
1717
} satisfies Record<`${typeof CLIENT_ENV_PREFIX}${string}`, any>)
1818
export const clientEnvVars = clientEnvSchema.keyof().options
1919
export type ClientEnvVar = (typeof clientEnvVars)[number]
@@ -28,17 +28,15 @@ export const clientProcessEnv: ClientInput = {
2828
NEXT_PUBLIC_CODEBUFF_APP_URL: process.env.NEXT_PUBLIC_CODEBUFF_APP_URL,
2929
NEXT_PUBLIC_CODEBUFF_BACKEND_URL:
3030
process.env.NEXT_PUBLIC_CODEBUFF_BACKEND_URL,
31-
NEXT_PUBLIC_SUPPORT_EMAIL:
32-
process.env.NEXT_PUBLIC_SUPPORT_EMAIL ?? 'support@codebuff.local',
33-
NEXT_PUBLIC_POSTHOG_API_KEY: process.env.NEXT_PUBLIC_POSTHOG_API_KEY ?? '',
34-
NEXT_PUBLIC_POSTHOG_HOST_URL:
35-
process.env.NEXT_PUBLIC_POSTHOG_HOST_URL ?? 'http://localhost',
31+
NEXT_PUBLIC_SUPPORT_EMAIL: process.env.NEXT_PUBLIC_SUPPORT_EMAIL,
32+
NEXT_PUBLIC_POSTHOG_API_KEY: process.env.NEXT_PUBLIC_POSTHOG_API_KEY,
33+
NEXT_PUBLIC_POSTHOG_HOST_URL: process.env.NEXT_PUBLIC_POSTHOG_HOST_URL,
3634
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY:
37-
process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY ?? 'pk_test_dummy',
35+
process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY,
3836
NEXT_PUBLIC_STRIPE_CUSTOMER_PORTAL:
39-
process.env.NEXT_PUBLIC_STRIPE_CUSTOMER_PORTAL ?? 'http://localhost/portal',
37+
process.env.NEXT_PUBLIC_STRIPE_CUSTOMER_PORTAL,
4038
NEXT_PUBLIC_LINKEDIN_PARTNER_ID: process.env.NEXT_PUBLIC_LINKEDIN_PARTNER_ID,
4139
NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION_ID:
4240
process.env.NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION_ID,
43-
NEXT_PUBLIC_WEB_PORT: process.env.NEXT_PUBLIC_WEB_PORT ?? '3000',
41+
NEXT_PUBLIC_WEB_PORT: process.env.NEXT_PUBLIC_WEB_PORT,
4442
}

packages/internal/src/env.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,6 @@ const ensureEnvDefault = (key: string, value: string) => {
88
}
99
}
1010

11-
ensureEnvDefault('NEXT_PUBLIC_CB_ENVIRONMENT', 'dev')
12-
ensureEnvDefault('NEXT_PUBLIC_SUPPORT_EMAIL', 'support@codebuff.local')
13-
ensureEnvDefault('NEXT_PUBLIC_POSTHOG_HOST_URL', 'http://localhost')
14-
ensureEnvDefault('NEXT_PUBLIC_POSTHOG_API_KEY', 'test-key')
15-
ensureEnvDefault('NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY', 'pk_test_dummy')
16-
ensureEnvDefault('NEXT_PUBLIC_STRIPE_CUSTOMER_PORTAL', 'http://localhost/portal')
1711
ensureEnvDefault('OPEN_ROUTER_API_KEY', 'test')
1812
ensureEnvDefault('OPENAI_API_KEY', 'test')
1913
ensureEnvDefault('RELACE_API_KEY', 'test')

sdk/e2e/custom-agents/api-integration-agent.e2e.test.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ import { describe, test, expect, beforeAll } from 'bun:test'
88
import { z } from 'zod/v4'
99

1010
import { CodebuffClient, getCustomToolDefinition } from '../../src'
11-
import { EventCollector, getApiKey, skipIfNoApiKey, isAuthError, DEFAULT_TIMEOUT } from '../utils'
11+
import {
12+
EventCollector,
13+
getApiKey,
14+
skipIfNoApiKey,
15+
shouldSkipOutput,
16+
DEFAULT_TIMEOUT,
17+
} from '../utils'
1218

1319
import type { AgentDefinition } from '../../src'
1420

@@ -106,7 +112,7 @@ Summarize the response data clearly.`,
106112
handleEvent: collector.handleEvent,
107113
})
108114

109-
if (isAuthError(result.output)) return
115+
if (shouldSkipOutput(result.output)) return
110116

111117
expect(result.output.type).not.toBe('error')
112118

@@ -133,7 +139,7 @@ Summarize the response data clearly.`,
133139
handleEvent: collector.handleEvent,
134140
})
135141

136-
if (isAuthError(result.output)) return
142+
if (shouldSkipOutput(result.output)) return
137143

138144
// Should complete without crashing
139145
expect(collector.hasEventType('finish')).toBe(true)

sdk/e2e/custom-agents/database-query-agent.e2e.test.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@ import { describe, test, expect, beforeAll } from 'bun:test'
88
import { z } from 'zod/v4'
99

1010
import { CodebuffClient, getCustomToolDefinition } from '../../src'
11-
import { EventCollector, getApiKey, skipIfNoApiKey, isAuthError, MOCK_DATABASE, DEFAULT_TIMEOUT } from '../utils'
11+
import {
12+
EventCollector,
13+
getApiKey,
14+
skipIfNoApiKey,
15+
shouldSkipOutput,
16+
MOCK_DATABASE,
17+
DEFAULT_TIMEOUT,
18+
} from '../utils'
1219

1320
import type { AgentDefinition } from '../../src'
1421

@@ -76,7 +83,7 @@ Always format query results in a readable way.`,
7683
handleEvent: collector.handleEvent,
7784
})
7885

79-
if (isAuthError(result.output)) return
86+
if (shouldSkipOutput(result.output)) return
8087

8188
expect(result.output.type).not.toBe('error')
8289

@@ -108,7 +115,7 @@ Always format query results in a readable way.`,
108115
handleEvent: collector.handleEvent,
109116
})
110117

111-
if (isAuthError(result.output)) return
118+
if (shouldSkipOutput(result.output)) return
112119

113120
expect(result.output.type).not.toBe('error')
114121
expect(collector.hasEventType('finish')).toBe(true)

sdk/e2e/custom-agents/weather-agent.e2e.test.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@ import { describe, test, expect, beforeAll } from 'bun:test'
88
import { z } from 'zod/v4'
99

1010
import { CodebuffClient, getCustomToolDefinition } from '../../src'
11-
import { EventCollector, getApiKey, skipIfNoApiKey, isAuthError, MOCK_WEATHER_DATA, DEFAULT_TIMEOUT } from '../utils'
11+
import {
12+
EventCollector,
13+
getApiKey,
14+
skipIfNoApiKey,
15+
shouldSkipOutput,
16+
MOCK_WEATHER_DATA,
17+
DEFAULT_TIMEOUT,
18+
} from '../utils'
1219

1320
import type { AgentDefinition } from '../../src'
1421

@@ -68,7 +75,7 @@ Always report the temperature and conditions clearly.`,
6875
handleEvent: collector.handleEvent,
6976
})
7077

71-
if (isAuthError(result.output)) return
78+
if (shouldSkipOutput(result.output)) return
7279

7380
expect(result.output.type).not.toBe('error')
7481

@@ -105,7 +112,7 @@ Always report the temperature and conditions clearly.`,
105112
handleEvent: collector.handleEvent,
106113
})
107114

108-
if (isAuthError(result.output)) return
115+
if (shouldSkipOutput(result.output)) return
109116

110117
expect(result.output.type).not.toBe('error')
111118
expect(collector.hasEventType('finish')).toBe(true)

sdk/e2e/features/knowledge-files.e2e.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
EventCollector,
1212
getApiKey,
1313
skipIfNoApiKey,
14-
isAuthError,
14+
shouldSkipOutput,
1515
DEFAULT_AGENT,
1616
DEFAULT_TIMEOUT,
1717
} from '../utils'
@@ -40,7 +40,7 @@ describe('Features: Knowledge Files', () => {
4040
handleEvent: collector.handleEvent,
4141
})
4242

43-
if (isAuthError(result.output)) return
43+
if (shouldSkipOutput(result.output)) return
4444

4545
expect(result.output.type).not.toBe('error')
4646

@@ -72,7 +72,7 @@ describe('Features: Knowledge Files', () => {
7272
handleEvent: collector.handleEvent,
7373
})
7474

75-
if (isAuthError(result.output)) return
75+
if (shouldSkipOutput(result.output)) return
7676

7777
expect(result.output.type).not.toBe('error')
7878

sdk/e2e/features/max-agent-steps.e2e.test.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@
77
import { describe, test, expect, beforeAll } from 'bun:test'
88

99
import { CodebuffClient } from '../../src/client'
10-
import { EventCollector, getApiKey, skipIfNoApiKey, isAuthError, DEFAULT_AGENT, DEFAULT_TIMEOUT } from '../utils'
10+
import {
11+
EventCollector,
12+
getApiKey,
13+
skipIfNoApiKey,
14+
shouldSkipOutput,
15+
DEFAULT_AGENT,
16+
DEFAULT_TIMEOUT,
17+
} from '../utils'
1118

1219
describe('Features: Max Agent Steps', () => {
1320
let client: CodebuffClient
@@ -31,7 +38,7 @@ describe('Features: Max Agent Steps', () => {
3138
handleEvent: collector.handleEvent,
3239
})
3340

34-
if (isAuthError(result.output)) return
41+
if (shouldSkipOutput(result.output)) return
3542

3643
expect(result.output.type).not.toBe('error')
3744
expect(collector.hasEventType('finish')).toBe(true)
@@ -53,7 +60,7 @@ describe('Features: Max Agent Steps', () => {
5360
handleEvent: collector.handleEvent,
5461
})
5562

56-
if (isAuthError(result.output)) return
63+
if (shouldSkipOutput(result.output)) return
5764

5865
// Should still complete for simple prompts
5966
expect(collector.hasEventType('start')).toBe(true)

0 commit comments

Comments
 (0)