83 lines
5.5 KiB
JavaScript
83 lines
5.5 KiB
JavaScript
import { readFileSync, readdirSync } from "node:fs";
|
|
|
|
const directory = new URL("../deploy/ack/", import.meta.url);
|
|
const files = readdirSync(directory).filter((name) => name.endsWith(".yaml")).sort();
|
|
|
|
for (const file of files) {
|
|
const text = readFileSync(new URL(file, directory), "utf8");
|
|
assert(text.includes("apiVersion:"), `${file}: missing apiVersion`);
|
|
assert(text.includes("kind:"), `${file}: missing kind`);
|
|
assert(!text.includes("server-snippet"), `${file}: must not depend on disabled snippet annotations`);
|
|
}
|
|
|
|
const migrationJob = read("migration-job.yaml");
|
|
assert(migrationJob.includes("name: ZHINIAN_DATA_BACKEND\n value: postgres"), "migration Job must select postgres");
|
|
assert(migrationJob.includes("name: DATABASE_APP_ROLE"), "migration Job must provision the Web role");
|
|
assert(migrationJob.includes("secretName: zhinian-rds-ca"), "migration Job must mount the optional RDS CA used by DATABASE_URL");
|
|
assert(!migrationJob.includes("DATABASE_SSL_MODE"), "migration Job must keep database TLS inside DATABASE_URL");
|
|
assert(!migrationJob.includes("DATABASE_CA_CERT_PATH"), "migration Job must keep database TLS inside DATABASE_URL");
|
|
|
|
const web = read("web.yaml");
|
|
assert(/^\s*replicas: 1\s*$/m.test(web), "Web must default to one replica until object storage is shared");
|
|
assert(web.includes("path: /api/health"), "Web must use process-level readiness (it is database-free in production)");
|
|
assert(web.includes("name: zhinian-runtime"), "Web must consume the Web runtime ConfigMap");
|
|
assert(!web.includes("ZHINIAN_DATA_BACKEND"), "Web must not select a database backend in production");
|
|
assert(!web.includes("DATABASE_URL"), "Web must not receive DATABASE_URL in production");
|
|
assert(!web.includes("zhinian-web-db"), "Web must not hold RDS credentials in production");
|
|
assert(!web.includes("rds-ca"), "Web must not mount the RDS CA in production");
|
|
|
|
const goApi = read("go-api.yaml");
|
|
assert(/^\s*replicas: 1\s*$/m.test(goApi), "Go API must default to one replica until object storage is shared");
|
|
assert(goApi.includes("path: /api/ready"), "Go API must use database-aware readiness");
|
|
assert(goApi.includes("runAsNonRoot: true"), "Go API must run as a non-root user");
|
|
assert(goApi.includes("name: zhinian-go-runtime"), "Go API must consume the Go runtime ConfigMap");
|
|
assert(goApi.includes("name: zhinian-go-bootstrap"), "Go API must receive bootstrap administrator credentials");
|
|
assert(goApi.includes("secretName: zhinian-rds-ca"), "Go API must mount the optional RDS CA used by DATABASE_URL");
|
|
assert(!goApi.includes("DATABASE_SSL_MODE"), "Go API must keep database TLS inside DATABASE_URL");
|
|
assert(!goApi.includes("DATABASE_CA_CERT_PATH"), "Go API must keep database TLS inside DATABASE_URL");
|
|
|
|
const configMap = read("configmap.yaml");
|
|
const webRuntime = configMap.split("\n---\n", 1)[0];
|
|
const expectedInternalBaseUrl = "http://zhinian-go-api:8080";
|
|
const internalBaseUrl = webRuntime.match(/^\s*ZHINIAN_GO_INTERNAL_BASE_URL:\s*(\S+)\s*$/m)?.[1];
|
|
assert(internalBaseUrl, "Web runtime ConfigMap must define ZHINIAN_GO_INTERNAL_BASE_URL");
|
|
assert(internalBaseUrl === expectedInternalBaseUrl, "Web runtime ConfigMap must use the cluster-internal Go API URL");
|
|
assert(!webRuntime.includes("ZHINIAN_DATA_BACKEND"), "Web runtime ConfigMap must not select a database backend");
|
|
assert(!webRuntime.includes("DATABASE_URL"), "Web runtime ConfigMap must not carry DATABASE_URL");
|
|
assert(!webRuntime.includes("rds-ca"), "Web runtime ConfigMap must not carry the RDS CA");
|
|
assert(configMap.includes("ZHINIAN_GO_EMBEDDED_WORKER: \"true\""), "Go runtime ConfigMap must embed the WorkerLoop");
|
|
assert(configMap.includes("GO_BACKEND_HOST: 0.0.0.0"), "Go runtime ConfigMap must listen on the Pod interface");
|
|
assert(!configMap.includes("DATABASE_SSL_MODE"), "ConfigMaps must not carry database TLS settings");
|
|
assert(!configMap.includes("DATABASE_CA_CERT_PATH"), "ConfigMaps must not carry database CA paths");
|
|
|
|
const ingress = read("ingress.yaml");
|
|
assert(ingress.includes("path: /api/internal/worker"), "Ingress must intercept the internal worker prefix");
|
|
assert(ingress.includes("name: zhinian-public-deny"), "Ingress must route the internal prefix away from the workloads");
|
|
assert(ingress.includes("name: zhinian-go-api"), "Ingress must route backend paths to the Go API Service");
|
|
assert(ingress.includes("path: /uploads"), "Ingress must route /uploads to the Go API");
|
|
assert(ingress.includes("path: /generated-results"), "Ingress must route /generated-results to the Go API");
|
|
assert(ingress.includes("name: zhinian-web"), "Ingress must route pages/static paths to Web");
|
|
|
|
const service = read("service.yaml");
|
|
assert(service.includes("name: zhinian-public-deny"), "selectorless deny Service is required");
|
|
|
|
const goService = goApi.match(
|
|
/kind: Service\s+metadata:\s+name:\s+(\S+)[\s\S]*?ports:\s+- name: http\s+port:\s+(\d+)\s+targetPort:\s+(\d+)/,
|
|
);
|
|
assert(goService, "Go API Service must declare an HTTP name, port, and targetPort");
|
|
const [, serviceName, servicePort, targetPort] = goService;
|
|
const parsedInternalBaseUrl = new URL(internalBaseUrl);
|
|
assert(parsedInternalBaseUrl.hostname === serviceName, "Web internal Go URL must use the Go API Service name");
|
|
assert(parsedInternalBaseUrl.port === servicePort, "Web internal Go URL must use the Go API Service port");
|
|
assert(targetPort === servicePort, "Go API Service targetPort must match its port");
|
|
|
|
console.log(`ACK manifest assertions passed (${files.length} files)`);
|
|
|
|
function read(file) {
|
|
return readFileSync(new URL(file, directory), "utf8").replace(/\r\n/g, "\n");
|
|
}
|
|
|
|
function assert(condition, message) {
|
|
if (!condition) throw new Error(message);
|
|
}
|