config: use D601 k3s namespace for WeChat collector

This commit is contained in:
Codex
2026-06-13 12:06:51 +00:00
parent d7def22a3b
commit 5574150c64
4 changed files with 72 additions and 16 deletions
+52 -8
View File
@@ -67,7 +67,7 @@ interface WechatArchiveConfig {
personalWechatIngress: {
enabled: boolean;
mode: string;
target: { id: string; windowsRoute: string; hostRoute: string; dockerRoute: string };
target: { id: string; windowsRoute: string; hostRoute: string; kubeRoute: string };
pcWechat: {
isolation: string;
requiredVersion: string;
@@ -91,7 +91,10 @@ interface WechatArchiveConfig {
};
collector: {
runtime: string;
containerName: string;
namespace: string;
createNamespace: boolean;
workload: { kind: string; name: string; serviceAccountName: string; replicas: number; containerName: string };
storage: { kind: string; name: string; mountPath: string; create: boolean };
wcfHost: string;
commandPort: number;
messagePort: number;
@@ -151,7 +154,7 @@ export function wechatArchiveHelp(): Record<string, unknown> {
boundary: {
langbot: "Receives WeChat/OpenClaw events and forwards archive events to the YAML-declared n8n webhook.",
n8n: "Stores a YAML-rendered workflow that normalizes WeChat payloads.",
personalWechatIngress: "Optionally declares the D601 Windows PC WeChat + WeChatFerry host and Docker read-only collector boundary.",
personalWechatIngress: "Optionally declares the D601 Windows PC WeChat + WeChatFerry host and D601 k3s read-only collector boundary.",
baiduNetdisk: "Uploads and downloads through the private backend-core microservice proxy; Baidu credentials remain in the baidu-netdisk service.",
database: "LangBot and n8n continue to use the single PK01/Pika01 external PostgreSQL instance with separate databases/roles.",
},
@@ -550,10 +553,11 @@ function policyChecks(config: WechatArchiveConfig): Array<Record<string, unknown
{ name: "baidu-private-proxy", ok: config.baiduNetdisk.proxyMode === "backend-core-microservice-proxy", detail: "Baidu Netdisk access stays behind backend-core microservice proxy." },
{ name: "callback-token-source-ref", ok: Boolean(config.archiveCallback.tokenSourceRef && config.archiveCallback.tokenKey), detail: "n8n archive callback token is read from a YAML-declared local sourceRef and never reverse-engineered from runtime." },
{ name: "personal-wechat-read-only", ok: config.langbot.readOnlyRecord.enabled && config.langbot.readOnlyRecord.discardPipelineUuid === "__discard__", detail: "LangBot inbound webhook must return skip_pipeline=true and bot fallback must discard so personal WeChat receives no automated replies." },
{ name: "personal-wechat-ingress-yaml", ok: config.personalWechatIngress.enabled === true, detail: "D601 PC WeChat + WeChatFerry host and Docker collector boundary is declared in YAML." },
{ name: "personal-wechat-ingress-yaml", ok: config.personalWechatIngress.enabled === true, detail: "D601 PC WeChat + WeChatFerry host and k3s collector boundary is declared in YAML." },
{ name: "wcf-version-pin", ok: config.personalWechatIngress.pcWechat.requiredVersion === config.personalWechatIngress.wcfHost.requiredWechatVersion, detail: "The isolated PC WeChat version and WCF host requirement must match in YAML." },
{ name: "wcf-no-public-exposure", ok: config.personalWechatIngress.wcfHost.firewall.publicExposure === false, detail: "WeChatFerry raw RPC must not be publicly exposed." },
{ name: "collector-read-only", ok: config.personalWechatIngress.collector.readOnly.enabled === true && config.personalWechatIngress.collector.readOnly.sendCapability === false, detail: "Docker collector is a read-only WCF RPC client and must not export send/friend/group/database surfaces." },
{ name: "collector-existing-namespace", ok: config.personalWechatIngress.collector.runtime === "d601-k3s" && config.personalWechatIngress.collector.namespace === "platform-infra" && config.personalWechatIngress.collector.createNamespace === false, detail: "D601 collector reuses the existing platform-infra namespace; namespace creation is disabled." },
{ name: "collector-read-only", ok: config.personalWechatIngress.collector.readOnly.enabled === true && config.personalWechatIngress.collector.readOnly.sendCapability === false, detail: "k3s collector is a read-only WCF RPC client and must not export send/friend/group/database surfaces." },
{ name: "collector-port-alignment", ok: config.personalWechatIngress.collector.commandPort === config.personalWechatIngress.wcfHost.commandPort && config.personalWechatIngress.collector.messagePort === config.personalWechatIngress.wcfHost.messagePort, detail: "Collector WCF ports must match the Windows WCF host ports declared in YAML." },
{ name: "test-account-first", ok: config.personalWechatIngress.poc.accountPolicy === "test-account-first", detail: "Initial PoC must use a test or low-risk WeChat account before any production account promotion." },
{ name: "single-pk01-postgres", ok: true, detail: "LangBot and n8n use dedicated databases inside the single PK01/Pika01 external PostgreSQL instance; this workflow adds no PostgreSQL instance." },
@@ -569,6 +573,8 @@ function parsePersonalWechatIngress(raw: Record<string, unknown>): WechatArchive
const wcfHost = recordField(raw, "wcfHost", `${configLabel}.personalWechatIngress`);
const firewall = recordField(wcfHost, "firewall", `${configLabel}.personalWechatIngress.wcfHost`);
const collector = recordField(raw, "collector", `${configLabel}.personalWechatIngress`);
const workload = recordField(collector, "workload", `${configLabel}.personalWechatIngress.collector`);
const storage = recordField(collector, "storage", `${configLabel}.personalWechatIngress.collector`);
const readOnly = recordField(collector, "readOnly", `${configLabel}.personalWechatIngress.collector`);
const poc = recordField(raw, "poc", `${configLabel}.personalWechatIngress`);
return {
@@ -578,7 +584,7 @@ function parsePersonalWechatIngress(raw: Record<string, unknown>): WechatArchive
id: stringField(target, "id", `${configLabel}.personalWechatIngress.target`),
windowsRoute: stringField(target, "windowsRoute", `${configLabel}.personalWechatIngress.target`),
hostRoute: stringField(target, "hostRoute", `${configLabel}.personalWechatIngress.target`),
dockerRoute: stringField(target, "dockerRoute", `${configLabel}.personalWechatIngress.target`),
kubeRoute: stringField(target, "kubeRoute", `${configLabel}.personalWechatIngress.target`),
},
pcWechat: {
isolation: stringField(pcWechat, "isolation", `${configLabel}.personalWechatIngress.pcWechat`),
@@ -606,7 +612,21 @@ function parsePersonalWechatIngress(raw: Record<string, unknown>): WechatArchive
},
collector: {
runtime: stringField(collector, "runtime", `${configLabel}.personalWechatIngress.collector`),
containerName: stringField(collector, "containerName", `${configLabel}.personalWechatIngress.collector`),
namespace: stringField(collector, "namespace", `${configLabel}.personalWechatIngress.collector`),
createNamespace: booleanField(collector, "createNamespace", `${configLabel}.personalWechatIngress.collector`),
workload: {
kind: stringField(workload, "kind", `${configLabel}.personalWechatIngress.collector.workload`),
name: stringField(workload, "name", `${configLabel}.personalWechatIngress.collector.workload`),
serviceAccountName: stringField(workload, "serviceAccountName", `${configLabel}.personalWechatIngress.collector.workload`),
replicas: numberField(workload, "replicas", `${configLabel}.personalWechatIngress.collector.workload`),
containerName: stringField(workload, "containerName", `${configLabel}.personalWechatIngress.collector.workload`),
},
storage: {
kind: stringField(storage, "kind", `${configLabel}.personalWechatIngress.collector.storage`),
name: stringField(storage, "name", `${configLabel}.personalWechatIngress.collector.storage`),
mountPath: stringField(storage, "mountPath", `${configLabel}.personalWechatIngress.collector.storage`),
create: booleanField(storage, "create", `${configLabel}.personalWechatIngress.collector.storage`),
},
wcfHost: stringField(collector, "wcfHost", `${configLabel}.personalWechatIngress.collector`),
commandPort: numberField(collector, "commandPort", `${configLabel}.personalWechatIngress.collector`),
messagePort: numberField(collector, "messagePort", `${configLabel}.personalWechatIngress.collector`),
@@ -631,6 +651,24 @@ function parsePersonalWechatIngress(raw: Record<string, unknown>): WechatArchive
function validatePersonalWechatIngress(config: WechatArchiveConfig["personalWechatIngress"]): void {
if (!config.enabled) return;
if (config.mode !== "d601-windows-wcf-host-with-k3s-collector") {
throw new Error(`${configLabel}.personalWechatIngress.mode must be d601-windows-wcf-host-with-k3s-collector`);
}
if (config.target.id !== "D601" || config.target.kubeRoute !== "D601:k3s") {
throw new Error(`${configLabel}.personalWechatIngress.target must route the collector through D601:k3s`);
}
if (config.collector.runtime !== "d601-k3s") {
throw new Error(`${configLabel}.personalWechatIngress.collector.runtime must be d601-k3s`);
}
if (config.collector.namespace !== "platform-infra" || config.collector.createNamespace !== false) {
throw new Error(`${configLabel}.personalWechatIngress.collector must reuse platform-infra with createNamespace=false`);
}
if (config.collector.workload.kind !== "Deployment") {
throw new Error(`${configLabel}.personalWechatIngress.collector.workload.kind must be Deployment`);
}
if (config.collector.storage.kind !== "PersistentVolumeClaim") {
throw new Error(`${configLabel}.personalWechatIngress.collector.storage.kind must be PersistentVolumeClaim`);
}
if (config.pcWechat.requiredVersion !== config.wcfHost.requiredWechatVersion) {
throw new Error(`${configLabel}.personalWechatIngress pcWechat.requiredVersion and wcfHost.requiredWechatVersion must match`);
}
@@ -649,6 +687,9 @@ function validatePersonalWechatIngress(config: WechatArchiveConfig["personalWech
if (config.collector.archiveCallbackRef !== "archiveCallback") {
throw new Error(`${configLabel}.personalWechatIngress.collector.archiveCallbackRef must point at archiveCallback`);
}
if (config.collector.wcfHost === "host.docker.internal") {
throw new Error(`${configLabel}.personalWechatIngress.collector.wcfHost must be reachable from D601 k3s, not Docker host.docker.internal`);
}
}
function personalWechatIngressSummary(config: WechatArchiveConfig["personalWechatIngress"]): Record<string, unknown> {
@@ -679,7 +720,10 @@ function personalWechatIngressSummary(config: WechatArchiveConfig["personalWecha
},
collector: {
runtime: config.collector.runtime,
containerName: config.collector.containerName,
namespace: config.collector.namespace,
createNamespace: config.collector.createNamespace,
workload: config.collector.workload,
storage: config.collector.storage,
wcfHost: config.collector.wcfHost,
commandPort: config.collector.commandPort,
messagePort: config.collector.messagePort,