Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions kiloclaw/.dev.vars.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
NEXTAUTH_SECRET=dev-secret-change-me
INTERNAL_API_SECRET=dev-internal-secret
GATEWAY_TOKEN_SECRET=dev-gateway-secret-kiloclaw
# Override WORKER_ENV to "development" for local dev.
# Production default is set in wrangler.jsonc. This override disables JWT env
# claim enforcement and uses "dev-" prefixed Fly app names.
# Override WORKER_ENV to "development" for local development.
# Production default is set in wrangler.jsonc. This selects the development
# Fly app naming prefix ("dev-") for per-user app creation.
WORKER_ENV=development

# Optional: Override KiloCode base URL (dev)
Expand Down Expand Up @@ -54,6 +54,3 @@ OPENCLAW_ALLOWED_ORIGINS=http://localhost:3000,http://localhost:8795,http://claw
# In wrangler dev, it connects to the remote Postgres via the Hyperdrive service.
# To use a local Postgres instead, add "localConnectionString" to the hyperdrive
# config in wrangler.jsonc (see https://developers.cloudflare.com/hyperdrive/configuration/local-development/).

# Development
DEV_MODE=true
2 changes: 0 additions & 2 deletions kiloclaw/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ The alarm runs for ALL statuses (not just `running`). `destroying` short-circuit
| `TELEGRAM_DM_POLICY` | Telegram DM policy (passed through to machine) |
| `DISCORD_DM_POLICY` | Discord DM policy (passed through to machine) |
| `OPENCLAW_ALLOWED_ORIGINS` | Comma-separated origins for Control UI WebSocket (e.g., `http://localhost:3000,http://localhost:8795`). Production: `https://claw.kilo.ai,https://claw.kilosessions.ai` |
| `DEV_MODE` | Enable dev mode features |

### Fly.io Regions

Expand Down Expand Up @@ -245,7 +244,6 @@ User config is transported to the machine via environment variables set in the F
| `KILOCODE_MODELS_JSON` | User config (DO), JSON-serialized | Available model list |
| `KILOCODE_API_BASE_URL` | Worker env | API base URL override |
| `AUTO_APPROVE_DEVICES` | Hardcoded `true` | Skip device pairing |
| `OPENCLAW_DEV_MODE` | Worker env (`DEV_MODE`) | Dev mode features |
| `TELEGRAM_DM_POLICY` | Worker env | Telegram DM policy |
| `DISCORD_DM_POLICY` | Worker env | Discord DM policy |
| `OPENCLAW_ALLOWED_ORIGINS` | Worker env | Control UI WebSocket allowed origins |
Expand Down
7 changes: 1 addition & 6 deletions kiloclaw/DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ user-provided encrypted secrets and channel tokens are silently skipped.

| Variable | Description |
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DEV_MODE` | Set to `true` to skip JWT auth and enable `allowInsecureAuth` in the container. **Local dev only.** |
| `WORKER_ENV` | Defaults to `"production"` in `wrangler.jsonc`. **Set to `"development"` in `.dev.vars` for local dev.** Controls JWT `env` claim matching and Fly app name prefixes (`dev-` vs `acct-`). |

### Optional
Expand Down Expand Up @@ -229,11 +228,7 @@ the WebSocket protocol (NOT as a URL parameter). See

## Local Dev Without Auth

Set `DEV_MODE=true` in `.dev.vars`. This skips JWT validation and sets
`OPENCLAW_DEV_MODE=true` in the container (bypasses device pairing).

In dev mode the catch-all proxy returns 401 because no `userId` is derived
(no JWT = no identity = no per-user sandbox). To test the full flow locally,
To test the full flow locally without browser auth,
use the platform API routes to provision and start an instance:

```bash
Expand Down
8 changes: 0 additions & 8 deletions kiloclaw/src/auth/middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,6 @@ describe('authMiddleware', () => {
app = createTestApp();
});

it('allows DEV_MODE bypass with synthetic userId', async () => {
const res = await app.request('/protected/whoami', {}, { DEV_MODE: 'true' } as never);
expect(res.status).toBe(200);
const body = await jsonBody(res);
expect(body.userId).toBe('dev@kilocode.ai');
expect(body.authToken).toBe('dev-token');
});

it('rejects when no NEXTAUTH_SECRET is configured', async () => {
const res = await app.request('/protected/whoami', {}, {} as never);
expect(res.status).toBe(500);
Expand Down
8 changes: 0 additions & 8 deletions kiloclaw/src/auth/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,8 @@ import { createDatabaseConnection, UserStore } from '../db';
* 3. Verify HS256 with NEXTAUTH_SECRET; check version and env
* 4. Validate apiTokenPepper against DB via Hyperdrive
* 5. Set ctx.userId, ctx.authToken on context
* 6. DEV_MODE bypass: synthetic userId 'dev@kilocode.ai'
*/
export async function authMiddleware(c: Context<AppEnv>, next: Next) {
// DEV_MODE bypass
if (c.env.DEV_MODE === 'true') {
c.set('userId', 'dev@kilocode.ai');
c.set('authToken', 'dev-token');
return next();
}

const secret = c.env.NEXTAUTH_SECRET;
if (!secret) {
console.error('[auth] NEXTAUTH_SECRET not configured');
Expand Down
9 changes: 1 addition & 8 deletions kiloclaw/src/gateway/env.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,6 @@ describe('buildEnvVars', () => {
expect(result.env.AUTO_APPROVE_DEVICES).toBe('true');
});

it('maps DEV_MODE to OPENCLAW_DEV_MODE in env bucket', async () => {
const env = createMockEnv({ DEV_MODE: 'true' });
const result = await buildEnvVars(env, SANDBOX_ID, SECRET);
expect(result.env.OPENCLAW_DEV_MODE).toBe('true');
});

it('passes KILOCODE_API_BASE_URL override in env bucket', async () => {
const env = createMockEnv({
KILOCODE_API_BASE_URL: 'https://example.internal/openrouter/',
Expand All @@ -91,12 +85,11 @@ describe('buildEnvVars', () => {
// ─── User config merging (Layers 2-4) ────────────────────────────────

it('merges user plaintext env vars on top of platform defaults', async () => {
const env = createMockEnv({ DEV_MODE: 'true' });
const env = createMockEnv();
const result = await buildEnvVars(env, SANDBOX_ID, SECRET, {
envVars: { CUSTOM_VAR: 'custom-value', NODE_ENV: 'production' },
});

expect(result.env.OPENCLAW_DEV_MODE).toBe('true');
expect(result.env.CUSTOM_VAR).toBe('custom-value');
expect(result.env.NODE_ENV).toBe('production');
});
Expand Down
1 change: 0 additions & 1 deletion kiloclaw/src/gateway/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ export async function buildEnvVars(
// Layer 1: Worker-level defaults (non-sensitive)
const plainEnv: Record<string, string> = {};

if (env.DEV_MODE) plainEnv.OPENCLAW_DEV_MODE = env.DEV_MODE;
if (env.KILOCODE_API_BASE_URL) plainEnv.KILOCODE_API_BASE_URL = env.KILOCODE_API_BASE_URL;
plainEnv.KILOCODE_FEATURE = 'kilo-claw';

Expand Down
6 changes: 1 addition & 5 deletions kiloclaw/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,8 @@ function isPlatformRoute(c: Context<AppEnv>): boolean {
return path === '/api/platform' || path.startsWith('/api/platform/');
}

/** Reject early if required secrets are missing (skip in dev mode). */
/** Reject early if required secrets are missing. */
async function requireEnvVars(c: Context<AppEnv>, next: Next) {
if (c.env.DEV_MODE === 'true') {
return next();
}

// Platform routes need infra bindings but not AI provider keys
if (isPlatformRoute(c)) {
const missing: string[] = [];
Expand Down
1 change: 0 additions & 1 deletion kiloclaw/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export type KiloClawEnv = {

// KiloCode provider configuration
KILOCODE_API_BASE_URL?: string;
DEV_MODE?: string;
TELEGRAM_BOT_TOKEN?: string;
TELEGRAM_DM_POLICY?: string;
DISCORD_BOT_TOKEN?: string;
Expand Down
5 changes: 0 additions & 5 deletions kiloclaw/start-openclaw.sh
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,6 @@ if (process.env.OPENCLAW_GATEWAY_TOKEN) {
config.gateway.auth.token = process.env.OPENCLAW_GATEWAY_TOKEN;
}

if (process.env.OPENCLAW_DEV_MODE === 'true') {
config.gateway.controlUi = config.gateway.controlUi || {};
config.gateway.controlUi.allowInsecureAuth = true;
}

// Allow Control UI connections from localhost without WebCrypto device identity.
// This is a fallback for insecure HTTP contexts where SubtleCrypto is unavailable.
// It does NOT bypass device pairing -- pairing is handled separately via the
Expand Down
9 changes: 0 additions & 9 deletions kiloclaw/test/docker-image-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,6 @@ cd cloud/kiloclaw
pnpm start
```

**4. DEV_MODE consideration**

- If `DEV_MODE=false` in `.dev.vars`, the worker requires real JWT auth from the
Cloud backend. Provision and access must go through the UI or use the platform
API with the internal API key.
- If `DEV_MODE=true`, the worker sets userId to `dev@kilocode.ai` for all requests,
which won't match instances provisioned for real user IDs. Only use this for
quick smoke tests where auth doesn't matter.

### Verify services

```bash
Expand Down