feat: declare D601 v03 public exposure

This commit is contained in:
Codex
2026-06-12 23:44:38 +00:00
parent 1ea1fe1c48
commit 71c5d1168c
3 changed files with 592 additions and 4 deletions
+78
View File
@@ -90,6 +90,36 @@ export interface HwlabRuntimeImageRewriteSpec {
readonly target: string;
}
export interface HwlabRuntimePublicExposureFrpcProxySpec {
readonly name: string;
readonly localIP: string;
readonly localPort: number;
readonly remotePort: number;
}
export interface HwlabRuntimePublicExposureSpec {
readonly enabled: boolean;
readonly mode: "pk01-caddy-frp";
readonly publicBaseUrl: string;
readonly hostname: string;
readonly expectedA: string;
readonly serverAddr: string;
readonly serverPort: number;
readonly tokenSourceRef: string;
readonly tokenSourceKey: string;
readonly secretName: string;
readonly secretKey: string;
readonly tokenKey: string;
readonly caddyRoute: string;
readonly caddyConfigPath: string;
readonly caddyServiceName: string;
readonly caddyEmail: string;
readonly caddyTls: "auto" | "internal";
readonly responseHeaderTimeoutSeconds: number;
readonly webProxy: HwlabRuntimePublicExposureFrpcProxySpec;
readonly apiProxy: HwlabRuntimePublicExposureFrpcProxySpec;
}
export interface HwlabRuntimeLaneSpec {
readonly lane: HwlabRuntimeLane;
readonly nodeId: string;
@@ -127,6 +157,7 @@ export interface HwlabRuntimeLaneSpec {
readonly stepEnv: Record<string, string>;
readonly buildkit?: HwlabRuntimeBuildkitSpec;
readonly externalPostgres?: HwlabRuntimeExternalPostgresSpec;
readonly publicExposure: HwlabRuntimePublicExposureSpec | null;
readonly observability: HwlabRuntimeObservabilitySpec;
readonly runtimeImageRewrites: readonly HwlabRuntimeImageRewriteSpec[];
readonly networkProfileId: string;
@@ -166,6 +197,7 @@ interface HwlabLaneConfig {
readonly stepEnv: Record<string, string>;
readonly buildkit?: HwlabRuntimeBuildkitSpec;
readonly externalPostgres?: HwlabRuntimeExternalPostgresSpec;
readonly publicExposure: HwlabRuntimePublicExposureSpec | null;
readonly observability: HwlabRuntimeObservabilitySpec;
readonly runtimeImageRewrites: readonly HwlabRuntimeImageRewriteSpec[];
}
@@ -365,6 +397,7 @@ function laneConfig(id: HwlabRuntimeLane, raw: Record<string, unknown>): HwlabLa
stepEnv: optionalStringRecord(raw.stepEnv, `lanes.${id}.stepEnv`),
buildkit: buildkitConfig(raw.buildkit, `lanes.${id}.buildkit`),
externalPostgres: externalPostgresConfig(raw.externalPostgres, `lanes.${id}.externalPostgres`),
publicExposure: publicExposureConfig(raw.publicExposure, `lanes.${id}.publicExposure`),
observability: observabilityConfig(raw.observability, `lanes.${id}.observability`),
runtimeImageRewrites: runtimeImageRewritesConfig(raw.runtimeImageRewrites, `lanes.${id}.runtimeImageRewrites`),
};
@@ -382,6 +415,7 @@ function laneTargetConfig(id: HwlabRuntimeLane, nodeId: string, baseRaw: Record<
stepEnv: mergeOptionalRecord(baseRaw.stepEnv, targetRaw.stepEnv) ?? {},
buildkit: mergeOptionalRecord(baseRaw.buildkit, targetRaw.buildkit),
externalPostgres: mergeOptionalRecord(baseRaw.externalPostgres, targetRaw.externalPostgres),
publicExposure: mergeOptionalRecord(baseRaw.publicExposure, targetRaw.publicExposure),
observability: mergeOptionalRecord(baseRaw.observability, targetRaw.observability),
};
delete merged.targets;
@@ -427,6 +461,49 @@ function externalPostgresConfig(value: unknown, path: string): HwlabRuntimeExter
};
}
function publicExposureProxyConfig(value: unknown, path: string): HwlabRuntimePublicExposureFrpcProxySpec {
const raw = asRecord(value, path);
return {
name: stringField(raw, "name", path),
localIP: stringField(raw, "localIP", path),
localPort: numberField(raw, "localPort", path),
remotePort: numberField(raw, "remotePort", path),
};
}
function publicExposureConfig(value: unknown, path: string): HwlabRuntimePublicExposureSpec | null {
if (value === undefined) return null;
const raw = asRecord(value, path);
const mode = stringField(raw, "mode", path);
if (mode !== "pk01-caddy-frp") throw new Error(`${path}.mode must be pk01-caddy-frp`);
const frpc = asRecord(raw.frpc, `${path}.frpc`);
const caddy = asRecord(raw.caddy, `${path}.caddy`);
const caddyTls = optionalStringField(caddy, "tls", `${path}.caddy`) ?? "auto";
if (caddyTls !== "auto" && caddyTls !== "internal") throw new Error(`${path}.caddy.tls must be auto or internal`);
return {
enabled: true,
mode,
publicBaseUrl: stringField(raw, "publicBaseUrl", path).replace(/\/+$/u, ""),
hostname: stringField(raw, "hostname", path),
expectedA: stringField(raw, "expectedA", path),
serverAddr: stringField(frpc, "serverAddr", `${path}.frpc`),
serverPort: numberField(frpc, "serverPort", `${path}.frpc`),
tokenSourceRef: stringField(frpc, "tokenSourceRef", `${path}.frpc`),
tokenSourceKey: stringField(frpc, "tokenSourceKey", `${path}.frpc`),
secretName: stringField(frpc, "secretName", `${path}.frpc`),
secretKey: optionalStringField(frpc, "secretKey", `${path}.frpc`) ?? "frpc.toml",
tokenKey: optionalStringField(frpc, "tokenKey", `${path}.frpc`) ?? "token",
caddyRoute: stringField(caddy, "route", `${path}.caddy`),
caddyConfigPath: stringField(caddy, "configPath", `${path}.caddy`),
caddyServiceName: stringField(caddy, "serviceName", `${path}.caddy`),
caddyEmail: stringField(caddy, "email", `${path}.caddy`),
caddyTls,
responseHeaderTimeoutSeconds: numberField(caddy, "responseHeaderTimeoutSeconds", `${path}.caddy`),
webProxy: publicExposureProxyConfig(frpc.webProxy, `${path}.frpc.webProxy`),
apiProxy: publicExposureProxyConfig(frpc.apiProxy, `${path}.frpc.apiProxy`),
};
}
function observabilityConfig(value: unknown, path: string): HwlabRuntimeObservabilitySpec {
const raw = asRecord(value, path);
return {
@@ -527,6 +604,7 @@ function buildRuntimeLaneSpec(config: HwlabLaneConfig): HwlabRuntimeLaneSpec {
stepEnv: config.stepEnv,
...(config.buildkit === undefined ? {} : { buildkit: config.buildkit }),
...(config.externalPostgres === undefined ? {} : { externalPostgres: config.externalPostgres }),
publicExposure: config.publicExposure,
observability: config.observability,
runtimeImageRewrites: config.runtimeImageRewrites,
networkProfileId: networkProfile.id,