fix: restore codex-api via pod-local forwarder

This commit is contained in:
Codex
2026-05-26 16:30:31 +08:00
parent c2344b2950
commit f1067bb51f
16 changed files with 846 additions and 69 deletions
+38 -2
View File
@@ -379,13 +379,20 @@ function validateCloudApiCodeAgentSource(ctx, env) {
const contract = DEV_CODE_AGENT_PROVIDER_CONTRACT;
expectEqual(ctx, env.HWLAB_CODE_AGENT_PROVIDER, contract.codeAgentProvider, "$.services.hwlab-cloud-api.env.HWLAB_CODE_AGENT_PROVIDER", "cloud API Code Agent provider");
expectEqual(ctx, env.HWLAB_CODE_AGENT_MODEL, contract.model, "$.services.hwlab-cloud-api.env.HWLAB_CODE_AGENT_MODEL", "cloud API Code Agent model");
expectEqual(ctx, env.HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE, contract.profiles.defaultProfile, "$.services.hwlab-cloud-api.env.HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE", "cloud API default provider profile");
expectEqual(ctx, env[contract.profiles.deepSeekModelEnv], "deepseek-chat", `$.services.hwlab-cloud-api.env.${contract.profiles.deepSeekModelEnv}`, "cloud API DeepSeek profile model");
expectEqual(ctx, env[contract.profiles.deepSeekBaseUrlEnv], contract.profiles.deepSeekBaseUrl, `$.services.hwlab-cloud-api.env.${contract.profiles.deepSeekBaseUrlEnv}`, "cloud API DeepSeek profile base URL");
expectEqual(ctx, env[contract.profiles.codexApiModelEnv], contract.model, `$.services.hwlab-cloud-api.env.${contract.profiles.codexApiModelEnv}`, "cloud API codex-api profile model");
expectEqual(ctx, env[contract.profiles.codexApiBaseUrlEnv], contract.egress.defaultBaseUrl, `$.services.hwlab-cloud-api.env.${contract.profiles.codexApiBaseUrlEnv}`, "cloud API codex-api profile base URL");
expectEqual(ctx, env[contract.forwarder.upstreamEnv], contract.forwarder.upstreamBaseUrl, `$.services.hwlab-cloud-api.env.${contract.forwarder.upstreamEnv}`, "cloud API codex-api upstream base URL");
expectEqual(ctx, env[contract.forwarder.portEnv], String(contract.forwarder.port), `$.services.hwlab-cloud-api.env.${contract.forwarder.portEnv}`, "cloud API codex-api forwarder port");
expectEqual(ctx, env.HWLAB_CODE_AGENT_TIMEOUT_MS, codeAgentBackendTimeoutMs, "$.services.hwlab-cloud-api.env.HWLAB_CODE_AGENT_TIMEOUT_MS", "cloud API Code Agent hard timeout budget");
expectEqual(
ctx,
env.HWLAB_CODE_AGENT_OPENAI_BASE_URL,
contract.egress.defaultBaseUrl,
"$.services.hwlab-cloud-api.env.HWLAB_CODE_AGENT_OPENAI_BASE_URL",
"cloud API Code Agent DEV egress/proxy base URL"
"cloud API Code Agent pod-local Codex API forwarder base URL"
);
expectEqual(
ctx,
@@ -572,16 +579,24 @@ function validateCloudApiCodeAgentArtifacts(ctx, workloads) {
const secretRef = contract.secretRefs[0];
const container = mapByServiceId(listItems(workloads)).get("hwlab-cloud-api")?.spec?.template?.spec?.containers?.[0];
const env = new Map((container?.env ?? []).map((entry) => [entry.name, entry]));
const podContainers = mapByServiceId(listItems(workloads)).get("hwlab-cloud-api")?.spec?.template?.spec?.containers ?? [];
const volumes = mapByServiceId(listItems(workloads)).get("hwlab-cloud-api")?.spec?.template?.spec?.volumes ?? [];
expectEqual(ctx, env.get("HWLAB_CODE_AGENT_PROVIDER")?.value, contract.codeAgentProvider, "deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.HWLAB_CODE_AGENT_PROVIDER", "cloud API workload Code Agent provider");
expectEqual(ctx, env.get("HWLAB_CODE_AGENT_MODEL")?.value, contract.model, "deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.HWLAB_CODE_AGENT_MODEL", "cloud API workload Code Agent model");
expectEqual(ctx, env.get("HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE")?.value, contract.profiles.defaultProfile, "deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE", "cloud API workload default provider profile");
expectEqual(ctx, env.get(contract.profiles.deepSeekModelEnv)?.value, "deepseek-chat", `deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.${contract.profiles.deepSeekModelEnv}`, "cloud API workload DeepSeek profile model");
expectEqual(ctx, env.get(contract.profiles.deepSeekBaseUrlEnv)?.value, contract.profiles.deepSeekBaseUrl, `deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.${contract.profiles.deepSeekBaseUrlEnv}`, "cloud API workload DeepSeek profile base URL");
expectEqual(ctx, env.get(contract.profiles.codexApiModelEnv)?.value, contract.model, `deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.${contract.profiles.codexApiModelEnv}`, "cloud API workload codex-api profile model");
expectEqual(ctx, env.get(contract.profiles.codexApiBaseUrlEnv)?.value, contract.egress.defaultBaseUrl, `deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.${contract.profiles.codexApiBaseUrlEnv}`, "cloud API workload codex-api profile base URL");
expectEqual(ctx, env.get(contract.forwarder.upstreamEnv)?.value, contract.forwarder.upstreamBaseUrl, `deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.${contract.forwarder.upstreamEnv}`, "cloud API workload codex-api upstream base URL");
expectEqual(ctx, env.get(contract.forwarder.portEnv)?.value, String(contract.forwarder.port), `deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.${contract.forwarder.portEnv}`, "cloud API workload codex-api forwarder port");
expectEqual(ctx, env.get("HWLAB_CODE_AGENT_TIMEOUT_MS")?.value, codeAgentBackendTimeoutMs, "deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.HWLAB_CODE_AGENT_TIMEOUT_MS", "cloud API workload Code Agent hard timeout budget");
expectEqual(
ctx,
env.get("HWLAB_CODE_AGENT_OPENAI_BASE_URL")?.value,
contract.egress.defaultBaseUrl,
"deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.HWLAB_CODE_AGENT_OPENAI_BASE_URL",
"cloud API workload Code Agent DEV egress/proxy base URL"
"cloud API workload Code Agent pod-local Codex API forwarder base URL"
);
expectEqual(
ctx,
@@ -599,6 +614,7 @@ function validateCloudApiCodeAgentArtifacts(ctx, workloads) {
expectEqual(ctx, env.get("CODEX_HOME")?.value, "/codex-home", "deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.CODEX_HOME", "cloud API workload CODEX_HOME contract");
expectNoProxyIncludes(ctx, env.get("NO_PROXY")?.value, contract.noProxyRequired, "deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.NO_PROXY");
expectNoProxyIncludes(ctx, env.get("no_proxy")?.value, contract.noProxyRequired, "deploy/k8s/base/workloads.yaml.hwlab-cloud-api.env.no_proxy");
validateCodexApiForwarderArtifacts(ctx, podContainers, contract);
validateCodexHomeMountArtifacts(ctx, container?.volumeMounts ?? [], volumes, contract);
expect(
ctx,
@@ -622,6 +638,26 @@ function expectNoProxyIncludes(ctx, value, required, path, label = "NO_PROXY con
}
}
function validateCodexApiForwarderArtifacts(ctx, containers, contract) {
const sidecar = (containers ?? []).find((entry) => entry.name === contract.forwarder.containerName);
expect(ctx, Boolean(sidecar), "codex_api_forwarder_missing", "deploy/k8s/base/workloads.yaml.hwlab-cloud-api.containers.hwlab-codex-api-forwarder", "cloud API pod includes codex-api loopback forwarder sidecar");
if (!sidecar) return;
expect(ctx, JSON.stringify(sidecar.command) === JSON.stringify(contract.forwarder.command), "codex_api_forwarder_command_mismatch", "deploy/k8s/base/workloads.yaml.hwlab-cloud-api.containers.hwlab-codex-api-forwarder.command", "codex-api forwarder command");
expect(
ctx,
(sidecar.ports ?? []).some((entry) => entry.name === contract.forwarder.portName && entry.containerPort === contract.forwarder.port),
"codex_api_forwarder_port_missing",
"deploy/k8s/base/workloads.yaml.hwlab-cloud-api.containers.hwlab-codex-api-forwarder.ports",
"codex-api forwarder exposes only a Pod-local container port"
);
const env = new Map((sidecar.env ?? []).map((entry) => [entry.name, entry.value]));
expectEqual(ctx, env.get(contract.forwarder.listenHostEnv), "127.0.0.1", `deploy/k8s/base/workloads.yaml.hwlab-cloud-api.containers.hwlab-codex-api-forwarder.env.${contract.forwarder.listenHostEnv}`, "codex-api forwarder loopback listen host env");
expectEqual(ctx, env.get(contract.forwarder.upstreamEnv), contract.forwarder.upstreamBaseUrl, `deploy/k8s/base/workloads.yaml.hwlab-cloud-api.containers.hwlab-codex-api-forwarder.env.${contract.forwarder.upstreamEnv}`, "codex-api forwarder upstream env");
expectEqual(ctx, env.get(contract.forwarder.portEnv), String(contract.forwarder.port), `deploy/k8s/base/workloads.yaml.hwlab-cloud-api.containers.hwlab-codex-api-forwarder.env.${contract.forwarder.portEnv}`, "codex-api forwarder port env");
expectNoProxyIncludes(ctx, env.get("NO_PROXY"), contract.noProxyRequired, "deploy/k8s/base/workloads.yaml.hwlab-cloud-api.containers.hwlab-codex-api-forwarder.env.NO_PROXY", "codex-api forwarder NO_PROXY contract");
expectNoProxyIncludes(ctx, env.get("no_proxy"), contract.noProxyRequired, "deploy/k8s/base/workloads.yaml.hwlab-cloud-api.containers.hwlab-codex-api-forwarder.env.no_proxy", "codex-api forwarder no_proxy contract");
}
function validateCodexHomeMountArtifacts(ctx, volumeMounts, volumes, contract) {
expect(
ctx,
+23 -17
View File
@@ -201,7 +201,7 @@ function recordObservation(ctx, observation) {
}
function expectedEnvValue(name, service, desiredCommitId) {
if (name === "HWLAB_COMMIT_ID" || name === "HWLAB_SKILLS_COMMIT_ID") return desiredCommitId;
if (name === "HWLAB_COMMIT_ID" || name === "HWLAB_SKILLS_COMMIT_ID") return service?.commitId ?? service?.imageTag ?? desiredCommitId;
if (name === "HWLAB_IMAGE") return service?.image ?? null;
if (name === "HWLAB_IMAGE_TAG") return service?.imageTag ?? null;
if (name === "HWLAB_IMAGE_DIGEST") return service?.digest ?? "not_published";
@@ -306,7 +306,8 @@ function inspectCodeAgentProviderDesiredState(ctx, deployService, workloadRecord
missingSecretRefs: inspection.missingSecretRefs,
missingEgressContract: inspection.missingEgressContract,
missingCodexHomeContract: inspection.missingCodexHomeContract,
missingNoProxyContract: inspection.missingNoProxyContract
missingNoProxyContract: inspection.missingNoProxyContract,
missingForwarderContract: inspection.missingForwarderContract
},
secretMaterialRead: false,
valuesRedacted: true
@@ -326,8 +327,8 @@ function inspectCodeAgentProviderDesiredState(ctx, deployService, workloadRecord
serviceId: "hwlab-cloud-api",
path: `${workloadsPath}.hwlab-cloud-api.env.HWLAB_CODE_AGENT_OPENAI_BASE_URL`,
field: "HWLAB_CODE_AGENT_OPENAI_BASE_URL",
kind: "egress-proxy",
value: inspection.egress.workloadMatchesDevProxy ? "dev-egress-proxy" : "missing_or_mismatched",
kind: "codex-api-forwarder",
value: inspection.egress.workloadMatchesDevProxy ? "pod-local-codex-api-forwarder" : "missing_or_mismatched",
expected: DEV_CODE_AGENT_PROVIDER_CONTRACT.egress.target
});
return inspection;
@@ -443,7 +444,8 @@ function indexWorkloads(workloads) {
env: {
...envListToObject(container?.env),
__volumeMounts: Array.isArray(container?.volumeMounts) ? container.volumeMounts : [],
__volumes: Array.isArray(item?.spec?.template?.spec?.volumes) ? item.spec.template.spec.volumes : []
__volumes: Array.isArray(item?.spec?.template?.spec?.volumes) ? item.spec.template.spec.volumes : [],
__podContainers: Array.isArray(item?.spec?.template?.spec?.containers) ? item.spec.template.spec.containers : []
},
path: `${workloadsPath}.${item?.kind ?? "Workload"}.${item?.metadata?.name ?? serviceId}.containers[${containerIndex}]`
};
@@ -796,10 +798,12 @@ export async function buildDesiredStatePlan(options = {}) {
const deployImage = parseImageRef(deployService?.image);
const catalogImage = parseImageRef(catalogService?.image);
const serviceImageTag = catalogService?.imageTag ?? deployImage.tag;
const serviceImageTag = catalogService?.imageTag ?? deployImage.tag ?? catalogImage.tag ?? desiredImageTag;
const serviceCommitId = catalogService?.commitId ?? serviceImageTag;
const expectedService = {
image: deployService?.image ?? catalogService?.image ?? null,
imageTag: desiredImageTag,
imageTag: serviceImageTag,
commitId: serviceCommitId,
digest: catalogService?.digest ?? "not_published"
};
@@ -816,8 +820,8 @@ export async function buildDesiredStatePlan(options = {}) {
});
if (!deployImage.valid) {
addMismatch(ctx, "invalid_image", `${deployPathBase}.image`, deployImage.reason, "tagged image ref", deployService.image, { serviceId });
} else if (deployImage.tag !== desiredImageTag) {
addMismatch(ctx, "image_tag_mismatch", `${deployPathBase}.image`, `${serviceId} deploy image tag must match deploy commit tag`, desiredImageTag, deployImage.tag, { serviceId });
} else if (deployImage.tag !== serviceImageTag) {
addMismatch(ctx, "image_tag_mismatch", `${deployPathBase}.image`, `${serviceId} deploy image tag must match service artifact tag`, serviceImageTag, deployImage.tag, { serviceId });
}
service.deploy = {
image: deployService.image,
@@ -843,7 +847,7 @@ export async function buildDesiredStatePlan(options = {}) {
field: "commitId",
kind: "commit",
value: catalogService.commitId,
expected: desiredCommitId
expected: serviceCommitId
});
recordObservation(ctx, {
source: "catalog",
@@ -861,16 +865,18 @@ export async function buildDesiredStatePlan(options = {}) {
field: "imageTag",
kind: "tag",
value: catalogService.imageTag,
expected: desiredImageTag
expected: serviceImageTag
});
if (!commitEquivalent(catalogService.commitId, desiredCommitId)) {
addMismatch(ctx, "commit_mismatch", `${catalogPathBase}.commitId`, `${serviceId} catalog service commitId must match deploy commitId`, desiredCommitId, catalogService.commitId, { serviceId });
if (!commitPattern.test(String(catalogService.commitId ?? ""))) {
addMismatch(ctx, "invalid_commit", `${catalogPathBase}.commitId`, `${serviceId} catalog service commitId must be a short or full lowercase Git SHA`, "7-40 lowercase hex", catalogService.commitId, { serviceId });
} else if (!commitEquivalent(catalogService.commitId, serviceImageTag)) {
addMismatch(ctx, "commit_mismatch", `${catalogPathBase}.commitId`, `${serviceId} catalog service commitId must match service artifact tag`, serviceImageTag, catalogService.commitId, { serviceId });
}
if (!catalogImage.valid) {
addMismatch(ctx, "invalid_image", `${catalogPathBase}.image`, catalogImage.reason, "tagged image ref", catalogService.image, { serviceId });
}
if (catalogService.imageTag !== desiredImageTag) {
addMismatch(ctx, "image_tag_mismatch", `${catalogPathBase}.imageTag`, `${serviceId} catalog imageTag must match deploy commit tag`, desiredImageTag, catalogService.imageTag, { serviceId });
if (catalogService.imageTag !== serviceImageTag) {
addMismatch(ctx, "image_tag_mismatch", `${catalogPathBase}.imageTag`, `${serviceId} catalog imageTag must match service artifact tag`, serviceImageTag, catalogService.imageTag, { serviceId });
}
if (catalogImage.valid && catalogImage.tag !== catalogService.imageTag) {
addMismatch(ctx, "image_tag_mismatch", `${catalogPathBase}.image`, `${serviceId} catalog image tag must match catalog imageTag`, catalogService.imageTag, catalogImage.tag, { serviceId });
@@ -901,8 +907,8 @@ export async function buildDesiredStatePlan(options = {}) {
});
if (!workloadImage.valid) {
addMismatch(ctx, "invalid_image", `${workload.path}.image`, workloadImage.reason, "tagged image ref", workload.image, { serviceId });
} else if (workloadImage.tag !== desiredImageTag) {
addMismatch(ctx, "image_tag_mismatch", `${workload.path}.image`, `${serviceId} workload image tag must match deploy commit tag`, desiredImageTag, workloadImage.tag, { serviceId });
} else if (workloadImage.tag !== serviceImageTag) {
addMismatch(ctx, "image_tag_mismatch", `${workload.path}.image`, `${serviceId} workload image tag must match service artifact tag`, serviceImageTag, workloadImage.tag, { serviceId });
}
if (deployService?.image && workload.image !== deployService.image) {
addMismatch(ctx, "image_mismatch", `${workload.path}.image`, `${serviceId} workload image must match deploy image`, deployService.image, workload.image, { serviceId });
+1
View File
@@ -41,6 +41,7 @@ export const DEFAULT_GITOPS_ONLY_PATHS = Object.freeze([
const serviceSpecificPaths = Object.freeze({
"hwlab-cloud-api": [
"cmd/hwlab-cloud-api/",
"cmd/hwlab-codex-api-responses-forwarder/",
"cmd/hwlab-deepseek-responses-bridge/",
"internal/cloud/",
"internal/db/",