Gitea Actions Runner Test / test-job (push) Successful in 0s
CI / check (push) Successful in 30s
CI / tests-unit (push) Successful in 1m37s
CI / tests-integration (push) Successful in 1m55s
CI / tests-ui (push) Successful in 2m23s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m38s
178 lines
5.2 KiB
JavaScript
178 lines
5.2 KiB
JavaScript
import { spawnSync } from "node:child_process";
|
|
import {
|
|
copyFileSync,
|
|
mkdirSync,
|
|
mkdtempSync,
|
|
readFileSync,
|
|
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 profile from .env for bare Compose commands 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];
|
|
const result = spawnSync(
|
|
"docker",
|
|
["compose", "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,
|
|
);
|
|
|
|
it("documents the local CrowdSec switches in .env.example", () => {
|
|
const examples = readFileSync(path.join(root, ".env.example"), "utf8");
|
|
for (const key of [
|
|
"CROWDSEC_LOCAL_ENABLED",
|
|
"CROWDSEC_LAPI_URL",
|
|
"CROWDSEC_LAPI_PORT",
|
|
"CROWDSEC_LAPI_API_KEY",
|
|
"CROWDSEC_NGINX_LOG_DIR",
|
|
]) {
|
|
expect(examples).toContain(key);
|
|
}
|
|
});
|
|
|
|
it.skipIf(!hasCompose)(
|
|
"renders the standalone CrowdSec stack with a loopback-only LAPI",
|
|
() => {
|
|
const directory = mkdtempSync(path.join(tmpdir(), "cms-crowdsec-"));
|
|
try {
|
|
mkdirSync(path.join(directory, "deployment/crowdsec/acquis.d"), {
|
|
recursive: true,
|
|
});
|
|
copyFileSync(
|
|
path.join(root, "deployment/crowdsec/compose.crowdsec.yml"),
|
|
path.join(directory, "deployment/crowdsec/compose.crowdsec.yml"),
|
|
);
|
|
copyFileSync(
|
|
path.join(root, "deployment/crowdsec/acquis.d/nginx.yaml"),
|
|
path.join(directory, "deployment/crowdsec/acquis.d/nginx.yaml"),
|
|
);
|
|
writeFileSync(
|
|
path.join(directory, ".env"),
|
|
[
|
|
"CROWDSEC_LAPI_API_KEY=fixture-key",
|
|
"CROWDSEC_LAPI_PORT=18080",
|
|
"CROWDSEC_LAPI_URL=http://127.0.0.1:18080",
|
|
"CROWDSEC_NGINX_LOG_DIR=/var/log/nginx",
|
|
].join("\n"),
|
|
);
|
|
const environment = { ...process.env };
|
|
for (const key of Object.keys(environment))
|
|
if (
|
|
key.startsWith("COMPOSE_") ||
|
|
key.startsWith("CROWDSEC_") ||
|
|
key.startsWith("TZ")
|
|
)
|
|
delete environment[key];
|
|
const result = spawnSync(
|
|
"docker",
|
|
[
|
|
"compose",
|
|
"--project-name",
|
|
"crowdsec-fixture",
|
|
"--env-file",
|
|
".env",
|
|
"-f",
|
|
"deployment/crowdsec/compose.crowdsec.yml",
|
|
"--profile",
|
|
"security",
|
|
"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 service = config.services.crowdsec;
|
|
expect(service).toBeDefined();
|
|
expect(service.image).toContain("crowdsecurity/crowdsec:");
|
|
expect(service.environment.BOUNCER_KEY_cms).toBe("fixture-key");
|
|
expect(service.environment.DISABLE_ONLINE_API).toBe("true");
|
|
expect(
|
|
service.ports.some(
|
|
(published) =>
|
|
published.host_ip === "127.0.0.1" &&
|
|
published.published === "18080" &&
|
|
published.target === 8080,
|
|
),
|
|
).toBe(true);
|
|
const targets = service.volumes.map((volume) => volume.target);
|
|
expect(targets).toContain("/var/log/nginx");
|
|
expect(targets).toContain("/etc/crowdsec/acquis.d");
|
|
expect(service.healthcheck.test.join(" ")).toContain("wget");
|
|
} finally {
|
|
rmSync(directory, { recursive: true, force: true });
|
|
}
|
|
},
|
|
30_000,
|
|
);
|