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
|
allowed_chat_ids: [] # Add your Telegram chat ID
|
||||||
|
|
||||||
server:
|
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
|
localhost: true
|
||||||
port: 18800
|
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."
|
"summary": "Docs fix: clarified the Tailscale auth note in docs/api/PROTOCOL.md to reference server.tailscale_identity."
|
||||||
},
|
},
|
||||||
"todo-config-default-server-schema-mismatch": {
|
"todo-config-default-server-schema-mismatch": {
|
||||||
"status": "planned",
|
"status": "completed",
|
||||||
"date": "2026-02-16",
|
"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": {
|
"openclaw-gap-roadmap": {
|
||||||
"file": "2026-02-15-openclaw-gap-roadmap.md",
|
"file": "2026-02-15-openclaw-gap-roadmap.md",
|
||||||
"status": "planned",
|
"status": "planned",
|
||||||
@@ -2123,7 +2132,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"overall_progress": {
|
"overall_progress": {
|
||||||
"total_test_count": 1689,
|
"total_test_count": 1692,
|
||||||
"all_tests_passing": true,
|
"all_tests_passing": true,
|
||||||
"p0_completion": "3/3 (100%)",
|
"p0_completion": "3/3 (100%)",
|
||||||
"p1_completion": "4/4 (100%)",
|
"p1_completion": "4/4 (100%)",
|
||||||
|
|||||||
@@ -72,6 +72,28 @@ telegram:
|
|||||||
expect(configValidates?.status).toBe('fail');
|
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 () => {
|
it('reports PASS for writable data directory', async () => {
|
||||||
mkdirSync(testDir, { recursive: true });
|
mkdirSync(testDir, { recursive: true });
|
||||||
const configPath = join(testDir, 'config.yaml');
|
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) => {
|
const checkEnvVars: Check = async (ctx) => {
|
||||||
if (!existsSync(ctx.configPath)) {
|
if (!existsSync(ctx.configPath)) {
|
||||||
return { status: 'skip', label: 'Env vars resolved', detail: '(no config file)' };
|
return { status: 'skip', label: 'Env vars resolved', detail: '(no config file)' };
|
||||||
@@ -492,6 +516,7 @@ const allChecks: Check[] = [
|
|||||||
checkConfigExists,
|
checkConfigExists,
|
||||||
checkOverlayExists,
|
checkOverlayExists,
|
||||||
checkConfigParses,
|
checkConfigParses,
|
||||||
|
checkDeprecatedConfigKeys,
|
||||||
checkConfigValidates,
|
checkConfigValidates,
|
||||||
checkEnvVars,
|
checkEnvVars,
|
||||||
checkDataDir,
|
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