Files
EpicNext-Cms/scripts/proxy-config.test.mjs
T
openhands 597287fce5
CI / check (push) Successful in 36s
CI / tests-imaging-browsers (push) Successful in 1m49s
CI / tests-integration (push) Successful in 1m59s
CI / tests-unit (push) Successful in 2m4s
CI / tests-quality (push) Successful in 42s
CI / tests-ui (push) Successful in 4m39s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 3m20s
fix(compose): keep the CMS opt-in so it cannot claim the CI port
On a CI-managed host scripts/ci-deploy.sh owns port 3002 through the
blue/green slots, so a compose replica of the cms service could only ever
crash-loop on EADDRINUSE — it never serves traffic, because nginx points at a
slot container. Gate the service behind the `cms` profile so a bare
`docker compose up -d` starts only byparr. Naming the service explicitly
(`docker compose up -d cms`, which is what the installer and updater already
do) still enables the profile automatically, so the compose-only install path
keeps working.

Keep the one port that is actually served (3002) and make the 2 GB ceiling
hard by capping swap at 2g as well. Drop the green compose service (3003):
the green slot only ever exists as a docker run container created by CI, so
compose no longer defines it and the two paths cannot drift apart.

The loopback override contract stays covered: proxy-config.test.mjs now
renders the configuration with --profile cms, and a new build-contract test
pins the profile and the memory limits so neither can be dropped by accident.
2026-10-19 19:00:07 +02:00

90 lines
2.8 KiB
JavaScript

import { spawnSync } from "node:child_process";
import {
copyFileSync,
mkdirSync,
mkdtempSync,
rmSync,
writeFileSync,
} from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { expect, it } from "vitest";
const root = process.cwd();
const hasCompose =
spawnSync("docker", ["compose", "version"], {
encoding: "utf8",
timeout: 10_000,
}).status === 0;
it.skipIf(!hasCompose)(
"loads the loopback override from .env for the cms service without changing mounts or host networking",
() => {
const directory = mkdtempSync(path.join(tmpdir(), "cms-proxy-config-"));
try {
mkdirSync(path.join(directory, "deployment/proxy"), { recursive: true });
copyFileSync(
path.join(root, "docker-compose.yml"),
path.join(directory, "docker-compose.yml"),
);
copyFileSync(
path.join(root, "deployment/proxy/compose.loopback.yml"),
path.join(directory, "deployment/proxy/compose.loopback.yml"),
);
writeFileSync(
path.join(directory, ".env"),
[
"COMPOSE_FILE=docker-compose.yml:deployment/proxy/compose.loopback.yml",
"COMPOSE_PATH_SEPARATOR=:",
"CMS_RELEASE=reviewed-release",
"HOSTNAME=0.0.0.0",
"PORT=9999",
"HOTEL_NAME=Proxy fixture",
"DATABASE_URL=mysql://fixture:[email protected]/fixture",
].join("\n"),
);
const environment = { ...process.env };
for (const key of Object.keys(environment))
if (
key.startsWith("COMPOSE_") ||
["CMS_RELEASE", "HOSTNAME", "PORT"].includes(key)
)
delete environment[key];
// `cms` is behind the `cms` profile so a bare `docker compose up -d`
// can never squat port 3002 on a CI-managed host. Selecting the
// profile here keeps the loopback/port-override contract under test.
const result = spawnSync(
"docker",
["compose", "--profile", "cms", "config", "--format", "json"],
{ cwd: directory, env: environment, encoding: "utf8", timeout: 15_000 },
);
expect(result.status, result.stderr).toBe(0);
const config = JSON.parse(result.stdout);
const cms = config.services.cms;
expect(cms.environment.HOSTNAME).toBe("127.0.0.1");
expect(cms.environment.PORT).toBe("3002");
expect(cms.network_mode).toBe("host");
expect(cms.ports).toBeUndefined();
expect(cms.image).toBe("epicnext-cms:reviewed-release");
expect(cms.healthcheck.test).toEqual([
"CMD",
"node",
"-e",
"fetch('http://127.0.0.1:3002/api/health').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))",
]);
expect(cms.volumes.map((volume) => volume.target).sort()).toEqual([
"/app/public/nitro-assets",
"/app/public/swf",
"/app/storage",
"/var/www/Gamedata",
]);
expect(cms.environment.DATABASE_URL).toBe(
"mysql://fixture:[email protected]/fixture",
);
} finally {
rmSync(directory, { recursive: true, force: true });
}
},
30_000,
);