Files
OmniRoute/tests/unit/bootstrap-env.test.ts
diegosouzapw f3b944a55a refactor(scripts): organize into build/dev/check/docs/i18n/ad-hoc subfolders
Reorganizes the 29 active scripts under scripts/ into purpose-driven
subfolders:

- scripts/build/    (11) — Build, install, publish, runtime env
- scripts/dev/      (13) — Dev servers, test runners, healthchecks
- scripts/check/    (10) — Lint/validation/coverage checks
- scripts/docs/      (2) — Docs index and provider reference generation
- scripts/i18n/     (+3) — Adds Python translation utilities (check/validate/autotranslate)
- scripts/ad-hoc/    (4) — One-shot maintenance utilities

Updates all references in package.json, electron/package.json,
.husky/pre-commit, .github/workflows/ci.yml, Dockerfile, src/,
tests/, scripts/ internal cross-imports, playwright.config.ts,
and English docs (CODEBASE_DOCUMENTATION, ENVIRONMENT, FEATURES,
RELEASE_CHECKLIST, COVERAGE_PLAN, ELECTRON_GUIDE, I18N, GEMINI).

Also patches scripts/build/pack-artifact-policy.ts so the npm pack
allowlist mirrors the new layout.

Validates with:
- npm run lint            (exit 0 — pre-existing minified-bundle errors only)
- npm run typecheck:core  (exit 0)
- npm run check:docs-all  (exit 0)
- unit tests for moved scripts (57 tests pass)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:14:25 -03:00

134 lines
4.2 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import Database from "better-sqlite3";
import { bootstrapEnv } from "../../scripts/build/bootstrap-env.mjs";
function withTempEnv(fn) {
const originalCwd = process.cwd();
const originalEnv = { ...process.env };
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-bootstrap-test-"));
const tempCwd = path.join(tempRoot, "cwd");
const tempHome = path.join(tempRoot, "home");
fs.mkdirSync(tempCwd, { recursive: true });
fs.mkdirSync(tempHome, { recursive: true });
delete process.env.DATA_DIR;
delete process.env.XDG_CONFIG_HOME;
delete process.env.APPDATA;
delete process.env.JWT_SECRET;
delete process.env.STORAGE_ENCRYPTION_KEY;
delete process.env.STORAGE_ENCRYPTION_KEY_VERSION;
delete process.env.API_KEY_SECRET;
delete process.env.INITIAL_PASSWORD;
process.env.HOME = tempHome;
process.chdir(tempCwd);
try {
fn({ tempRoot, tempCwd, tempHome, dataDir: path.join(tempHome, ".omniroute") });
} finally {
process.chdir(originalCwd);
for (const key of Object.keys(process.env)) {
if (!(key in originalEnv)) delete process.env[key];
}
for (const [key, value] of Object.entries(originalEnv)) {
process.env[key] = value;
}
fs.rmSync(tempRoot, { recursive: true, force: true });
}
}
test("bootstrapEnv prefers ~/.omniroute/.env over server.env", () => {
withTempEnv(({ dataDir }) => {
process.env.DATA_DIR = dataDir;
fs.mkdirSync(dataDir, { recursive: true });
fs.writeFileSync(
path.join(dataDir, ".env"),
"STORAGE_ENCRYPTION_KEY=from-dot-env\nJWT_SECRET=jwt-from-dot-env\n",
"utf8"
);
fs.writeFileSync(
path.join(dataDir, "server.env"),
"STORAGE_ENCRYPTION_KEY=from-server-env\nJWT_SECRET=jwt-from-server-env\n",
"utf8"
);
const env = bootstrapEnv({ quiet: true });
assert.equal(env.STORAGE_ENCRYPTION_KEY, "from-dot-env");
assert.equal(env.JWT_SECRET, "jwt-from-dot-env");
});
});
test("bootstrapEnv strips matching quotes from env values", () => {
withTempEnv(({ dataDir }) => {
process.env.DATA_DIR = dataDir;
fs.mkdirSync(dataDir, { recursive: true });
fs.writeFileSync(
path.join(dataDir, "server.env"),
'JWT_SECRET="jwt-from-server-env"\nCLAUDE_USER_AGENT="claude-cli/2.1.137 (external, cli)"\n',
"utf8"
);
const env = bootstrapEnv({ quiet: true });
assert.equal(env.JWT_SECRET, "jwt-from-server-env");
assert.equal(env.CLAUDE_USER_AGENT, "claude-cli/2.1.137 (external, cli)");
});
});
test("bootstrapEnv refuses to generate a new key over encrypted data", () => {
withTempEnv(({ dataDir }) => {
process.env.DATA_DIR = dataDir;
fs.mkdirSync(dataDir, { recursive: true });
const db = new Database(path.join(dataDir, "storage.sqlite"));
try {
db.exec(`
CREATE TABLE provider_connections (
id TEXT PRIMARY KEY,
access_token TEXT,
refresh_token TEXT,
api_key TEXT,
id_token TEXT
);
`);
db.prepare("INSERT INTO provider_connections (id, access_token) VALUES (?, ?)").run(
"conn-1",
"enc:v1:deadbeef:feedface:cafebabe"
);
} finally {
db.close();
}
assert.throws(
() => bootstrapEnv({ quiet: true }),
/Refusing to auto-generate STORAGE_ENCRYPTION_KEY/
);
});
});
test("bootstrapEnv fails closed when existing database cannot be inspected", () => {
withTempEnv(({ dataDir }) => {
process.env.DATA_DIR = dataDir;
fs.mkdirSync(path.join(dataDir, "storage.sqlite"), { recursive: true });
assert.throws(() => bootstrapEnv({ quiet: true }), /Unable to inspect existing database/);
});
});
test("bootstrapEnv ignores blank dataDirOverride values", () => {
withTempEnv(({ dataDir }) => {
process.env.DATA_DIR = dataDir;
fs.mkdirSync(dataDir, { recursive: true });
fs.writeFileSync(path.join(dataDir, ".env"), "JWT_SECRET=jwt-from-dot-env\n", "utf8");
const env = bootstrapEnv({ dataDirOverride: " ", quiet: true });
assert.equal(env.JWT_SECRET, "jwt-from-dot-env");
});
});