BangSo/scripts/ensure-local-env.test.ts

117 lines
4.4 KiB
TypeScript
Raw Normal View History

2026-09-02 07:38:57 +00:00
import { execFileSync } from "node:child_process";
import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";
const script = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "ensure-local-env.sh");
const EXAMPLE = `NODE_ENV=development
BETTER_AUTH_SECRET=replace-with-32-plus-character-secret
ENCRYPTION_KEY=replace-with-64-random-hex-characters
SANDBOX_SUPERVISOR_TOKEN=
SCREEN_PROXY_SECRET=replace-with-32-plus-character-screen-proxy-secret
COMPUTER_USER_PASSWORD=
COMPUTER_ALLOW_SUDO=
# VITE_DEFAULT_UI_LOCALE=en
`;
function readKey(file: string, key: string) {
let value = "";
for (const line of readFileSync(file, "utf8").split(/\r?\n/)) {
if (line.startsWith(`${key}=`)) value = line.slice(key.length + 1);
}
return value;
}
function run(dir: string, extraEnv: NodeJS.ProcessEnv = {}) {
const env = { ...process.env };
for (const key of [
"BETTER_AUTH_SECRET",
"ENCRYPTION_KEY",
"SANDBOX_SUPERVISOR_TOKEN",
"SCREEN_PROXY_SECRET",
"COMPUTER_USER_PASSWORD",
"COMPUTER_ALLOW_SUDO",
"VITE_DEFAULT_UI_LOCALE",
"LOCAL_COMPUTER_PASSWORD",
"LOCAL_COMPUTER_SUDO",
"LOCAL_UI_LOCALE",
]) {
delete env[key];
}
return execFileSync("bash", [script], {
encoding: "utf8",
env: {
...env,
ENV_FILE: path.join(dir, ".env"),
EXAMPLE_FILE: path.join(dir, ".env.example"),
...extraEnv,
},
});
}
describe("ensure-local-env", () => {
it("creates .env and injects the local computer baseline plus secrets", () => {
const dir = mkdtempSync(path.join(tmpdir(), "bangso-env-"));
writeFileSync(path.join(dir, ".env.example"), EXAMPLE);
const output = run(dir);
const envFile = path.join(dir, ".env");
expect(output).toContain("created");
expect(readKey(envFile, "COMPUTER_ALLOW_SUDO")).toBe("1");
expect(readKey(envFile, "COMPUTER_USER_PASSWORD")).toBe("bangso");
expect(readKey(envFile, "VITE_DEFAULT_UI_LOCALE")).toBe("zh-TW");
expect(readKey(envFile, "BETTER_AUTH_SECRET")).toMatch(/^[0-9a-f]{64}$/);
expect(readKey(envFile, "ENCRYPTION_KEY")).toMatch(/^[0-9a-f]{64}$/);
expect(readKey(envFile, "SANDBOX_SUPERVISOR_TOKEN")).toMatch(/^[0-9a-f]{64}$/);
expect(readKey(envFile, "SCREEN_PROXY_SECRET")).toMatch(/^[0-9a-f]{64}$/);
expect(readKey(envFile, "NODE_ENV")).toBe("development");
});
it("does not clobber values already set in .env", () => {
const dir = mkdtempSync(path.join(tmpdir(), "bangso-env-"));
writeFileSync(path.join(dir, ".env.example"), EXAMPLE);
writeFileSync(
path.join(dir, ".env"),
`BETTER_AUTH_SECRET=keep-auth-secret-value-32chars-min
ENCRYPTION_KEY=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
SANDBOX_SUPERVISOR_TOKEN=keep-supervisor-token-value-32chars
SCREEN_PROXY_SECRET=keep-screen-proxy-secret-value-32c
COMPUTER_USER_PASSWORD=already-set
COMPUTER_ALLOW_SUDO=0
VITE_DEFAULT_UI_LOCALE=en
`,
);
const output = run(dir);
const envFile = path.join(dir, ".env");
expect(output).not.toContain("injected");
expect(readKey(envFile, "COMPUTER_ALLOW_SUDO")).toBe("0");
expect(readKey(envFile, "COMPUTER_USER_PASSWORD")).toBe("already-set");
expect(readKey(envFile, "VITE_DEFAULT_UI_LOCALE")).toBe("en");
expect(readKey(envFile, "BETTER_AUTH_SECRET")).toBe("keep-auth-secret-value-32chars-min");
});
it("fills only blank computer keys and accepts process-env overrides", () => {
const dir = mkdtempSync(path.join(tmpdir(), "bangso-env-"));
writeFileSync(path.join(dir, ".env.example"), EXAMPLE);
writeFileSync(
path.join(dir, ".env"),
`BETTER_AUTH_SECRET=keep-auth-secret-value-32chars-min
ENCRYPTION_KEY=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
SANDBOX_SUPERVISOR_TOKEN=keep-supervisor-token-value-32chars
SCREEN_PROXY_SECRET=keep-screen-proxy-secret-value-32c
COMPUTER_USER_PASSWORD=
COMPUTER_ALLOW_SUDO=
`,
);
run(dir, { COMPUTER_USER_PASSWORD: "from-make", COMPUTER_ALLOW_SUDO: "1" });
const envFile = path.join(dir, ".env");
expect(readKey(envFile, "COMPUTER_USER_PASSWORD")).toBe("from-make");
expect(readKey(envFile, "COMPUTER_ALLOW_SUDO")).toBe("1");
expect(readKey(envFile, "VITE_DEFAULT_UI_LOCALE")).toBe("zh-TW");
expect(readKey(envFile, "BETTER_AUTH_SECRET")).toBe("keep-auth-secret-value-32chars-min");
});
});