# How Freebuff Handles Environment Variable Validation Across Test Packages

> Discover how Freebuff ensures consistent environment variable validation across test packages using a centralized Zod schema for type-safe access throughout your codebase.

- Repository: [Codebuff/freebuff](https://github.com/CodebuffAI/freebuff)
- Tags: how-to-guide
- Published: 2026-08-20

---

**Freebuff uses a centralized Zod-based schema in [`common/src/env-schema.ts`](https://github.com/CodebuffAI/freebuff/blob/main/common/src/env-schema.ts) to validate environment variables, with test packages importing a validated `env` object from [`common/src/env.ts`](https://github.com/CodebuffAI/freebuff/blob/main/common/src/env.ts) to ensure consistent type-safe access across the entire codebase.**

Freebuff is an open-source AI coding assistant that enforces strict environment variable validation to prevent runtime misconfigurations. The project uses a **shared validation layer** that both production code and test suites rely on, eliminating drift between test mocks and real deployment settings.

## The Centralized Validation Architecture

According to the CodebuffAI/freebuff source code, all environment variable handling flows through two core files in the `common` package.

### Schema Definition in [`common/src/env-schema.ts`](https://github.com/CodebuffAI/freebuff/blob/main/common/src/env-schema.ts)

The `clientEnvSchema` uses Zod to declare every public variable (`NEXT_PUBLIC_*`) that client-side code may access:

```typescript
// common/src/env-schema.ts
import { z } from "zod";

export const clientEnvSchema = z.object({
  NEXT_PUBLIC_CB_ENVIRONMENT: z.string().optional(),
  NEXT_PUBLIC_CB_API_URL: z.string().url().optional(),
  // ... additional public variables
});

export type ClientEnv = z.infer<typeof clientEnvSchema>;

// Server-only variables extend the client schema
export const serverEnvSchema = clientEnvSchema.extend({
  OPEN_ROUTER_API_KEY: z.string().min(1),
  DATABASE_URL: z.string().startsWith("postgres://"),
});

export type ServerEnv = z.infer<typeof serverEnvSchema>;

```

The `clientProcessEnv` helper filters `process.env` to only keys matching the schema's declared variables, preventing accidental exposure of undeclared secrets.

### Runtime Parsing in [`common/src/env.ts`](https://github.com/CodebuffAI/freebuff/blob/main/common/src/env.ts)

The [`env.ts`](https://github.com/CodebuffAI/freebuff/blob/main/env.ts) module executes validation immediately on import, failing fast on any configuration errors:

```typescript
// common/src/env.ts
import { clientEnvSchema, clientProcessEnv } from "./env-schema";

const parsedEnv = clientEnvSchema.safeParse(clientProcessEnv);

if (!parsedEnv.success) {
  throw new Error(
    `Invalid client environment variables: ${JSON.stringify(parsedEnv.error.format())}`
  );
}

export const env = parsedEnv.data;

```

This **fail-fast pattern** ensures that invalid environments never reach application logic. Tests can catch this behavior by asserting on the thrown error.

## How Test Packages Consume the Validation Layer

Freebuff's test packages do not reimplement validation logic. Instead, they import the same `env` object used in production, guaranteeing identical behavior.

### SDK Test Package Validation

The SDK tests verify that environment-file access policies are enforced regardless of test environment overrides:

```typescript
// sdk/src/__tests__/read-files.test.ts
import { env } from "../../common/src/env";

test("blocks access to .env files regardless of process.env", () => {
  // Even with this override, the env policy blocks file reads
  process.env.SOME_SECRET_KEY = "exposed";
  
  // env.OPEN_ROUTER_API_KEY remains typed and validated
  expect(() => accessEnvFile(".env.local")).toThrow(PermissionError);
});

```

The [`run-file-filter.test.ts`](https://github.com/CodebuffAI/freebuff/blob/main/run-file-filter.test.ts) file similarly confirms that environment validation executes before any file-filter callbacks run, preventing secret leakage through misconfigured filters.

### Agent Test Package Validation

Agent tests validate that AI agents respect typed environment variables during execution:

```typescript
// agents/__tests__/base2.test.ts
import { env } from "../../common/src/env";

test("agent uses API key only when properly configured", () => {
  // TypeScript enforces env.OPEN_ROUTER_API_KEY exists and is string
  const agent = new Agent({
    apiKey: env.OPEN_ROUTER_API_KEY,
  });
  
  expect(agent.isConfigured).toBe(!!env.OPEN_ROUTER_API_KEY);
});

```

The [`base3.test.ts`](https://github.com/CodebuffAI/freebuff/blob/main/base3.test.ts) suite extends this to verify graceful degradation when optional variables are absent.

## Testing Validation Failures Directly

Freebuff includes explicit tests for the validation mechanism itself, ensuring schema changes maintain expected error behavior:

```typescript
// sdk/src/__tests__/env-validation.test.ts
import { clientEnvSchema, clientProcessEnv } from "../../common/src/env-schema";

test("safeParse returns error for type mismatches", () => {
  const invalidEnv = {
    ...clientProcessEnv,
    NEXT_PUBLIC_CB_ENVIRONMENT: 123, // wrong type
  };
  
  const result = clientEnvSchema.safeParse(invalidEnv);
  expect(result.success).toBe(false);
  expect(result.error!.issues[0].path).toContain("NEXT_PUBLIC_CB_ENVIRONMENT");
});

test("throws on unexpected environment shape", () => {
  // Simulate fresh import with bad environment
  jest.isolateModules(() => {
    process.env = { INVALID_VAR: "value" };
    expect(() => require("../../common/src/env")).toThrow(/Invalid client environment/);
  });
});

```

## Propagation of Schema Changes

Because **all packages import from the same [`common/src/env.ts`](https://github.com/CodebuffAI/freebuff/blob/main/common/src/env.ts) module**, modifying the schema immediately affects every test suite:

| Change Type | Impact Across Test Packages |
|-------------|---------------------------|
| Add required variable | All tests fail until `process.env` updated; single fix propagates |
| Make variable optional | Tests gain flexibility; no code changes required |
| Type narrowing (e.g., `url()` validation) | Invalid test values caught immediately at parse time |
| Server-only addition | Client tests unaffected; server tests gain new typed field |

This **single source of truth** prevents the common bug pattern where tests pass with mocked values that would fail in production.

## Summary

- **Freebuff validates environment variables using Zod schemas defined in [`common/src/env-schema.ts`](https://github.com/CodebuffAI/freebuff/blob/main/common/src/env-schema.ts)** with separate client and server variants
- **[`common/src/env.ts`](https://github.com/CodebuffAI/freebuff/blob/main/common/src/env.ts) parses `process.env` on import**, throwing immediately for invalid configurations
- **Test packages import the validated `env` object directly**, ensuring test behavior matches production
- **SDK tests verify file-access policies respect env validation** before secret leakage can occur
- **Agent tests confirm AI components use typed environment variables** with proper optional handling
- **Schema changes propagate automatically** to all test suites through the shared module dependency

## Frequently Asked Questions

### Does Freebuff allow different environment variables in tests versus production?

No. All test packages import from [`common/src/env.ts`](https://github.com/CodebuffAI/freebuff/blob/main/common/src/env.ts), which uses the identical schema validation as production. Tests can override `process.env` values before importing, but the variable names and types must match the schema exactly.

### How does Freebuff prevent secrets from appearing in test logs?

The `clientEnvSchema` explicitly excludes server-only variables. Tests importing `env` receive only the filtered `ClientEnv` type. Server tests use a separate `serverEnvSchema` with additional secrets, but both schemas apply the same runtime validation pattern.

### What happens when a required environment variable is missing in CI?

The `safeParse` check in [`env.ts`](https://github.com/CodebuffAI/freebuff/blob/main/env.ts) throws an error with a formatted Zod error message describing which variables are missing or invalid. This causes immediate test or application failure, alerting developers to configuration gaps before deployment.

### Can tests validate custom environment shapes without modifying the shared schema?

Tests can import `clientEnvSchema` and use Zod's `.extend()` or `.pick()` methods to create temporary validation schemas for specific test scenarios. However, the production `env` export always uses the canonical schema to prevent divergence.