fix(docker): harden integrated service exposure

Squash merge PR #1291 into dev.
This commit is contained in:
Kai (Tam Nhu) Tran authored and GitHub committed 2026-05-19 07:45:20 -04:00
1 parent 79172c86eb
commit 857dac8751
8 files changed
+142 -15

No files matched your search

@@ -1,4 +1,4 @@
import { existsSync } from 'fs';
import { existsSync, readFileSync } from 'fs';
import { describe, expect, it } from 'bun:test';
import { getDockerAssetPaths } from '../../../src/docker/docker-assets';
@@ -18,4 +18,17 @@ describe('docker bundled assets', () => {
expect(existsSync(assets.supervisordConfig)).toBe(true);
expect(existsSync(assets.entrypoint)).toBe(true);
});
it('binds integrated service ports to loopback by default', () => {
const compose = readFileSync(assets.composeFile, 'utf8');
expect(compose).toContain(
'"${CCS_DOCKER_BIND_HOST:-127.0.0.1}:${CCS_DASHBOARD_PORT:-3000}:3000"'
);
expect(compose).toContain(
'"${CCS_DOCKER_BIND_HOST:-127.0.0.1}:${CCS_CLIPROXY_PORT:-8317}:8317"'
);
expect(compose).not.toContain('"${CCS_DASHBOARD_PORT:-3000}:3000"');
expect(compose).not.toContain('"${CCS_CLIPROXY_PORT:-8317}:8317"');
});
});
@@ -0,0 +1,65 @@
import { mkdtempSync, rmSync } from 'fs';
import { tmpdir } from 'os';
import { join } from 'path';
import { afterEach, describe, expect, it } from 'bun:test';
import { ensureDockerCliproxyAuth } from '../../../src/docker/docker-bootstrap';
import { loadOrCreateUnifiedConfig, mutateConfig } from '../../../src/config/config-loader-facade';
import {
CCS_CONTROL_PANEL_SECRET,
CCS_INTERNAL_API_KEY,
} from '../../../src/cliproxy/config/config-generator';
const originalCcsHome = process.env.CCS_HOME;
const tempDirs: string[] = [];
function useTempCcsHome(): string {
const dir = mkdtempSync(join(tmpdir(), 'ccs-docker-auth-'));
tempDirs.push(dir);
process.env.CCS_HOME = dir;
return dir;
}
afterEach(() => {
if (originalCcsHome === undefined) {
delete process.env.CCS_HOME;
} else {
process.env.CCS_HOME = originalCcsHome;
}
for (const dir of tempDirs.splice(0)) {
rmSync(dir, { recursive: true, force: true });
}
});
describe('docker bootstrap auth', () => {
it('generates per-install CLIProxy secrets when Docker config has only defaults', () => {
useTempCcsHome();
const changed = ensureDockerCliproxyAuth();
const config = loadOrCreateUnifiedConfig();
expect(changed).toBe(true);
expect(config.cliproxy.auth?.api_key).toBeTruthy();
expect(config.cliproxy.auth?.management_secret).toBeTruthy();
expect(config.cliproxy.auth?.api_key).not.toBe(CCS_INTERNAL_API_KEY);
expect(config.cliproxy.auth?.management_secret).not.toBe(CCS_CONTROL_PANEL_SECRET);
expect(config.cliproxy.auth?.api_key).not.toBe(config.cliproxy.auth?.management_secret);
});
it('preserves custom CLIProxy auth values for Docker deployments', () => {
useTempCcsHome();
mutateConfig((config) => {
config.cliproxy.auth = {
api_key: 'custom-api-key',
management_secret: 'custom-management-secret',
};
});
const changed = ensureDockerCliproxyAuth();
const config = loadOrCreateUnifiedConfig();
expect(changed).toBe(false);
expect(config.cliproxy.auth?.api_key).toBe('custom-api-key');
expect(config.cliproxy.auth?.management_secret).toBe('custom-management-secret');
});
});
@@ -53,6 +53,7 @@ describe('docker executor', () => {
expect(calls[0].options?.env?.CCS_NPM_VERSION).toBe('7.59.0');
expect(calls[0].options?.env?.CCS_DASHBOARD_PORT).toBe('4000');
expect(calls[0].options?.env?.CCS_CLIPROXY_PORT).toBe('9317');
expect(calls[0].options?.env?.CCS_DOCKER_BIND_HOST).toBe('127.0.0.1');
expect(calls[0].options?.timeoutMs).toBe(300_000);
});
@@ -89,6 +90,7 @@ describe('docker executor', () => {
expect(calls[2].args[1]).toContain("export CCS_NPM_VERSION='7.59.0'");
expect(calls[2].args[1]).toContain("export CCS_DASHBOARD_PORT='3000'");
expect(calls[2].args[1]).toContain("export CCS_CLIPROXY_PORT='8317'");
expect(calls[2].args[1]).toContain("export CCS_DOCKER_BIND_HOST='127.0.0.1'");
expect(calls[2].args[1]).toContain('docker-compose version >/dev/null 2>&1');
expect(calls[2].options?.timeoutMs).toBe(300_000);
});