732 lines
31 KiB
TypeScript
732 lines
31 KiB
TypeScript
import { ENVIRONMENT_DEV } from "../protocol/index.mjs";
|
|
|
|
export const DEV_CODE_AGENT_PROVIDER_CONTRACT = Object.freeze({
|
|
contractVersion: "v1",
|
|
environment: ENVIRONMENT_DEV,
|
|
codeAgentProvider: "codex-stdio",
|
|
runtimeProvider: "openai-responses",
|
|
backend: "hwlab-cloud-api/codex-app-server-stdio",
|
|
fallbackBackend: "hwlab-cloud-api/openai-responses",
|
|
model: "gpt-5.5",
|
|
requiredEnv: Object.freeze([
|
|
"OPENAI_API_KEY",
|
|
"HWLAB_CODE_AGENT_WORKSPACE",
|
|
"HWLAB_CODE_AGENT_CODEX_WORKSPACE",
|
|
"HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE",
|
|
"HWLAB_CODE_AGENT_OPENAI_BASE_URL",
|
|
"HWLAB_CODE_AGENT_DEEPSEEK_MODEL",
|
|
"HWLAB_CODE_AGENT_DEEPSEEK_BASE_URL",
|
|
"HWLAB_CODE_AGENT_CODEX_API_MODEL",
|
|
"HWLAB_CODE_AGENT_CODEX_API_BASE_URL",
|
|
"HWLAB_CODE_AGENT_CODEX_API_UPSTREAM_BASE_URL",
|
|
"HWLAB_CODE_AGENT_CODEX_API_FORWARDER_PORT"
|
|
]),
|
|
secretRefs: Object.freeze([
|
|
Object.freeze({
|
|
env: "OPENAI_API_KEY",
|
|
secretName: "hwlab-code-agent-provider",
|
|
secretKey: "openai-api-key"
|
|
})
|
|
]),
|
|
egress: Object.freeze({
|
|
env: "HWLAB_CODE_AGENT_OPENAI_BASE_URL",
|
|
target: "pod-local-codex-api-forwarder",
|
|
defaultBaseUrl: "http://127.0.0.1:49280/responses",
|
|
upstreamEnv: "HWLAB_CODE_AGENT_CODEX_API_UPSTREAM_BASE_URL",
|
|
upstreamBaseUrl: "https://hyueapi.com",
|
|
forbiddenDirectBaseUrl: "https://api.openai.com/v1/responses",
|
|
reason: "DEV cloud-api pods must send codex-api traffic to a same-Pod loopback forwarder; the forwarder direct-connects to hyueapi with NO_PROXY."
|
|
}),
|
|
profiles: Object.freeze({
|
|
defaultProfile: "deepseek",
|
|
deepSeekProfile: "deepseek",
|
|
deepSeekModelEnv: "HWLAB_CODE_AGENT_DEEPSEEK_MODEL",
|
|
deepSeekBaseUrlEnv: "HWLAB_CODE_AGENT_DEEPSEEK_BASE_URL",
|
|
deepSeekBaseUrl: "http://hwlab-deepseek-proxy.hwlab-dev.svc.cluster.local:4000/v1/responses",
|
|
codexApiProfile: "codex-api",
|
|
codexApiModelEnv: "HWLAB_CODE_AGENT_CODEX_API_MODEL",
|
|
codexApiBaseUrlEnv: "HWLAB_CODE_AGENT_CODEX_API_BASE_URL"
|
|
}),
|
|
forwarder: Object.freeze({
|
|
containerName: "hwlab-codex-api-forwarder",
|
|
command: Object.freeze(["/usr/local/bin/bun", "run", "/app/cmd/hwlab-codex-api-responses-forwarder/main.ts"]),
|
|
port: 49280,
|
|
portName: "codex-api",
|
|
listenHostEnv: "HWLAB_CODE_AGENT_CODEX_API_FORWARDER_HOST",
|
|
portEnv: "HWLAB_CODE_AGENT_CODEX_API_FORWARDER_PORT",
|
|
upstreamEnv: "HWLAB_CODE_AGENT_CODEX_API_UPSTREAM_BASE_URL",
|
|
upstreamBaseUrl: "https://hyueapi.com"
|
|
}),
|
|
codexHome: Object.freeze({
|
|
path: "/codex-home",
|
|
configMapName: "hwlab-code-agent-codex-config",
|
|
configKey: "config.toml",
|
|
secretName: "hwlab-code-agent-codex-auth",
|
|
authKey: "auth.json",
|
|
mountContract: "writable emptyDir CODEX_HOME with read-only config.toml/auth.json file mounts"
|
|
}),
|
|
workspace: Object.freeze({
|
|
path: "/workspace/hwlab",
|
|
mountPath: "/workspace",
|
|
sourcePath: "/app",
|
|
volumeName: "hwlab-code-agent-workspace",
|
|
claimName: "hwlab-code-agent-workspace",
|
|
accessMode: "ReadWriteOnce",
|
|
storage: "8Gi",
|
|
initContainerName: "hwlab-code-agent-workspace-init",
|
|
initMarker: ".hwlab-workspace-initialized",
|
|
rolloutStrategy: "Recreate",
|
|
mountContract: "persistent RWO PVC mounted at /workspace with copy-once /app bootstrap into /workspace/hwlab"
|
|
}),
|
|
noProxyRequired: Object.freeze([
|
|
"hyueapi.com",
|
|
".hyueapi.com",
|
|
"hyui.com",
|
|
".hyui.com",
|
|
"127.0.0.1",
|
|
"localhost",
|
|
"::1",
|
|
"api.minimaxi.com",
|
|
".minimaxi.com"
|
|
]),
|
|
forbidden: Object.freeze({
|
|
prodAllowed: false,
|
|
secretPlaintextAllowed: false,
|
|
directPublicOpenAiFromDevPod: false
|
|
})
|
|
});
|
|
|
|
export function codeAgentSecretRefPlaceholder() {
|
|
const ref = DEV_CODE_AGENT_PROVIDER_CONTRACT.secretRefs[0];
|
|
return `secretRef:${ref.secretName}/${ref.secretKey}`;
|
|
}
|
|
|
|
export function inspectCodeAgentProviderManifestRefs({ deployEnv = {}, workloadEnv = {} } = {}) {
|
|
const contract = DEV_CODE_AGENT_PROVIDER_CONTRACT;
|
|
const secretRef = contract.secretRefs[0];
|
|
const expectedSecretRef = codeAgentSecretRefPlaceholder();
|
|
const requiredRuntimeEnv = codeAgentRequiredRuntimeEnv();
|
|
const expectedValues = {
|
|
HWLAB_CODE_AGENT_PROVIDER: contract.codeAgentProvider,
|
|
HWLAB_CODE_AGENT_MODEL: contract.model,
|
|
HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE: contract.profiles.defaultProfile,
|
|
[contract.profiles.deepSeekModelEnv]: "deepseek-chat",
|
|
[contract.profiles.deepSeekBaseUrlEnv]: contract.profiles.deepSeekBaseUrl,
|
|
[contract.profiles.codexApiModelEnv]: contract.model,
|
|
[contract.profiles.codexApiBaseUrlEnv]: contract.egress.defaultBaseUrl,
|
|
[contract.forwarder.upstreamEnv]: contract.forwarder.upstreamBaseUrl,
|
|
[contract.forwarder.portEnv]: String(contract.forwarder.port),
|
|
[contract.egress.env]: contract.egress.defaultBaseUrl,
|
|
HWLAB_CODE_AGENT_WORKSPACE: contract.workspace.path,
|
|
HWLAB_CODE_AGENT_CODEX_WORKSPACE: contract.workspace.path,
|
|
CODEX_HOME: contract.codexHome.path,
|
|
NO_PROXY: contract.noProxyRequired.join(","),
|
|
no_proxy: contract.noProxyRequired.join(","),
|
|
[secretRef.env]: expectedSecretRef
|
|
};
|
|
const workloadInspection = inspectCodeAgentProviderWorkloadEnv(workloadEnv);
|
|
const missingDeployEnv = requiredRuntimeEnv.filter((name) => !Object.hasOwn(deployEnv ?? {}, name));
|
|
const deployMismatches = requiredRuntimeEnv
|
|
.filter((name) => Object.hasOwn(deployEnv ?? {}, name) && !Object.is(deployEnv[name], expectedValues[name]))
|
|
.map((name) => ({
|
|
name,
|
|
expected: name === secretRef.env ? expectedSecretRef : expectedValues[name],
|
|
redacted: name === secretRef.env || name === contract.egress.env
|
|
}));
|
|
const missingSecretRefs = [];
|
|
if (deployEnv?.[secretRef.env] !== expectedSecretRef || workloadInspection.secretRef.present !== true) {
|
|
missingSecretRefs.push(`${secretRef.secretName}/${secretRef.secretKey}`);
|
|
}
|
|
const missingEgressContract = [];
|
|
if (deployEnv?.[contract.egress.env] !== contract.egress.defaultBaseUrl || workloadInspection.egress.matchesDevProxy !== true) {
|
|
missingEgressContract.push(`${contract.egress.env} must use ${contract.egress.target}`);
|
|
}
|
|
if (
|
|
isForbiddenDirectOpenAiBaseUrl(deployEnv?.[contract.egress.env]) ||
|
|
workloadInspection.egress.directPublicOpenAi === true
|
|
) {
|
|
missingEgressContract.push(`${contract.egress.env} must not point directly at public api.openai.com`);
|
|
}
|
|
const missingCodexHomeContract = [];
|
|
if (deployEnv?.CODEX_HOME !== contract.codexHome.path || workloadInspection.codexHome.present !== true) {
|
|
missingCodexHomeContract.push(`CODEX_HOME must be ${contract.codexHome.path}`);
|
|
}
|
|
if (workloadInspection.codexHome.writableHomeMountPresent !== true) {
|
|
missingCodexHomeContract.push(`${contract.codexHome.path} must be a writable volumeMount`);
|
|
}
|
|
if (workloadInspection.codexHome.emptyDirPresent !== true) {
|
|
missingCodexHomeContract.push(`${contract.codexHome.path} must be backed by emptyDir`);
|
|
}
|
|
if (workloadInspection.codexHome.configMapPresent !== true) {
|
|
missingCodexHomeContract.push(`${contract.codexHome.configMapName}/${contract.codexHome.configKey}`);
|
|
}
|
|
if (workloadInspection.codexHome.authSecretPresent !== true) {
|
|
missingCodexHomeContract.push(`${contract.codexHome.secretName}/${contract.codexHome.authKey}`);
|
|
}
|
|
const missingWorkspaceContract = [];
|
|
if (
|
|
deployEnv?.HWLAB_CODE_AGENT_WORKSPACE !== contract.workspace.path ||
|
|
deployEnv?.HWLAB_CODE_AGENT_CODEX_WORKSPACE !== contract.workspace.path ||
|
|
workloadInspection.workspace.present !== true
|
|
) {
|
|
missingWorkspaceContract.push(`Code Agent workspace must be ${contract.workspace.path}`);
|
|
}
|
|
if (workloadInspection.workspace.writableMountPresent !== true) {
|
|
missingWorkspaceContract.push(`${contract.workspace.mountPath} must be a writable volumeMount`);
|
|
}
|
|
if (workloadInspection.workspace.persistentVolumeClaimPresent !== true) {
|
|
missingWorkspaceContract.push(`${contract.workspace.volumeName} must use PVC ${contract.workspace.claimName}`);
|
|
}
|
|
if (workloadInspection.workspace.initContainerPresent !== true) {
|
|
missingWorkspaceContract.push(`${contract.workspace.initContainerName} must bootstrap ${contract.workspace.path} from ${contract.workspace.sourcePath}`);
|
|
}
|
|
if (workloadInspection.workspace.recreateStrategy !== true) {
|
|
missingWorkspaceContract.push(`hwlab-cloud-api rollout strategy must be ${contract.workspace.rolloutStrategy}`);
|
|
}
|
|
const missingNoProxyContract = [...new Set([
|
|
...noProxyMissing(deployEnv?.NO_PROXY, contract.noProxyRequired),
|
|
...noProxyMissing(deployEnv?.no_proxy, contract.noProxyRequired),
|
|
...workloadInspection.noProxy.missing
|
|
])];
|
|
const missingForwarderContract = workloadInspection.forwarder.present ? [] : [contract.forwarder.containerName];
|
|
|
|
const ready =
|
|
missingDeployEnv.length === 0 &&
|
|
deployMismatches.length === 0 &&
|
|
workloadInspection.ready === true &&
|
|
missingSecretRefs.length === 0 &&
|
|
missingEgressContract.length === 0 &&
|
|
missingCodexHomeContract.length === 0 &&
|
|
missingWorkspaceContract.length === 0 &&
|
|
missingNoProxyContract.length === 0 &&
|
|
missingForwarderContract.length === 0;
|
|
|
|
return {
|
|
contractVersion: contract.contractVersion,
|
|
environment: contract.environment,
|
|
provider: contract.codeAgentProvider,
|
|
runtimeProvider: contract.runtimeProvider,
|
|
backend: contract.backend,
|
|
model: contract.model,
|
|
status: ready ? "pass" : "blocked",
|
|
ready,
|
|
requiredEnv: requiredRuntimeEnv.map((name) => ({
|
|
name,
|
|
deployPresent: Object.hasOwn(deployEnv ?? {}, name),
|
|
workloadPresent: workloadInspection.requiredEnv.find((entry) => entry.name === name)?.present === true,
|
|
redacted: name === secretRef.env || name === contract.egress.env,
|
|
source: name === secretRef.env ? "k8s-secret-ref" : "runtime-env"
|
|
})),
|
|
secretRef: {
|
|
env: secretRef.env,
|
|
secretName: secretRef.secretName,
|
|
secretKey: secretRef.secretKey,
|
|
deployPlaceholderPresent: deployEnv?.[secretRef.env] === expectedSecretRef,
|
|
workloadSecretRefPresent: workloadInspection.secretRef.present === true,
|
|
present: deployEnv?.[secretRef.env] === expectedSecretRef && workloadInspection.secretRef.present === true,
|
|
redacted: true
|
|
},
|
|
egress: {
|
|
env: contract.egress.env,
|
|
target: contract.egress.target,
|
|
deployPresent: Boolean(deployEnv?.[contract.egress.env]),
|
|
workloadPresent: workloadInspection.egress.present,
|
|
deployMatchesDevProxy: deployEnv?.[contract.egress.env] === contract.egress.defaultBaseUrl,
|
|
workloadMatchesDevProxy: workloadInspection.egress.matchesDevProxy,
|
|
directPublicOpenAi:
|
|
isForbiddenDirectOpenAiBaseUrl(deployEnv?.[contract.egress.env]) ||
|
|
workloadInspection.egress.directPublicOpenAi === true,
|
|
upstream: {
|
|
env: contract.egress.upstreamEnv,
|
|
deployMatchesDirectHyueapi: deployEnv?.[contract.egress.upstreamEnv] === contract.egress.upstreamBaseUrl,
|
|
workloadMatchesDirectHyueapi: workloadInspection.egress.upstreamMatchesDirectHyueapi,
|
|
valueRedacted: true
|
|
},
|
|
valueRedacted: true
|
|
},
|
|
missingDeployEnv,
|
|
missingWorkloadEnv: workloadInspection.missingEnv,
|
|
deployMismatches,
|
|
workloadMismatches: workloadInspection.mismatchedEnv,
|
|
missingSecretRefs,
|
|
missingEgressContract,
|
|
missingCodexHomeContract,
|
|
missingWorkspaceContract,
|
|
missingNoProxyContract,
|
|
missingForwarderContract,
|
|
codexHome: workloadInspection.codexHome,
|
|
workspace: workloadInspection.workspace,
|
|
forwarder: workloadInspection.forwarder,
|
|
noProxy: workloadInspection.noProxy,
|
|
secretMaterialRead: false,
|
|
valuesRedacted: true,
|
|
providerConnected: false,
|
|
fixtureEvidence: false
|
|
};
|
|
}
|
|
|
|
export function inspectCodeAgentProviderWorkloadEnv(workloadEnv = {}) {
|
|
const contract = DEV_CODE_AGENT_PROVIDER_CONTRACT;
|
|
const secretRef = contract.secretRefs[0];
|
|
const requiredRuntimeEnv = codeAgentRequiredRuntimeEnv();
|
|
const expectedValues = {
|
|
HWLAB_CODE_AGENT_PROVIDER: contract.codeAgentProvider,
|
|
HWLAB_CODE_AGENT_MODEL: contract.model,
|
|
HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE: contract.profiles.defaultProfile,
|
|
[contract.profiles.deepSeekModelEnv]: "deepseek-chat",
|
|
[contract.profiles.deepSeekBaseUrlEnv]: contract.profiles.deepSeekBaseUrl,
|
|
[contract.profiles.codexApiModelEnv]: contract.model,
|
|
[contract.profiles.codexApiBaseUrlEnv]: contract.egress.defaultBaseUrl,
|
|
[contract.forwarder.upstreamEnv]: contract.forwarder.upstreamBaseUrl,
|
|
[contract.forwarder.portEnv]: String(contract.forwarder.port),
|
|
[contract.egress.env]: contract.egress.defaultBaseUrl,
|
|
HWLAB_CODE_AGENT_WORKSPACE: contract.workspace.path,
|
|
HWLAB_CODE_AGENT_CODEX_WORKSPACE: contract.workspace.path,
|
|
CODEX_HOME: contract.codexHome.path,
|
|
NO_PROXY: contract.noProxyRequired.join(","),
|
|
no_proxy: contract.noProxyRequired.join(",")
|
|
};
|
|
const requiredEnv = requiredRuntimeEnv.map((name) => {
|
|
const entry = getEnvEntry(workloadEnv, name);
|
|
return {
|
|
name,
|
|
present: Boolean(entry),
|
|
redacted: name === secretRef.env || name === contract.egress.env,
|
|
source: name === secretRef.env ? "k8s-secret-ref" : "runtime-env"
|
|
};
|
|
});
|
|
const missingEnv = requiredEnv.filter((entry) => !entry.present).map((entry) => entry.name);
|
|
const mismatchedEnv = [];
|
|
for (const [name, expected] of Object.entries(expectedValues)) {
|
|
const entry = getEnvEntry(workloadEnv, name);
|
|
if (entry && !Object.is(envEntryValue(entry), expected)) {
|
|
mismatchedEnv.push({
|
|
name,
|
|
expected,
|
|
redacted: name === contract.egress.env
|
|
});
|
|
}
|
|
}
|
|
|
|
const secretKeyRef = envEntrySecretKeyRef(getEnvEntry(workloadEnv, secretRef.env));
|
|
const secretPresent =
|
|
secretKeyRef?.name === secretRef.secretName &&
|
|
secretKeyRef?.key === secretRef.secretKey;
|
|
const baseUrl = envEntryValue(getEnvEntry(workloadEnv, contract.egress.env));
|
|
const upstreamBaseUrl = envEntryValue(getEnvEntry(workloadEnv, contract.egress.upstreamEnv));
|
|
const directPublicOpenAi = isForbiddenDirectOpenAiBaseUrl(baseUrl);
|
|
const matchesDevProxy = baseUrl === contract.egress.defaultBaseUrl;
|
|
const upstreamMatchesDirectHyueapi = upstreamBaseUrl === contract.egress.upstreamBaseUrl;
|
|
const codexHomePresent = envEntryValue(getEnvEntry(workloadEnv, "CODEX_HOME")) === contract.codexHome.path;
|
|
const workspacePathPresent =
|
|
envEntryValue(getEnvEntry(workloadEnv, "HWLAB_CODE_AGENT_WORKSPACE")) === contract.workspace.path &&
|
|
envEntryValue(getEnvEntry(workloadEnv, "HWLAB_CODE_AGENT_CODEX_WORKSPACE")) === contract.workspace.path;
|
|
const noProxyMissingEntries = [...new Set([
|
|
...noProxyMissing(envEntryValue(getEnvEntry(workloadEnv, "NO_PROXY")), contract.noProxyRequired),
|
|
...noProxyMissing(envEntryValue(getEnvEntry(workloadEnv, "no_proxy")), contract.noProxyRequired)
|
|
])];
|
|
const codexHome = inspectCodexHomeWorkloadMounts(workloadEnv);
|
|
const workspace = inspectCodeAgentWorkspaceWorkloadMounts(workloadEnv);
|
|
const forwarder = inspectCodexApiForwarderWorkload(workloadEnv);
|
|
const ready =
|
|
missingEnv.length === 0 &&
|
|
mismatchedEnv.length === 0 &&
|
|
secretPresent &&
|
|
matchesDevProxy &&
|
|
upstreamMatchesDirectHyueapi &&
|
|
!directPublicOpenAi &&
|
|
codexHome.present === true &&
|
|
codexHome.configMapPresent === true &&
|
|
codexHome.authSecretPresent === true &&
|
|
workspacePathPresent &&
|
|
workspace.present === true &&
|
|
noProxyMissingEntries.length === 0 &&
|
|
forwarder.present === true;
|
|
|
|
return {
|
|
contractVersion: contract.contractVersion,
|
|
environment: contract.environment,
|
|
provider: contract.codeAgentProvider,
|
|
runtimeProvider: contract.runtimeProvider,
|
|
backend: contract.backend,
|
|
model: contract.model,
|
|
status: ready ? "pass" : "blocked",
|
|
ready,
|
|
requiredEnv,
|
|
missingEnv,
|
|
mismatchedEnv,
|
|
secretRef: {
|
|
env: secretRef.env,
|
|
secretName: secretRef.secretName,
|
|
secretKey: secretRef.secretKey,
|
|
present: secretPresent,
|
|
redacted: true
|
|
},
|
|
egress: {
|
|
env: contract.egress.env,
|
|
target: contract.egress.target,
|
|
present: Boolean(baseUrl),
|
|
matchesDevProxy,
|
|
upstreamMatchesDirectHyueapi,
|
|
directPublicOpenAi,
|
|
valueRedacted: true
|
|
},
|
|
codexHome: {
|
|
...codexHome,
|
|
present: codexHomePresent && codexHome.present === true
|
|
},
|
|
workspace: {
|
|
...workspace,
|
|
present: workspacePathPresent && workspace.present === true
|
|
},
|
|
forwarder,
|
|
noProxy: {
|
|
required: [...contract.noProxyRequired],
|
|
missing: noProxyMissingEntries,
|
|
present: noProxyMissingEntries.length === 0
|
|
},
|
|
secretMaterialRead: false,
|
|
valuesRedacted: true,
|
|
providerConnected: false
|
|
};
|
|
}
|
|
|
|
export function buildCodeAgentProviderManifestPlaceholder() {
|
|
const contract = DEV_CODE_AGENT_PROVIDER_CONTRACT;
|
|
return {
|
|
contractVersion: contract.contractVersion,
|
|
environment: contract.environment,
|
|
provider: contract.codeAgentProvider,
|
|
runtimeProvider: contract.runtimeProvider,
|
|
backend: contract.backend,
|
|
model: contract.model,
|
|
requiredEnv: [...contract.requiredEnv],
|
|
secretRefs: contract.secretRefs.map((item) => ({ ...item })),
|
|
egress: { ...contract.egress },
|
|
profiles: { ...contract.profiles },
|
|
forwarder: {
|
|
...contract.forwarder,
|
|
command: [...contract.forwarder.command]
|
|
},
|
|
codexHome: { ...contract.codexHome },
|
|
workspace: { ...contract.workspace },
|
|
noProxyRequired: [...contract.noProxyRequired],
|
|
fixtureEvidence: {
|
|
providerConnected: false,
|
|
summary: "This manifest contract records provider env names, Secret/ConfigMap reference names, DEV egress policy, and Codex app-server mount policy only. It is not live provider evidence."
|
|
}
|
|
};
|
|
}
|
|
|
|
export function inspectCodeAgentProviderEnv(env = {}) {
|
|
const contract = DEV_CODE_AGENT_PROVIDER_CONTRACT;
|
|
const missingEnv = contract.requiredEnv.filter((name) => !hasEnvValue(env, name));
|
|
const secretRef = contract.secretRefs[0];
|
|
const baseUrl = firstNonEmpty(env.HWLAB_CODE_AGENT_OPENAI_BASE_URL);
|
|
const codexApiBaseUrl = firstNonEmpty(env[contract.profiles.codexApiBaseUrlEnv]);
|
|
const upstreamBaseUrl = firstNonEmpty(env[contract.forwarder.upstreamEnv]);
|
|
const forwarderPort = firstNonEmpty(env[contract.forwarder.portEnv]);
|
|
const directPublicOpenAi =
|
|
baseUrl === contract.egress.forbiddenDirectBaseUrl ||
|
|
/^https:\/\/api\.openai\.com\/v1\/responses\/?$/u.test(baseUrl);
|
|
const egressMatchesForwarder = baseUrl === contract.egress.defaultBaseUrl;
|
|
const codexApiProfileReady = codexApiBaseUrl === contract.egress.defaultBaseUrl;
|
|
const upstreamReady = upstreamBaseUrl === contract.forwarder.upstreamBaseUrl;
|
|
const forwarderPortReady = forwarderPort === String(contract.forwarder.port);
|
|
const egressReady = Boolean(baseUrl) && !directPublicOpenAi && egressMatchesForwarder && codexApiProfileReady && upstreamReady && forwarderPortReady;
|
|
const noProxyReady = noProxyMissing(env.NO_PROXY, contract.noProxyRequired).length === 0 &&
|
|
noProxyMissing(env.no_proxy, contract.noProxyRequired).length === 0;
|
|
const codexHomeReady = firstNonEmpty(env.CODEX_HOME) === contract.codexHome.path;
|
|
const workspaceReady = firstNonEmpty(env.HWLAB_CODE_AGENT_WORKSPACE) === contract.workspace.path &&
|
|
firstNonEmpty(env.HWLAB_CODE_AGENT_CODEX_WORKSPACE) === contract.workspace.path;
|
|
const ready = missingEnv.length === 0 && egressReady && codexHomeReady && workspaceReady && noProxyReady;
|
|
|
|
return {
|
|
contractVersion: contract.contractVersion,
|
|
environment: contract.environment,
|
|
provider: contract.runtimeProvider,
|
|
model: firstNonEmpty(env.HWLAB_CODE_AGENT_MODEL, contract.model),
|
|
backend: contract.backend,
|
|
status: ready ? "available" : "blocked",
|
|
ready,
|
|
requiredEnv: contract.requiredEnv.map((name) => ({
|
|
name,
|
|
present: hasEnvValue(env, name),
|
|
redacted: name === secretRef.env,
|
|
source: name === secretRef.env ? "k8s-secret-ref" : "runtime-env"
|
|
})),
|
|
missingEnv,
|
|
secretRefs: [
|
|
{
|
|
env: secretRef.env,
|
|
secretName: secretRef.secretName,
|
|
secretKey: secretRef.secretKey,
|
|
present: hasEnvValue(env, secretRef.env),
|
|
envInjected: hasEnvValue(env, secretRef.env),
|
|
secretPresent: "not_observed_by_runtime",
|
|
secretKeyPresent: "not_observed_by_runtime",
|
|
redacted: true
|
|
}
|
|
],
|
|
egress: {
|
|
env: contract.egress.env,
|
|
present: hasEnvValue(env, contract.egress.env),
|
|
target: contract.egress.target,
|
|
baseUrlConfigured: Boolean(baseUrl),
|
|
directPublicOpenAi,
|
|
matchesForwarder: egressMatchesForwarder,
|
|
codexApiProfileReady,
|
|
upstreamReady,
|
|
forwarderPortReady,
|
|
ready: egressReady,
|
|
valueRedacted: true
|
|
},
|
|
forwarder: {
|
|
containerName: contract.forwarder.containerName,
|
|
expectedBaseUrl: contract.egress.defaultBaseUrl,
|
|
upstreamEnv: contract.forwarder.upstreamEnv,
|
|
expectedUpstreamHost: new URL(contract.forwarder.upstreamBaseUrl).hostname,
|
|
managedByKubernetes: true,
|
|
podLocalOnly: true,
|
|
serviceRequired: false
|
|
},
|
|
codexHome: {
|
|
path: contract.codexHome.path,
|
|
present: codexHomeReady,
|
|
configRef: `${contract.codexHome.configMapName}/${contract.codexHome.configKey}`,
|
|
authRef: `${contract.codexHome.secretName}/${contract.codexHome.authKey}`,
|
|
secretMaterialRead: false,
|
|
valuesRedacted: true
|
|
},
|
|
workspace: {
|
|
path: contract.workspace.path,
|
|
mountPath: contract.workspace.mountPath,
|
|
claimName: contract.workspace.claimName,
|
|
initContainerName: contract.workspace.initContainerName,
|
|
rolloutStrategy: contract.workspace.rolloutStrategy,
|
|
present: workspaceReady,
|
|
persistentVolumeClaimPresent: "not_observed_by_runtime"
|
|
},
|
|
noProxy: {
|
|
required: [...contract.noProxyRequired],
|
|
missing: [...new Set([
|
|
...noProxyMissing(env.NO_PROXY, contract.noProxyRequired),
|
|
...noProxyMissing(env.no_proxy, contract.noProxyRequired)
|
|
])],
|
|
present: noProxyReady
|
|
},
|
|
safety: {
|
|
devOnly: true,
|
|
prodAllowed: contract.forbidden.prodAllowed,
|
|
secretsRead: false,
|
|
secretMaterialRead: false,
|
|
valuesRedacted: true,
|
|
directPublicOpenAiFromDevPod: directPublicOpenAi
|
|
},
|
|
blocker: ready ? null : codeAgentProviderBlocker({ missingEnv, directPublicOpenAi, baseUrl, egressMatchesForwarder, codexApiProfileReady, upstreamReady, forwarderPortReady })
|
|
};
|
|
}
|
|
|
|
function codeAgentProviderBlocker({ missingEnv, directPublicOpenAi, baseUrl, egressMatchesForwarder, codexApiProfileReady, upstreamReady, forwarderPortReady }) {
|
|
if (directPublicOpenAi) {
|
|
return "DEV Code Agent OpenAI base URL points at public api.openai.com instead of the pod-local Codex API forwarder";
|
|
}
|
|
if (!baseUrl) {
|
|
return "DEV Code Agent OpenAI base URL is missing; provider calls must use the pod-local Codex API forwarder";
|
|
}
|
|
if (!egressMatchesForwarder || !codexApiProfileReady || !upstreamReady || !forwarderPortReady) {
|
|
return "DEV Code Agent codex-api profile must use the pod-local loopback forwarder with direct hyueapi upstream";
|
|
}
|
|
return `Code Agent provider runtime config is missing ${missingEnv.join(", ")}`;
|
|
}
|
|
|
|
function hasEnvValue(env, name) {
|
|
return typeof env?.[name] === "string" && env[name].trim().length > 0;
|
|
}
|
|
|
|
function firstNonEmpty(...values) {
|
|
for (const value of values) {
|
|
if (typeof value === "string" && value.trim()) return value.trim();
|
|
}
|
|
return "";
|
|
}
|
|
|
|
function codeAgentRequiredRuntimeEnv() {
|
|
return [
|
|
"HWLAB_CODE_AGENT_PROVIDER",
|
|
"HWLAB_CODE_AGENT_MODEL",
|
|
...DEV_CODE_AGENT_PROVIDER_CONTRACT.requiredEnv
|
|
];
|
|
}
|
|
|
|
function getEnvEntry(env, name) {
|
|
if (!env) return undefined;
|
|
if (env instanceof Map) return env.get(name);
|
|
if (Array.isArray(env)) return env.find((entry) => entry?.name === name);
|
|
return env[name];
|
|
}
|
|
|
|
function envEntryValue(entry) {
|
|
if (typeof entry === "string") return entry;
|
|
if (entry && typeof entry === "object" && Object.hasOwn(entry, "value")) return entry.value;
|
|
return undefined;
|
|
}
|
|
|
|
function envEntrySecretKeyRef(entry) {
|
|
if (!entry || typeof entry !== "object") return null;
|
|
return entry.valueFrom?.secretKeyRef ?? null;
|
|
}
|
|
|
|
function inspectCodexHomeWorkloadMounts(workloadEnv = {}) {
|
|
const contract = DEV_CODE_AGENT_PROVIDER_CONTRACT;
|
|
const volumeMounts = Array.isArray(workloadEnv.__volumeMounts) ? workloadEnv.__volumeMounts : [];
|
|
const volumes = Array.isArray(workloadEnv.__volumes) ? workloadEnv.__volumes : [];
|
|
const homeMount = volumeMounts.find((entry) => entry?.name === "hwlab-code-agent-codex-home" && entry?.mountPath === contract.codexHome.path);
|
|
const writableHomeMount = homeMount && homeMount.readOnly !== true;
|
|
const homeVolume = volumes.find((entry) =>
|
|
entry?.name === "hwlab-code-agent-codex-home" &&
|
|
entry?.emptyDir &&
|
|
typeof entry.emptyDir === "object" &&
|
|
!Array.isArray(entry.emptyDir)
|
|
);
|
|
const configMount = volumeMounts.find((entry) =>
|
|
entry?.name === "hwlab-code-agent-codex-config" &&
|
|
entry?.mountPath === `${contract.codexHome.path}/${contract.codexHome.configKey}` &&
|
|
entry?.subPath === contract.codexHome.configKey &&
|
|
entry?.readOnly === true
|
|
);
|
|
const authMount = volumeMounts.find((entry) =>
|
|
entry?.name === "hwlab-code-agent-codex-auth" &&
|
|
entry?.mountPath === `${contract.codexHome.path}/${contract.codexHome.authKey}` &&
|
|
entry?.subPath === contract.codexHome.authKey &&
|
|
entry?.readOnly === true
|
|
);
|
|
const configVolume = volumes.find((entry) =>
|
|
entry?.name === "hwlab-code-agent-codex-config" &&
|
|
entry?.configMap?.name === contract.codexHome.configMapName &&
|
|
(entry.configMap.items ?? []).some((item) => item?.key === contract.codexHome.configKey && item?.path === contract.codexHome.configKey)
|
|
);
|
|
const authVolume = volumes.find((entry) =>
|
|
entry?.name === "hwlab-code-agent-codex-auth" &&
|
|
entry?.secret?.secretName === contract.codexHome.secretName &&
|
|
(entry.secret.items ?? []).some((item) => item?.key === contract.codexHome.authKey && item?.path === contract.codexHome.authKey)
|
|
);
|
|
return {
|
|
path: contract.codexHome.path,
|
|
present: Boolean(writableHomeMount && homeVolume),
|
|
writableHomeMountPresent: Boolean(writableHomeMount),
|
|
emptyDirPresent: Boolean(homeVolume),
|
|
configMapPresent: Boolean(configMount && configVolume),
|
|
authSecretPresent: Boolean(authMount && authVolume),
|
|
configMapName: contract.codexHome.configMapName,
|
|
secretName: contract.codexHome.secretName,
|
|
mountContract: contract.codexHome.mountContract,
|
|
secretMaterialRead: false,
|
|
valuesRedacted: true
|
|
};
|
|
}
|
|
|
|
function inspectCodeAgentWorkspaceWorkloadMounts(workloadEnv = {}) {
|
|
const contract = DEV_CODE_AGENT_PROVIDER_CONTRACT;
|
|
const volumeMounts = Array.isArray(workloadEnv.__volumeMounts) ? workloadEnv.__volumeMounts : [];
|
|
const volumes = Array.isArray(workloadEnv.__volumes) ? workloadEnv.__volumes : [];
|
|
const initContainers = Array.isArray(workloadEnv.__initContainers) ? workloadEnv.__initContainers : [];
|
|
const deploymentStrategy = workloadEnv.__deploymentStrategy;
|
|
const workspaceMount = volumeMounts.find((entry) =>
|
|
entry?.name === contract.workspace.volumeName &&
|
|
entry?.mountPath === contract.workspace.mountPath
|
|
);
|
|
const writableMountPresent = Boolean(workspaceMount && workspaceMount.readOnly !== true);
|
|
const workspaceVolume = volumes.find((entry) =>
|
|
entry?.name === contract.workspace.volumeName &&
|
|
entry?.persistentVolumeClaim?.claimName === contract.workspace.claimName
|
|
);
|
|
const initContainer = initContainers.find((entry) => entry?.name === contract.workspace.initContainerName);
|
|
const initContainerMountPresent = (initContainer?.volumeMounts ?? []).some((entry) =>
|
|
entry?.name === contract.workspace.volumeName &&
|
|
entry?.mountPath === contract.workspace.mountPath
|
|
);
|
|
const initCommand = [...(initContainer?.command ?? []), ...(initContainer?.args ?? [])].join("\n");
|
|
const copyOnceCommandPresent = initCommand.includes(contract.workspace.sourcePath) &&
|
|
initCommand.includes(contract.workspace.path) &&
|
|
initCommand.includes(contract.workspace.initMarker);
|
|
const recreateStrategy = deploymentStrategy?.type === contract.workspace.rolloutStrategy;
|
|
const persistentVolumeClaimPresent = Boolean(workspaceVolume);
|
|
const initContainerPresent = Boolean(initContainer && initContainerMountPresent && copyOnceCommandPresent);
|
|
return {
|
|
path: contract.workspace.path,
|
|
mountPath: contract.workspace.mountPath,
|
|
volumeName: contract.workspace.volumeName,
|
|
claimName: contract.workspace.claimName,
|
|
accessMode: contract.workspace.accessMode,
|
|
storage: contract.workspace.storage,
|
|
initContainerName: contract.workspace.initContainerName,
|
|
initMarker: contract.workspace.initMarker,
|
|
rolloutStrategy: contract.workspace.rolloutStrategy,
|
|
present: Boolean(writableMountPresent && persistentVolumeClaimPresent && initContainerPresent && recreateStrategy),
|
|
writableMountPresent,
|
|
persistentVolumeClaimPresent,
|
|
initContainerPresent,
|
|
initContainerMountPresent,
|
|
copyOnceCommandPresent,
|
|
recreateStrategy,
|
|
mountContract: contract.workspace.mountContract,
|
|
secretMaterialRead: false,
|
|
valuesRedacted: true
|
|
};
|
|
}
|
|
|
|
function noProxyMissing(value, required) {
|
|
const entries = new Set(String(value ?? "")
|
|
.split(/[,;\s]+/u)
|
|
.map((item) => item.trim().toLowerCase())
|
|
.filter(Boolean));
|
|
return required.filter((item) => !entries.has(String(item).toLowerCase()));
|
|
}
|
|
|
|
function inspectCodexApiForwarderWorkload(workloadEnv = {}) {
|
|
const contract = DEV_CODE_AGENT_PROVIDER_CONTRACT;
|
|
const containers = Array.isArray(workloadEnv.__podContainers) ? workloadEnv.__podContainers : [];
|
|
const sidecar = containers.find((entry) => entry?.name === contract.forwarder.containerName);
|
|
const env = new Map((sidecar?.env ?? []).map((entry) => [entry?.name, envEntryValue(entry)]));
|
|
const commandMatches = arrayEqual(sidecar?.command, contract.forwarder.command);
|
|
const portMatches = (sidecar?.ports ?? []).some((entry) =>
|
|
entry?.name === contract.forwarder.portName && entry?.containerPort === contract.forwarder.port
|
|
);
|
|
const upstreamMatches = env.get(contract.forwarder.upstreamEnv) === contract.forwarder.upstreamBaseUrl;
|
|
const listenHostMatches = env.get(contract.forwarder.listenHostEnv) === "127.0.0.1";
|
|
const portEnvMatches = env.get(contract.forwarder.portEnv) === String(contract.forwarder.port);
|
|
const noProxyReady = noProxyMissing(env.get("NO_PROXY"), contract.noProxyRequired).length === 0 &&
|
|
noProxyMissing(env.get("no_proxy"), contract.noProxyRequired).length === 0;
|
|
const present = Boolean(sidecar && commandMatches && portMatches && upstreamMatches && listenHostMatches && portEnvMatches && noProxyReady);
|
|
return {
|
|
containerName: contract.forwarder.containerName,
|
|
present,
|
|
sidecarPresent: Boolean(sidecar),
|
|
commandMatches,
|
|
portMatches,
|
|
upstreamMatches,
|
|
listenHostMatches,
|
|
portEnvMatches,
|
|
noProxyReady,
|
|
podLocalOnly: true,
|
|
managedByKubernetes: true,
|
|
serviceRequired: false,
|
|
valueRedacted: true
|
|
};
|
|
}
|
|
|
|
function arrayEqual(actual, expected) {
|
|
if (!Array.isArray(actual) || !Array.isArray(expected)) return false;
|
|
if (actual.length !== expected.length) return false;
|
|
return actual.every((item, index) => Object.is(item, expected[index]));
|
|
}
|
|
|
|
function isForbiddenDirectOpenAiBaseUrl(value) {
|
|
const baseUrl = firstNonEmpty(value);
|
|
return (
|
|
baseUrl === DEV_CODE_AGENT_PROVIDER_CONTRACT.egress.forbiddenDirectBaseUrl ||
|
|
/^https:\/\/api\.openai\.com\/v1\/responses\/?$/u.test(baseUrl)
|
|
);
|
|
}
|