fix(config): align default.yaml with server schema
This commit is contained in:
+4
-1
@@ -10,7 +10,10 @@ telegram:
|
||||
allowed_chat_ids: [] # Add your Telegram chat ID
|
||||
|
||||
server:
|
||||
tailscale_only: true
|
||||
# Tailscale Serve config (optional). Enable `serve: true` to expose the
|
||||
# gateway to your tailnet via `tailscale serve`.
|
||||
tailscale:
|
||||
serve: false
|
||||
localhost: true
|
||||
port: 18800
|
||||
|
||||
|
||||
+12
-3
@@ -30,10 +30,19 @@
|
||||
"summary": "Docs fix: clarified the Tailscale auth note in docs/api/PROTOCOL.md to reference server.tailscale_identity."
|
||||
},
|
||||
"todo-config-default-server-schema-mismatch": {
|
||||
"status": "planned",
|
||||
"status": "completed",
|
||||
"date": "2026-02-16",
|
||||
"summary": "TODO: reconcile config/default.yaml with src/config/schema.ts (config uses server.tailscale_only but schema defines server.tailscale.*). Update docs snippets (if any) and add a test/doctor check to prevent future drift."
|
||||
"updated": "2026-02-16",
|
||||
"summary": "Reconciled config/default.yaml with src/config/schema.ts by replacing deprecated server.tailscale_only with server.tailscale.*. Added a doctor warning for deprecated keys and a regression test to prevent future drift.",
|
||||
"files_modified": [
|
||||
"config/default.yaml",
|
||||
"src/cli/doctor.ts",
|
||||
"src/cli/doctor.test.ts",
|
||||
"src/config/defaultYaml.test.ts"
|
||||
],
|
||||
"test_status": "pnpm test:run + pnpm typecheck passing"
|
||||
},
|
||||
|
||||
"openclaw-gap-roadmap": {
|
||||
"file": "2026-02-15-openclaw-gap-roadmap.md",
|
||||
"status": "planned",
|
||||
@@ -2123,7 +2132,7 @@
|
||||
},
|
||||
|
||||
"overall_progress": {
|
||||
"total_test_count": 1689,
|
||||
"total_test_count": 1692,
|
||||
"all_tests_passing": true,
|
||||
"p0_completion": "3/3 (100%)",
|
||||
"p1_completion": "4/4 (100%)",
|
||||
|
||||
@@ -72,6 +72,28 @@ telegram:
|
||||
expect(configValidates?.status).toBe('fail');
|
||||
});
|
||||
|
||||
it('warns when deprecated server.tailscale_only key is present', async () => {
|
||||
mkdirSync(testDir, { recursive: true });
|
||||
const configPath = join(testDir, 'config.yaml');
|
||||
writeFileSync(configPath, `
|
||||
telegram:
|
||||
bot_token: "test-token"
|
||||
allowed_chat_ids: [123]
|
||||
server:
|
||||
tailscale_only: true
|
||||
models:
|
||||
default:
|
||||
provider: anthropic
|
||||
model: claude-sonnet
|
||||
`);
|
||||
|
||||
const ctx: DoctorContext = { configPath, dataDir: testDir };
|
||||
const results = await runChecks(ctx);
|
||||
|
||||
const deprecated = results.find(r => r.label.includes('deprecated keys'));
|
||||
expect(deprecated?.status).toBe('warn');
|
||||
});
|
||||
|
||||
it('reports PASS for writable data directory', async () => {
|
||||
mkdirSync(testDir, { recursive: true });
|
||||
const configPath = join(testDir, 'config.yaml');
|
||||
|
||||
@@ -71,6 +71,30 @@ const checkConfigValidates: Check = async (ctx) => {
|
||||
}
|
||||
};
|
||||
|
||||
const checkDeprecatedConfigKeys: Check = async (ctx) => {
|
||||
if (!existsSync(ctx.configPath)) {
|
||||
return { status: 'skip', label: 'Config deprecated keys', detail: '(no config file)' };
|
||||
}
|
||||
|
||||
try {
|
||||
const raw = readFileSync(ctx.configPath, 'utf-8');
|
||||
const parsed = parse(raw) as any;
|
||||
const tailscaleOnly = Boolean(parsed?.server && typeof parsed.server === 'object' && 'tailscale_only' in parsed.server);
|
||||
|
||||
if (tailscaleOnly) {
|
||||
return {
|
||||
status: 'warn',
|
||||
label: 'Config deprecated keys',
|
||||
detail: 'server.tailscale_only is deprecated/ignored; use server.tailscale.* + server.localhost instead',
|
||||
};
|
||||
}
|
||||
|
||||
return { status: 'pass', label: 'Config deprecated keys' };
|
||||
} catch {
|
||||
return { status: 'skip', label: 'Config deprecated keys', detail: '(could not read/parse config)' };
|
||||
}
|
||||
};
|
||||
|
||||
const checkEnvVars: Check = async (ctx) => {
|
||||
if (!existsSync(ctx.configPath)) {
|
||||
return { status: 'skip', label: 'Env vars resolved', detail: '(no config file)' };
|
||||
@@ -492,6 +516,7 @@ const allChecks: Check[] = [
|
||||
checkConfigExists,
|
||||
checkOverlayExists,
|
||||
checkConfigParses,
|
||||
checkDeprecatedConfigKeys,
|
||||
checkConfigValidates,
|
||||
checkEnvVars,
|
||||
checkDataDir,
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { readFileSync } from 'fs';
|
||||
import { parse } from 'yaml';
|
||||
|
||||
describe('config/default.yaml', () => {
|
||||
it('does not use deprecated server.tailscale_only key', () => {
|
||||
const raw = readFileSync('config/default.yaml', 'utf-8');
|
||||
const parsed = parse(raw) as any;
|
||||
|
||||
expect(parsed).toBeTruthy();
|
||||
expect(parsed.server).toBeTruthy();
|
||||
expect(parsed.server.tailscale_only).toBeUndefined();
|
||||
});
|
||||
|
||||
it('documents server.tailscale.* shape', () => {
|
||||
const raw = readFileSync('config/default.yaml', 'utf-8');
|
||||
const parsed = parse(raw) as any;
|
||||
|
||||
expect(parsed.server.tailscale).toBeTruthy();
|
||||
expect(typeof parsed.server.tailscale).toBe('object');
|
||||
expect(typeof parsed.server.tailscale.serve).toBe('boolean');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user