fix: route D601 PK01 postgres through master relay (#967)

Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
Lyon
2026-06-26 12:22:30 +08:00
committed by GitHub
parent 9d6ef37fb0
commit 754789c43c
6 changed files with 209 additions and 7 deletions
+33 -2
View File
@@ -44,12 +44,18 @@ export interface DeprecatedHostComposeEntry {
}
const rebuildableServices = ["backend-core", "frontend", "dev-frontend-proxy", "provider-gateway", "todo-note", "project-manager", "baidu-netdisk", "oa-event-flow", "code-queue-mgr"] as const;
const restartableServices = [...rebuildableServices, "pk01-postgres-relay"] as const;
export type RebuildableService = typeof rebuildableServices[number];
export type RestartableService = typeof restartableServices[number];
export function isRebuildableService(value: string | undefined): value is RebuildableService {
return rebuildableServices.some((service) => service === value);
}
export function isRestartableService(value: string | undefined): value is RestartableService {
return restartableServices.some((service) => service === value);
}
export function unsupportedRebuildService(value: string | undefined): Record<string, unknown> {
const service = value ?? null;
const classifications: Record<string, Record<string, unknown>> = {
@@ -83,6 +89,12 @@ export function unsupportedRebuildService(value: string | undefined): Record<str
replacement: "keep direct bridge repair and artifact plan/dry-run; live prod apply requires supervisor confirmation",
deleteAllowedLater: false,
},
"pk01-postgres-relay": {
classification: "image-reuse",
reason: "pk01-postgres-relay reuses the reviewed provider-gateway Bun image and has no source build step of its own",
replacement: "server restart pk01-postgres-relay",
deleteAllowedLater: false,
},
};
return {
ok: false,
@@ -107,6 +119,7 @@ export function unsupportedRestartService(value: string | undefined): Record<str
error: "unsupported-server-restart",
reason: typeof base.reason === "string" ? base.reason.replace(/server rebuild/g, "server restart") : base.reason,
replacement: typeof base.replacement === "string" ? base.replacement.replace(/server rebuild/g, "server restart") : base.replacement,
allowedServices: [...restartableServices],
policy: "server restart is a no-build maintenance entrypoint and must not silently mutate upstream images, D601 services, database, or unknown objects",
};
}
@@ -307,6 +320,12 @@ export function writeComposeEnv(config: UniDeskConfig, freshLogPrefix: boolean):
UNIDESK_OA_EVENT_FLOW_BASE_URL: runtimeSecret("UNIDESK_OA_EVENT_FLOW_BASE_URL") || "http://oa-event-flow:4255",
UNIDESK_OA_EVENT_FLOW_PORT: runtimeSecret("UNIDESK_OA_EVENT_FLOW_PORT") || "4255",
UNIDESK_OA_EVENT_FLOW_BIND_HOST: runtimeSecretWithDefault("UNIDESK_OA_EVENT_FLOW_BIND_HOST", restrictedHostBind, "127.0.0.1"),
UNIDESK_PK01_POSTGRES_RELAY_LISTEN_HOST: runtimeSecret("UNIDESK_PK01_POSTGRES_RELAY_LISTEN_HOST") || "0.0.0.0",
UNIDESK_PK01_POSTGRES_RELAY_LISTEN_PORT: runtimeSecret("UNIDESK_PK01_POSTGRES_RELAY_LISTEN_PORT") || "15433",
UNIDESK_PK01_POSTGRES_RELAY_TARGET_HOST: runtimeSecret("UNIDESK_PK01_POSTGRES_RELAY_TARGET_HOST") || "82.156.23.220",
UNIDESK_PK01_POSTGRES_RELAY_TARGET_PORT: runtimeSecret("UNIDESK_PK01_POSTGRES_RELAY_TARGET_PORT") || "5432",
UNIDESK_PK01_POSTGRES_RELAY_IDLE_TIMEOUT_MS: runtimeSecret("UNIDESK_PK01_POSTGRES_RELAY_IDLE_TIMEOUT_MS") || "300000",
UNIDESK_PK01_POSTGRES_RELAY_ALLOWED_SOURCE_CIDRS: runtimeSecret("UNIDESK_PK01_POSTGRES_RELAY_ALLOWED_SOURCE_CIDRS") || "127.0.0.1/32,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16",
UNIDESK_CODE_QUEUE_NOTIFY_CLAUDEQQ_ENABLED: runtimeSecret("UNIDESK_CODE_QUEUE_NOTIFY_CLAUDEQQ_ENABLED") || "true",
UNIDESK_CODE_QUEUE_NOTIFY_CLAUDEQQ_BASE_URL: runtimeSecret("UNIDESK_CODE_QUEUE_NOTIFY_CLAUDEQQ_BASE_URL") || "http://claudeqq.unidesk.svc.cluster.local:3290",
UNIDESK_CODE_QUEUE_NOTIFY_CLAUDEQQ_TARGET_TYPE: runtimeSecret("UNIDESK_CODE_QUEUE_NOTIFY_CLAUDEQQ_TARGET_TYPE") || "private",
@@ -442,7 +461,7 @@ export function rebuildService(config: UniDeskConfig, service: RebuildableServic
};
}
export function restartService(config: UniDeskConfig, service: RebuildableService): unknown {
export function restartService(config: UniDeskConfig, service: RestartableService): unknown {
const runtimeEnv = writeComposeEnv(config, false);
const compose = resolveComposeCommand(config, runtimeEnv.envFile);
const listServiceContainersCommand = [
@@ -650,6 +669,8 @@ export async function stackStatus(config: UniDeskConfig): Promise<unknown> {
const databaseBindHost = runtimeValue("UNIDESK_DATABASE_BIND_HOST") || "127.0.0.1";
const oaEventFlowBindHost = runtimeValue("UNIDESK_OA_EVENT_FLOW_BIND_HOST") || "127.0.0.1";
const oaEventFlowPort = Number(runtimeValue("UNIDESK_OA_EVENT_FLOW_PORT") || "4255");
const pk01PostgresRelayListenHost = runtimeValue("UNIDESK_PK01_POSTGRES_RELAY_LISTEN_HOST") || "0.0.0.0";
const pk01PostgresRelayPort = Number(runtimeValue("UNIDESK_PK01_POSTGRES_RELAY_LISTEN_PORT") || "15433");
const coreHealth = dockerExecJson("unidesk-backend-core", "/health");
const overview = dockerExecJson("unidesk-backend-core", "/api/overview");
return {
@@ -676,6 +697,14 @@ export async function stackStatus(config: UniDeskConfig): Promise<unknown> {
listening: isPortListening(oaEventFlowPort),
expected: oaEventFlowBindHost === "127.0.0.1" ? "local-only" : "restricted-to-code-queue-provider",
},
{
name: "pk01-postgres-relay",
bindHost: pk01PostgresRelayListenHost,
hostPort: pk01PostgresRelayPort,
containerPort: pk01PostgresRelayPort,
listening: isPortListening(pk01PostgresRelayPort),
expected: "source-acl-private-or-local-only",
},
],
internalPorts: [
{ name: "backend-core", containerPort: config.network.core.containerPort, hostPort: null },
@@ -684,6 +713,7 @@ export async function stackStatus(config: UniDeskConfig): Promise<unknown> {
{ name: "project-manager", containerPort: 4233, hostPort: null },
{ name: "baidu-netdisk", containerPort: 4244, hostPort: null },
{ name: "oa-event-flow", containerPort: 4255, hostPort: null },
{ name: "pk01-postgres-relay", containerPort: pk01PostgresRelayPort, hostPort: pk01PostgresRelayPort },
],
containers,
health: {
@@ -693,6 +723,7 @@ export async function stackStatus(config: UniDeskConfig): Promise<unknown> {
providerIngress: await probe(`http://127.0.0.1:${config.network.providerIngress.port}/health`),
providerDataPortListening: isPortListening(config.network.providerData.port),
database: dockerExec(config, "unidesk-database", ["pg_isready", "-U", config.database.user, "-d", config.database.name]),
pk01PostgresRelay: dockerExec(config, "unidesk-pk01-postgres-relay", ["bun", "/workspace/scripts/runtime/pk01-postgres-relay.js", "--healthcheck"]),
overview,
},
urls: {
@@ -781,7 +812,7 @@ export function stackLogs(config: UniDeskConfig, tailBytes: number): unknown {
const truncated = sizeBytes > tailBytes;
return { path, name: basename(path), sizeBytes, tailBytes, truncated, tail: tailFile(path, tailBytes) };
});
const containerNames = ["unidesk-database", "unidesk-backend-core", "unidesk-frontend", "unidesk-dev-frontend-proxy", "unidesk-provider-gateway-main", "todo-note-backend", "project-manager-backend", "baidu-netdisk-backend", "oa-event-flow-backend"];
const containerNames = ["unidesk-database", "unidesk-backend-core", "unidesk-frontend", "unidesk-dev-frontend-proxy", "unidesk-provider-gateway-main", "unidesk-pk01-postgres-relay", "todo-note-backend", "project-manager-backend", "baidu-netdisk-backend", "oa-event-flow-backend"];
const docker = containerNames.map((name) => {
const result = runCommand(["docker", "logs", "--tail", "40", name], repoRoot);
return {
+2 -2
View File
@@ -20,7 +20,7 @@ export function rootHelp(): unknown {
{ command: "server cleanup plan [--min-age-hours N] [--limit N]", description: "Dry-run Docker image cleanup plan only: list active/protected images, stale candidates older than the default 24h threshold, risk, estimated reclaim, and manual review commands without deleting anything." },
{ command: "gc plan|run|db-trace|policy|remote [--confirm] [--logs-keep-days N] [--include-browser-cache]", description: "One-time main-server or remote provider disk relief and low-risk anti-bloat policy for logs, journald, allowlisted /tmp artifacts, scoped core dumps and explicit trace telemetry retention; plan is read-only and run requires --confirm." },
{ command: "server rebuild <backend-core|frontend|dev-frontend-proxy|provider-gateway|todo-note|code-queue-mgr|project-manager|baidu-netdisk|oa-event-flow>", description: "Maintenance-only local Compose rebuild for reviewed main-server services; frontend standard release must use CI artifact plus deploy apply dev/prod artifact consumers." },
{ command: "server restart <backend-core|frontend|dev-frontend-proxy|provider-gateway|todo-note|code-queue-mgr|project-manager|baidu-netdisk|oa-event-flow>", description: "No-build single-service Compose restart for reviewed main-server maintenance recovery; returns an async job and validates the recreated container." },
{ command: "server restart <backend-core|frontend|dev-frontend-proxy|provider-gateway|pk01-postgres-relay|todo-note|code-queue-mgr|project-manager|baidu-netdisk|oa-event-flow>", description: "No-build single-service Compose restart for reviewed main-server maintenance recovery; returns an async job and validates the recreated container." },
{ command: "provider attach <providerId> [--master-server URL] [--up] [--force] | provider triage <providerId> [--observed-error text] [--observed-scope scope] [--microservice id ...] [--full|--raw]", description: "Generate the minimal external provider-gateway env/compose bundle or run the low-noise read-only provider health triage contract." },
{ command: "trans <route> [operation args...] (alias of ssh <route> ...)", description: "Open a Host SSH / WSL SSH maintenance session; provider WebSocket carries control and host.ssh.tcp-pool carries stdin/stdout/stderr data." },
{ command: "trans gh:/owner/repo[/pr|/issue][/number[/1]] ls|cat|rg|apply-patch", description: "Treat GitHub PRs/issues as virtual text directories; `issue ls --search/--state` covers filtered reads, `cat|rg` reads first-floor body text, and `apply-patch` updates `body.md` through UniDesk gh plus apply-patch v2." },
@@ -118,7 +118,7 @@ export function serverHelp(action: string | undefined = undefined): unknown {
logs: "bun scripts/cli.ts server logs [--tail-bytes N]",
cleanup: "bun scripts/cli.ts server cleanup plan [--min-age-hours N] [--limit N]",
rebuild: "bun scripts/cli.ts server rebuild <backend-core|frontend|dev-frontend-proxy|provider-gateway|todo-note|code-queue-mgr|project-manager|baidu-netdisk|oa-event-flow>",
restart: "bun scripts/cli.ts server restart <backend-core|frontend|dev-frontend-proxy|provider-gateway|todo-note|code-queue-mgr|project-manager|baidu-netdisk|oa-event-flow>",
restart: "bun scripts/cli.ts server restart <backend-core|frontend|dev-frontend-proxy|provider-gateway|pk01-postgres-relay|todo-note|code-queue-mgr|project-manager|baidu-netdisk|oa-event-flow>",
},
cleanupPlan: {
dryRunOnly: true,