Files
kuber/tests/server/build-job.test.ts
T
2026-09-03 11:28:30 +07:00

170 lines
5.8 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import { createBuildJob } from "../../server/build-job";
import type { BuildSpec } from "../../shared/build-protocol";
function spec(architecture: "arm64" | "amd64"): BuildSpec {
return {
architecture,
image: "registry.example.com/kuber/demo-web:latest",
context: "apps/web",
dockerfile: "docker/Web.Dockerfile",
target: "production",
buildArgs: ["NODE_ENV=production"],
workspace: `sha256:${"a".repeat(64)}`,
};
}
describe("BuildKit Job generation", () => {
test.each(["arm64", "amd64"] as const)(
"generates a rootless %s job",
(architecture) => {
const job = createBuildJob({
name: `build-${architecture}`,
namespace: "kuber-system",
spec: spec(architecture),
workspaceClaimName: "build-workspaces",
workspaceSubPath: "snapshot",
cacheImage: "registry.example.com/cache/demo-web",
registrySecretName: "registry-auth",
nodeSelector: { "kubernetes.io/arch": "wrong", pool: "builders" },
});
const jobSpec = job.spec as any;
const pod = jobSpec.template.spec;
const container = pod.containers[0];
expect(pod.nodeSelector["kubernetes.io/arch"]).toBe(architecture);
expect(pod.nodeSelector.pool).toBe("builders");
expect(pod.automountServiceAccountToken).toBe(false);
expect(pod.securityContext).toMatchObject({
runAsNonRoot: true,
runAsUser: 1000,
seccompProfile: { type: "Unconfined" },
});
expect(container.securityContext).toEqual({
runAsNonRoot: true,
runAsUser: 1000,
allowPrivilegeEscalation: true,
seccompProfile: { type: "Unconfined" },
appArmorProfile: { type: "Unconfined" },
});
expect(container.env).toContainEqual({
name: "BUILDKITD_FLAGS",
value: "--oci-worker-no-process-sandbox",
});
expect(container.args).toContain(`--opt=platform=linux/${architecture}`);
expect(container.args).toContain(
"--import-cache=type=registry,ref=registry.example.com/cache/demo-web",
);
expect(container.args).toContain(
"--export-cache=type=registry,ref=registry.example.com/cache/demo-web,mode=max",
);
expect(container.args).toContain(
"--output=type=image,name=registry.example.com/kuber/demo-web:latest,push=true",
);
expect(container.volumeMounts).toContainEqual({
name: "workspace",
mountPath: "/workspace",
readOnly: true,
subPath: "snapshot",
});
expect(pod.volumes).toContainEqual({
name: "registry-auth",
secret: {
secretName: "registry-auth",
items: [{ key: ".dockerconfigjson", path: "config.json" }],
},
});
expect(
jobSpec.template.metadata.annotations[
"container.apparmor.security.beta.kubernetes.io/buildkit"
],
).toBe("unconfined");
},
);
test("uses pushImage for output when set", () => {
const job = createBuildJob({
name: "build-push",
namespace: "default",
spec: spec("amd64"),
workspaceClaimName: "workspace",
cacheImage: "registry.example.com/cache/demo-web",
pushImage: "internal.registry:5000/kuber/demo-web:latest",
});
const container = (job.spec as any).template.spec.containers[0];
expect(container.args).toContain(
"--output=type=image,name=internal.registry:5000/kuber/demo-web:latest,push=true",
);
expect(container.args).not.toContainEqual(
expect.stringContaining("--output=type=image,name=registry.example.com"),
);
});
test("adds insecure flags when configured", () => {
const job = createBuildJob({
name: "build-insecure",
namespace: "default",
spec: spec("amd64"),
workspaceClaimName: "workspace",
cacheImage: "internal.registry:5000/cache/demo-web",
pushImage: "internal.registry:5000/kuber/demo-web:latest",
pushRegistryInsecure: true,
cacheRegistryInsecure: true,
});
const container = (job.spec as any).template.spec.containers[0];
expect(container.args).toContain(
"--import-cache=type=registry,ref=internal.registry:5000/cache/demo-web,registry.insecure=true",
);
expect(container.args).toContain(
"--export-cache=type=registry,ref=internal.registry:5000/cache/demo-web,mode=max,registry.insecure=true",
);
expect(container.args).toContain(
"--output=type=image,name=internal.registry:5000/kuber/demo-web:latest,push=true,registry.insecure=true",
);
});
test("no insecure flags when not configured", () => {
const job = createBuildJob({
name: "build-secure",
namespace: "default",
spec: spec("amd64"),
workspaceClaimName: "workspace",
cacheImage: "registry.example.com/cache/demo-web",
});
const container = (job.spec as any).template.spec.containers[0];
for (const arg of container.args) {
expect(arg).not.toContain("registry.insecure");
}
});
test("rejects traversal and invalid Kubernetes names", () => {
expect(() =>
createBuildJob({
name: "Invalid_Name",
namespace: "default",
spec: spec("arm64"),
workspaceClaimName: "workspace",
cacheImage: "cache",
}),
).toThrow("DNS label");
expect(() =>
createBuildJob({
name: "valid",
namespace: "default",
spec: { ...spec("arm64"), context: "../outside" },
workspaceClaimName: "workspace",
cacheImage: "cache",
}),
).toThrow("safe workspace-relative");
expect(() =>
createBuildJob({
name: "valid",
namespace: "default",
spec: spec("arm64"),
workspaceClaimName: "workspace",
workspaceSubPath: "../outside",
cacheImage: "cache",
}),
).toThrow("Workspace subPath");
});
});