feat(config): support PORT env override
This commit is contained in:
+13
-1
@@ -43,6 +43,18 @@
|
||||
"test_status": "pnpm test:run + pnpm typecheck passing"
|
||||
},
|
||||
|
||||
"deployment-port-env-override": {
|
||||
"status": "completed",
|
||||
"date": "2026-02-16",
|
||||
"updated": "2026-02-16",
|
||||
"summary": "Added PORT environment variable override support so PaaS deployments can bind the gateway to the platform-assigned port without requiring config changes.",
|
||||
"files_modified": [
|
||||
"src/config/loader.ts",
|
||||
"src/config/loader.test.ts"
|
||||
],
|
||||
"test_status": "pnpm test:run + pnpm typecheck passing"
|
||||
},
|
||||
|
||||
"openclaw-gap-roadmap": {
|
||||
"file": "2026-02-15-openclaw-gap-roadmap.md",
|
||||
"status": "planned",
|
||||
@@ -2132,7 +2144,7 @@
|
||||
},
|
||||
|
||||
"overall_progress": {
|
||||
"total_test_count": 1692,
|
||||
"total_test_count": 1694,
|
||||
"all_tests_passing": true,
|
||||
"p0_completion": "3/3 (100%)",
|
||||
"p1_completion": "4/4 (100%)",
|
||||
|
||||
@@ -102,6 +102,68 @@ telegram:
|
||||
|
||||
rmSync(testDir, { recursive: true });
|
||||
});
|
||||
|
||||
it('overrides server.port from PORT env var when set', () => {
|
||||
mkdirSync(testDir, { recursive: true });
|
||||
const configPath = join(testDir, 'config.yaml');
|
||||
|
||||
const prevPort = process.env.PORT;
|
||||
process.env.PORT = '3777';
|
||||
|
||||
writeFileSync(configPath, `
|
||||
telegram:
|
||||
bot_token: "test-token"
|
||||
allowed_chat_ids: [123]
|
||||
server:
|
||||
port: 18800
|
||||
models:
|
||||
default:
|
||||
provider: anthropic
|
||||
model: claude-sonnet
|
||||
`);
|
||||
|
||||
const config = loadConfig(configPath);
|
||||
expect(config.server.port).toBe(3777);
|
||||
|
||||
if (prevPort !== undefined) {
|
||||
process.env.PORT = prevPort;
|
||||
} else {
|
||||
delete process.env.PORT;
|
||||
}
|
||||
|
||||
rmSync(testDir, { recursive: true });
|
||||
});
|
||||
|
||||
it('ignores invalid PORT env var values', () => {
|
||||
mkdirSync(testDir, { recursive: true });
|
||||
const configPath = join(testDir, 'config.yaml');
|
||||
|
||||
const prevPort = process.env.PORT;
|
||||
process.env.PORT = 'not-a-number';
|
||||
|
||||
writeFileSync(configPath, `
|
||||
telegram:
|
||||
bot_token: "test-token"
|
||||
allowed_chat_ids: [123]
|
||||
server:
|
||||
port: 18800
|
||||
models:
|
||||
default:
|
||||
provider: anthropic
|
||||
model: claude-sonnet
|
||||
`);
|
||||
|
||||
const config = loadConfig(configPath);
|
||||
expect(config.server.port).toBe(18800);
|
||||
|
||||
if (prevPort !== undefined) {
|
||||
process.env.PORT = prevPort;
|
||||
} else {
|
||||
delete process.env.PORT;
|
||||
}
|
||||
|
||||
rmSync(testDir, { recursive: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadConfig with overlay', () => {
|
||||
|
||||
+14
-1
@@ -81,5 +81,18 @@ export function loadConfig(configPath: string, overlayPath?: string): Config {
|
||||
}
|
||||
|
||||
const expandedConfig = expandEnvVarsInObject(rawConfig);
|
||||
return configSchema.parse(expandedConfig);
|
||||
const config = configSchema.parse(expandedConfig);
|
||||
|
||||
// PaaS convention: if PORT is set, bind the gateway to it.
|
||||
// This is intentionally an override (even if config.server.port is set)
|
||||
// to make deployments on Fly/Railway/Render/Heroku-style platforms work.
|
||||
const envPort = process.env.PORT;
|
||||
if (envPort && /^\d+$/.test(envPort)) {
|
||||
const port = Number(envPort);
|
||||
if (Number.isFinite(port) && port > 0 && port <= 65535) {
|
||||
config.server.port = port;
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user