85 lines
3.2 KiB
JavaScript
85 lines
3.2 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { spawnSync } from "node:child_process";
|
|
import { fileURLToPath } from "node:url";
|
|
import { describe, it } from "vitest";
|
|
|
|
const rootDirectory = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
const startScript = path.join(rootDirectory, "start.sh");
|
|
|
|
describe("portal container entrypoint credential boundary", () => {
|
|
it("starts with only the dedicated portal runtime authority", () => {
|
|
const result = runPortalEntrypoint();
|
|
assert.equal(result.status, 0, result.stderr);
|
|
assert.match(result.stdout, /portal-runtime-started/);
|
|
});
|
|
|
|
it("allows Coolify's injected non-secret runtime metadata", () => {
|
|
const result = runPortalEntrypoint({
|
|
COOLIFY_BRANCH: "main",
|
|
COOLIFY_CONTAINER_NAME: "portal-container",
|
|
COOLIFY_FQDN: "staging-portal.example.test",
|
|
COOLIFY_RESOURCE_UUID: "portal-resource",
|
|
COOLIFY_URL: "https://staging-portal.example.test",
|
|
});
|
|
|
|
assert.equal(result.status, 0, result.stderr);
|
|
assert.match(result.stdout, /portal-runtime-started/);
|
|
});
|
|
|
|
it("does not forward its environment-key snapshot to the Node runtime", () => {
|
|
const result = runPortalEntrypoint({ PORTAL_ENV_KEYS: "caller-controlled" });
|
|
|
|
assert.equal(result.status, 0, result.stderr);
|
|
assert.match(result.stdout, /portal-runtime-started/);
|
|
});
|
|
|
|
it.each([
|
|
"SESSION_SECRET",
|
|
"AUTHENTIK_CLIENT_SECRET",
|
|
"GOOGLE_OAUTH_CLIENT_SECRET",
|
|
"MCP_OAUTH_TOKEN_HASH_SECRET",
|
|
"BILLING_API_KEY",
|
|
"LAGO_API_KEY",
|
|
"COOLIFY",
|
|
"COOLIFY_TOKEN",
|
|
"COOLIFY_UNRECOGNIZED_METADATA",
|
|
"SSH_AUTH_SOCK",
|
|
"TRAEFIK_API_TOKEN",
|
|
"INGRESS_PASSWORD",
|
|
"CLOUDFLARE_API_TOKEN",
|
|
"PORTAL_SERVER_SECRET",
|
|
"DOMAIN_CONTROLLER_TOKEN",
|
|
"CUSTOMER_DOMAIN_CONTROLLER_TOKEN",
|
|
])("fails closed before Node starts when %s is present", (key) => {
|
|
const result = runPortalEntrypoint({ [key]: "must-not-reach-the-portal" });
|
|
assert.notEqual(result.status, 0);
|
|
assert.doesNotMatch(result.stdout, /portal-runtime-started/);
|
|
assert.match(result.stderr, /(?:SESSION_SECRET is forbidden|forbidden core session, OAuth, billing, ingress, or domain-controller credential)/);
|
|
assert.doesNotMatch(result.stderr, /must-not-reach-the-portal/);
|
|
});
|
|
});
|
|
|
|
function runPortalEntrypoint(extraEnv = {}) {
|
|
const temporaryDirectory = fs.mkdtempSync(path.join(os.tmpdir(), "hivegrid-portal-entrypoint-"));
|
|
const nodeStub = path.join(temporaryDirectory, "node");
|
|
fs.writeFileSync(nodeStub, '#!/bin/sh\n[ -z "${PORTAL_ENV_KEYS+x}" ] || exit 19\necho portal-runtime-started\n');
|
|
fs.chmodSync(nodeStub, 0o755);
|
|
return spawnSync("/bin/sh", [startScript], {
|
|
encoding: "utf8",
|
|
env: {
|
|
PATH: `${temporaryDirectory}:/usr/bin:/bin`,
|
|
RLS_RUNTIME_MODE: "required",
|
|
DATABASE_URL: "postgresql://hivegrid_portal:secret@db.example.test:5432/hivegrid",
|
|
DATABASE_RUNTIME_ROLE: "hivegrid_portal",
|
|
WEB_RUNTIME_SURFACE: "portal",
|
|
PORTAL_SESSION_SECRET: "portal-session-secret-minimum-32-bytes",
|
|
MCAPTCHA_ACCOUNT_SECRET: "allowed-portal-captcha-secret",
|
|
MAILJET_API_KEY: "allowed-mail-delivery-key",
|
|
...extraEnv,
|
|
},
|
|
});
|
|
}
|