fix: runner proxy and transient env secret
This commit is contained in:
@@ -42,6 +42,7 @@ const selfTest: SelfTestCase = async (context) => {
|
||||
assertRunnerJobUsesWritableCodexHome(rendered.manifest as JsonRecord, context.codexHome, "codex-0", "/var/run/agentrun/secrets/codex-0");
|
||||
assertRunnerJobUsesToolCredential(rendered, "GH_TOKEN", "agentrun-v01-tool-github-pr", "GH_TOKEN");
|
||||
assertRunnerJobUsesToolCredential(rendered, "UNIDESK_SSH_CLIENT_TOKEN", "agentrun-v01-tool-unidesk-ssh", "UNIDESK_SSH_CLIENT_TOKEN");
|
||||
assertRunnerJobUsesG14EgressProxy(rendered.manifest as JsonRecord);
|
||||
assert.equal(runnerEnvValue(rendered.manifest as JsonRecord, "AGENTRUN_CODEX_SHELL_SANDBOX"), "danger-full-access");
|
||||
assert.equal(runnerEnvValue(rendered.manifest as JsonRecord, "HWLAB_API_KEY"), "REDACTED");
|
||||
assert.deepEqual((((rendered.transientEnv as JsonRecord).names) as string[]), ["HWLAB_API_KEY"]);
|
||||
@@ -123,13 +124,35 @@ const selfTest: SelfTestCase = async (context) => {
|
||||
|
||||
const fakeKubectl = path.join(context.tmp, "fake-kubectl.js");
|
||||
const createdManifest = path.join(context.tmp, "created-runner-job.json");
|
||||
const createdTransientEnvSecret = path.join(context.tmp, "created-transient-env-secret.json");
|
||||
const patchedTransientEnvSecret = path.join(context.tmp, "patched-transient-env-secret.json");
|
||||
await writeFile(fakeKubectl, `#!/usr/bin/env bun
|
||||
const chunks = [];
|
||||
for await (const chunk of Bun.stdin.stream()) chunks.push(chunk);
|
||||
const text = Buffer.concat(chunks.map((chunk) => Buffer.from(chunk))).toString("utf8");
|
||||
await Bun.write(${JSON.stringify(createdManifest)}, text);
|
||||
const manifest = JSON.parse(text);
|
||||
console.log(JSON.stringify({ apiVersion: manifest.apiVersion, kind: manifest.kind, metadata: { uid: "job-uid-selftest", resourceVersion: "1", name: manifest.metadata.name, namespace: manifest.metadata.namespace } }));
|
||||
const args = Bun.argv.slice(2);
|
||||
async function readStdin() {
|
||||
const chunks = [];
|
||||
for await (const chunk of Bun.stdin.stream()) chunks.push(chunk);
|
||||
return Buffer.concat(chunks.map((chunk) => Buffer.from(chunk))).toString("utf8");
|
||||
}
|
||||
if (args[0] === "create") {
|
||||
const text = await readStdin();
|
||||
const manifest = JSON.parse(text);
|
||||
if (manifest.kind === "Secret") await Bun.write(${JSON.stringify(createdTransientEnvSecret)}, text);
|
||||
if (manifest.kind === "Job") await Bun.write(${JSON.stringify(createdManifest)}, text);
|
||||
const uid = manifest.kind === "Job" ? "job-uid-selftest" : "secret-uid-selftest";
|
||||
console.log(JSON.stringify({ apiVersion: manifest.apiVersion, kind: manifest.kind, metadata: { uid, resourceVersion: "1", name: manifest.metadata.name, namespace: manifest.metadata.namespace } }));
|
||||
process.exit(0);
|
||||
}
|
||||
if (args[0] === "patch" && args[1] === "secret") {
|
||||
await Bun.write(${JSON.stringify(patchedTransientEnvSecret)}, JSON.stringify({ args }, null, 2));
|
||||
console.log(JSON.stringify({ apiVersion: "v1", kind: "Secret", metadata: { uid: "secret-uid-selftest", resourceVersion: "2", name: args[2], namespace: args[4] } }));
|
||||
process.exit(0);
|
||||
}
|
||||
if (args[0] === "delete" && args[1] === "secret") {
|
||||
console.log(JSON.stringify({ kind: "Status", status: "Success" }));
|
||||
process.exit(0);
|
||||
}
|
||||
console.error("unsupported fake kubectl args: " + args.join(" "));
|
||||
process.exit(1);
|
||||
`);
|
||||
await chmod(fakeKubectl, 0o755);
|
||||
await mkdir(path.dirname(fakeKubectl), { recursive: true });
|
||||
@@ -167,12 +190,25 @@ console.log(JSON.stringify({ apiVersion: manifest.apiVersion, kind: manifest.kin
|
||||
assert.equal((created as { mutation?: unknown }).mutation, true);
|
||||
assert.equal(((created as JsonRecord).retention as JsonRecord).ttlSecondsAfterFinished, 86_400);
|
||||
assert.deepEqual((((created as JsonRecord).transientEnv as JsonRecord).names) as string[], ["HWLAB_API_KEY", "HWLAB_RUNTIME_API_URL", "HWLAB_RUNTIME_WEB_URL", "HWLAB_RUNTIME_NAMESPACE", "HWLAB_RUNTIME_LANE", "HWLAB_RUNTIME_ENDPOINT_SOURCE", "HWLAB_RUNTIME_ENDPOINT_LOCKED", "HWLAB_CODE_AGENT_ASSEMBLED_RUNTIME", "UNIDESK_MAIN_SERVER_IP"]);
|
||||
const transientEnvSecret = (created as JsonRecord).transientEnvSecret as JsonRecord;
|
||||
assert.match(String(transientEnvSecret.name), /^agentrun-v01-runner-env-[a-f0-9]{20}$/u);
|
||||
assert.equal(transientEnvSecret.namespace, "agentrun-v01");
|
||||
assert.equal(transientEnvSecret.valuesPrinted, false);
|
||||
assert.deepEqual(transientEnvSecret.keys as string[], ["HWLAB_API_KEY", "HWLAB_RUNTIME_API_URL", "HWLAB_RUNTIME_WEB_URL", "HWLAB_RUNTIME_NAMESPACE", "HWLAB_RUNTIME_LANE", "HWLAB_RUNTIME_ENDPOINT_SOURCE", "HWLAB_RUNTIME_ENDPOINT_LOCKED", "HWLAB_CODE_AGENT_ASSEMBLED_RUNTIME", "UNIDESK_MAIN_SERVER_IP"]);
|
||||
assert.equal(((transientEnvSecret.ownerReference as JsonRecord).attached), true);
|
||||
const secretManifest = JSON.parse(await readFile(createdTransientEnvSecret, "utf8")) as JsonRecord;
|
||||
assert.equal(secretManifest.kind, "Secret");
|
||||
assert.equal(((secretManifest.metadata as JsonRecord).name), transientEnvSecret.name);
|
||||
assert.equal(Object.keys((secretManifest.stringData as JsonRecord)).length, 9);
|
||||
const ownerPatch = JSON.parse(await readFile(patchedTransientEnvSecret, "utf8")) as JsonRecord;
|
||||
assert.deepEqual((ownerPatch.args as string[]).slice(0, 3), ["patch", "secret", String(transientEnvSecret.name)]);
|
||||
const manifest = JSON.parse(await readFile(createdManifest, "utf8")) as JsonRecord;
|
||||
assert.equal((manifest.spec as JsonRecord).ttlSecondsAfterFinished, 86_400);
|
||||
assert.equal(runnerEnvValue(manifest, "HWLAB_API_KEY"), "hwl_live_selftest");
|
||||
assert.equal(runnerEnvValue(manifest, "HWLAB_RUNTIME_API_URL"), "http://runtime-api.test");
|
||||
assert.equal(runnerEnvValue(manifest, "HWLAB_CODE_AGENT_ASSEMBLED_RUNTIME"), "1");
|
||||
assert.equal(runnerEnvValue(manifest, "UNIDESK_MAIN_SERVER_IP"), "https://unidesk.example.test");
|
||||
assertRunnerJobUsesG14EgressProxy(manifest);
|
||||
assertRunnerJobUsesTransientEnvSecret(manifest, "HWLAB_API_KEY", String(transientEnvSecret.name));
|
||||
assertRunnerJobUsesTransientEnvSecret(manifest, "HWLAB_RUNTIME_API_URL", String(transientEnvSecret.name));
|
||||
assertRunnerJobUsesTransientEnvSecret(manifest, "HWLAB_CODE_AGENT_ASSEMBLED_RUNTIME", String(transientEnvSecret.name));
|
||||
assertRunnerJobUsesTransientEnvSecret(manifest, "UNIDESK_MAIN_SERVER_IP", String(transientEnvSecret.name));
|
||||
assertRunnerJobUsesToolCredential({ manifest, toolCredentials: (created as JsonRecord).toolCredentials } as JsonRecord, "GH_TOKEN", "agentrun-v01-tool-github-pr", "GH_TOKEN");
|
||||
assertRunnerJobUsesToolCredential({ manifest, toolCredentials: (created as JsonRecord).toolCredentials } as JsonRecord, "UNIDESK_SSH_CLIENT_TOKEN", "agentrun-v01-tool-unidesk-ssh", "UNIDESK_SSH_CLIENT_TOKEN");
|
||||
assertNoSecretLeak(created);
|
||||
@@ -183,7 +219,9 @@ console.log(JSON.stringify({ apiVersion: manifest.apiVersion, kind: manifest.kin
|
||||
}) as JsonRecord;
|
||||
assert.deepEqual(((defaultEndpointCreated.transientEnv as JsonRecord).names) as string[], ["UNIDESK_MAIN_SERVER_IP"]);
|
||||
const defaultEndpointManifest = JSON.parse(await readFile(createdManifest, "utf8")) as JsonRecord;
|
||||
assert.equal(runnerEnvValue(defaultEndpointManifest, "UNIDESK_MAIN_SERVER_IP"), "https://unidesk.default.example.test");
|
||||
const defaultEndpointSecret = defaultEndpointCreated.transientEnvSecret as JsonRecord;
|
||||
assertRunnerJobUsesTransientEnvSecret(defaultEndpointManifest, "UNIDESK_MAIN_SERVER_IP", String(defaultEndpointSecret.name));
|
||||
assertRunnerJobUsesG14EgressProxy(defaultEndpointManifest);
|
||||
assertRunnerJobUsesToolCredential({ manifest: defaultEndpointManifest, toolCredentials: defaultEndpointCreated.toolCredentials } as JsonRecord, "UNIDESK_SSH_CLIENT_TOKEN", "agentrun-v01-tool-unidesk-ssh", "UNIDESK_SSH_CLIENT_TOKEN");
|
||||
assertNoSecretLeak(defaultEndpointCreated);
|
||||
await assert.rejects(
|
||||
@@ -239,7 +277,7 @@ console.log(JSON.stringify({ apiVersion: manifest.apiVersion, kind: manifest.kin
|
||||
assert.equal(envMap.get("AGENTRUN_SESSION_PVC_NAMESPACE"), "agentrun-v01");
|
||||
assert.equal(envMap.get("AGENTRUN_SESSION_PVC_MOUNT_PATH"), "/home/agentrun/.codex-codex/sessions");
|
||||
assert.equal(envMap.get("AGENTRUN_CODEX_ROLLOUT_SUBDIR"), "sessions");
|
||||
return { name: "runner-k8s-job", tests: ["runner-k8s-job-dry-run", "runner-k8s-job-codex-shell-sandbox-env", "runner-k8s-job-deepseek-profile-dry-run", "runner-k8s-job-minimax-m3-profile-dry-run", "runner-k8s-job-dsflash-go-profile-dry-run", "runner-k8s-job-dsflash-go-legacy-secretref-normalized", "runner-k8s-job-create-api", "runner-k8s-job-retention-ttl", "runner-job-transient-env", "runner-job-tool-credential-env", "runner-job-unidesk-ssh-tool-credential-env", "runner-job-unidesk-ssh-endpoint-auto-env", "runner-job-unidesk-ssh-transient-env-denied", "runner-k8s-job-session-pvc-volume-and-env"] };
|
||||
return { name: "runner-k8s-job", tests: ["runner-k8s-job-dry-run", "runner-k8s-job-codex-shell-sandbox-env", "runner-k8s-job-g14-egress-proxy-env", "runner-k8s-job-deepseek-profile-dry-run", "runner-k8s-job-minimax-m3-profile-dry-run", "runner-k8s-job-dsflash-go-profile-dry-run", "runner-k8s-job-dsflash-go-legacy-secretref-normalized", "runner-k8s-job-create-api", "runner-k8s-job-retention-ttl", "runner-job-transient-env", "runner-job-transient-env-secretref", "runner-job-tool-credential-env", "runner-job-unidesk-ssh-tool-credential-env", "runner-job-unidesk-ssh-endpoint-auto-env", "runner-job-unidesk-ssh-transient-env-denied", "runner-k8s-job-session-pvc-volume-and-env"] };
|
||||
} finally {
|
||||
await new Promise<void>((resolve) => server.server.close(() => resolve()));
|
||||
}
|
||||
@@ -247,14 +285,44 @@ console.log(JSON.stringify({ apiVersion: manifest.apiVersion, kind: manifest.kin
|
||||
|
||||
export default selfTest;
|
||||
|
||||
function runnerEnvValue(manifest: JsonRecord, name: string): unknown {
|
||||
function runnerEnvEntry(manifest: JsonRecord, name: string): JsonRecord | undefined {
|
||||
const spec = manifest.spec as JsonRecord;
|
||||
const template = spec.template as JsonRecord;
|
||||
const podSpec = template.spec as JsonRecord;
|
||||
const containers = podSpec.containers as JsonRecord[];
|
||||
const runner = containers[0] as JsonRecord;
|
||||
const env = runner.env as JsonRecord[];
|
||||
return env.find((item) => item.name === name)?.value;
|
||||
return env.find((item) => item.name === name) as JsonRecord | undefined;
|
||||
}
|
||||
|
||||
function runnerEnvValue(manifest: JsonRecord, name: string): unknown {
|
||||
return runnerEnvEntry(manifest, name)?.value;
|
||||
}
|
||||
|
||||
function assertRunnerJobUsesTransientEnvSecret(manifest: JsonRecord, envName: string, secretName: string): void {
|
||||
const entry = runnerEnvEntry(manifest, envName);
|
||||
assert.ok(entry, `${envName} env should be present`);
|
||||
assert.equal(entry.value, undefined);
|
||||
const valueFrom = entry.valueFrom as JsonRecord;
|
||||
const secretKeyRef = valueFrom.secretKeyRef as JsonRecord;
|
||||
assert.equal(secretKeyRef.name, secretName);
|
||||
assert.equal(secretKeyRef.key, envName);
|
||||
}
|
||||
|
||||
function assertRunnerJobUsesG14EgressProxy(manifest: JsonRecord): void {
|
||||
const proxy = "http://g14-provider-egress-proxy.unidesk.svc.cluster.local:18789";
|
||||
assert.equal(runnerEnvValue(manifest, "HTTP_PROXY"), proxy);
|
||||
assert.equal(runnerEnvValue(manifest, "HTTPS_PROXY"), proxy);
|
||||
assert.equal(runnerEnvValue(manifest, "ALL_PROXY"), proxy);
|
||||
assert.equal(runnerEnvValue(manifest, "http_proxy"), proxy);
|
||||
assert.equal(runnerEnvValue(manifest, "https_proxy"), proxy);
|
||||
assert.equal(runnerEnvValue(manifest, "all_proxy"), proxy);
|
||||
const noProxy = String(runnerEnvValue(manifest, "NO_PROXY"));
|
||||
assert.equal(runnerEnvValue(manifest, "no_proxy"), noProxy);
|
||||
assert.ok(noProxy.includes("hyueapi.com"), "NO_PROXY must keep hyueapi.com direct");
|
||||
assert.ok(noProxy.includes(".hyueapi.com"), "NO_PROXY must keep .hyueapi.com direct");
|
||||
assert.ok(noProxy.includes("g14-provider-egress-proxy.unidesk.svc.cluster.local"), "NO_PROXY must include the proxy Service itself");
|
||||
assert.ok(noProxy.includes(".svc"), "NO_PROXY must include Kubernetes Service domains");
|
||||
}
|
||||
|
||||
function assertRunnerJobUsesToolCredential(rendered: JsonRecord, envName: string, secretName: string, secretKey: string): void {
|
||||
|
||||
@@ -11,12 +11,30 @@ const selfTest: SelfTestCase = async (context) => {
|
||||
const fakeKubectl = path.join(context.tmp, "fake-kubectl-queue-q2.js");
|
||||
const createdManifest = path.join(context.tmp, "created-queue-q2-runner-job.json");
|
||||
await writeFile(fakeKubectl, `#!/usr/bin/env bun
|
||||
const chunks = [];
|
||||
for await (const chunk of Bun.stdin.stream()) chunks.push(chunk);
|
||||
const text = Buffer.concat(chunks.map((chunk) => Buffer.from(chunk))).toString("utf8");
|
||||
await Bun.write(${JSON.stringify(createdManifest)}, text);
|
||||
const manifest = JSON.parse(text);
|
||||
console.log(JSON.stringify({ apiVersion: manifest.apiVersion, kind: manifest.kind, metadata: { uid: "job-uid-queue-q2", resourceVersion: "1", name: manifest.metadata.name, namespace: manifest.metadata.namespace } }));
|
||||
const args = Bun.argv.slice(2);
|
||||
async function readStdin() {
|
||||
const chunks = [];
|
||||
for await (const chunk of Bun.stdin.stream()) chunks.push(chunk);
|
||||
return Buffer.concat(chunks.map((chunk) => Buffer.from(chunk))).toString("utf8");
|
||||
}
|
||||
if (args[0] === "create") {
|
||||
const text = await readStdin();
|
||||
const manifest = JSON.parse(text);
|
||||
if (manifest.kind === "Job") await Bun.write(${JSON.stringify(createdManifest)}, text);
|
||||
const uid = manifest.kind === "Job" ? "job-uid-queue-q2" : "secret-uid-queue-q2";
|
||||
console.log(JSON.stringify({ apiVersion: manifest.apiVersion, kind: manifest.kind, metadata: { uid, resourceVersion: "1", name: manifest.metadata.name, namespace: manifest.metadata.namespace } }));
|
||||
process.exit(0);
|
||||
}
|
||||
if (args[0] === "patch" && args[1] === "secret") {
|
||||
console.log(JSON.stringify({ apiVersion: "v1", kind: "Secret", metadata: { uid: "secret-uid-queue-q2", resourceVersion: "2", name: args[2], namespace: args[4] } }));
|
||||
process.exit(0);
|
||||
}
|
||||
if (args[0] === "delete" && args[1] === "secret") {
|
||||
console.log(JSON.stringify({ kind: "Status", status: "Success" }));
|
||||
process.exit(0);
|
||||
}
|
||||
console.error("unsupported fake kubectl args: " + args.join(" "));
|
||||
process.exit(1);
|
||||
`);
|
||||
await chmod(fakeKubectl, 0o755);
|
||||
const store = new MemoryAgentRunStore();
|
||||
@@ -132,8 +150,9 @@ console.log(JSON.stringify({ apiVersion: manifest.apiVersion, kind: manifest.kin
|
||||
}) as QueueTaskRecord;
|
||||
const unideskDispatched = await client.post(`/api/v1/queue/tasks/${unideskCreated.id}/dispatch`, { attemptId: "attempt_queue_q2_unidesk_ssh_selftest" }) as QueueDispatchResult;
|
||||
assert.deepEqual((((unideskDispatched.runnerJob as JsonRecord).transientEnv as JsonRecord).names) as string[], ["UNIDESK_MAIN_SERVER_IP"]);
|
||||
assert.equal((((unideskDispatched.runnerJob as JsonRecord).transientEnvSecret as JsonRecord).valuesPrinted), false);
|
||||
const unideskManifest = JSON.parse(await readFile(createdManifest, "utf8")) as JsonRecord;
|
||||
assert.equal(runnerEnvValue(unideskManifest, "UNIDESK_MAIN_SERVER_IP"), "https://unidesk.default.example.test");
|
||||
assert.equal(runnerEnvValue(unideskManifest, "UNIDESK_MAIN_SERVER_IP"), "secretRef");
|
||||
assert.equal(runnerEnvValue(unideskManifest, "UNIDESK_SSH_CLIENT_TOKEN"), "secretRef");
|
||||
assertNoSecretLeak(unideskDispatched);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user