Initial Commit

This commit is contained in:
jb
2026-09-18 23:15:05 -04:00
commit fdcc4863f5
118 changed files with 16868 additions and 0 deletions
+174
View File
@@ -0,0 +1,174 @@
import { constants } from 'node:fs';
import { open } from 'node:fs/promises';
import { parseEnv } from 'node:util';
import { fileURLToPath } from 'node:url';
export interface VaultProject {
workspaceId: string;
defaultEnvironment: string;
domain: string;
secretPath: string;
}
export const BOOTSTRAP_KEYS = ['INFISICAL_UNIVERSAL_AUTH_CLIENT_ID', 'INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET'] as const;
export const APPLICATION_KEYS = [
'EVE_CLIENT_ID', 'EVE_CLIENT_SECRET', 'TYPESAFE_API_KEY', 'TOKEN_ENCRYPTION_KEY',
'CONVEX_BRIDGE_SECRET', 'APP_AUTH_PRIVATE_KEY', 'APP_AUTH_JWKS',
] as const;
export const REQUIRED_KEYS = ['EVE_CLIENT_ID', 'TOKEN_ENCRYPTION_KEY', 'CONVEX_BRIDGE_SECRET', 'APP_AUTH_PRIVATE_KEY', 'APP_AUTH_JWKS'] as const;
export const ADMIN_KEY = 'CONVEX_SELF_HOSTED_ADMIN_KEY';
export type Environment = Record<string, string | undefined>;
export type CliRunner = (args: string[], env: Environment) => Promise<string>;
export function validateProject(input: unknown): VaultProject {
if (!input || typeof input !== 'object' || Array.isArray(input)) throw new Error('Invalid Infisical project configuration');
const project = input as Record<string, unknown>;
if (typeof project.workspaceId !== 'string' || !/^[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$/i.test(project.workspaceId)) throw new Error('Invalid Infisical project ID');
if (typeof project.defaultEnvironment !== 'string' || !/^[a-zA-Z0-9_-]+$/.test(project.defaultEnvironment)) throw new Error('Invalid Infisical environment');
// This repository is deliberately pinned to the operator-authorized vault origin.
// A repository config change alone must never send the bootstrap credential elsewhere.
if (project.domain !== 'https://secrets.jb.codes') throw new Error('Infisical origin is not the approved instance');
if (typeof project.secretPath !== 'string' || !/^\/(?:[a-zA-Z0-9_-]+(?:\/[a-zA-Z0-9_-]+)*)?$/.test(project.secretPath)) throw new Error('Invalid Infisical secret path');
return project as unknown as VaultProject;
}
export async function readCredentials(path: string): Promise<Record<string, string>> {
let handle;
try {
// Do not follow a symlink or read a world/group-accessible bootstrap secret.
handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
const stat = await handle.stat();
if (!stat.isFile() || (stat.mode & 0o077) !== 0 || stat.uid !== process.getuid?.() || stat.size > 16_384) {
throw new Error('Invalid credentials file');
}
const parsed = parseEnv(await handle.readFile('utf8'));
const selected: Record<string, string> = {};
for (const name of BOOTSTRAP_KEYS) {
if (!parsed[name]?.trim()) throw new Error('Missing bootstrap credential');
selected[name] = parsed[name];
}
return selected;
} catch {
throw new Error('Cannot read Universal Auth credentials: use a regular, owner-owned 0600 file containing the two documented variables');
} finally {
await handle?.close();
}
}
async function boundedOutput(stream: ReadableStream<Uint8Array>, limit: number): Promise<string> {
const reader = stream.getReader();
const chunks: Uint8Array[] = [];
let bytes = 0;
try {
for (;;) {
const { value, done } = await reader.read();
if (done) break;
bytes += value.byteLength;
if (bytes > limit) throw new Error('Infisical output exceeded its safety limit');
chunks.push(value);
}
} finally { reader.releaseLock(); }
return Buffer.concat(chunks).toString('utf8');
}
async function captureSecretCommand(argv: string[], env: Environment): Promise<string> {
const child = Bun.spawn(argv, { env, stdin: 'ignore', stdout: 'pipe', stderr: 'pipe' });
const deadline = setTimeout(() => child.kill('SIGKILL'), 30_000);
deadline.unref();
try {
const [output, , code] = await Promise.all([
boundedOutput(child.stdout, 2 * 1024 * 1024),
boundedOutput(child.stderr, 64 * 1024),
child.exited,
]);
if (code !== 0) throw new Error('CLI failed');
return output;
} catch {
// CLI errors can embed request details. Never echo raw stdout/stderr or credentials.
throw new Error('Credential command failed; check permissions and connectivity (raw output suppressed)');
} finally {
clearTimeout(deadline);
if (child.exitCode === null) child.kill('SIGKILL');
}
}
export const runCli: CliRunner = async (args, env) => {
const executable = fileURLToPath(new URL('../../node_modules/.bin/infisical', import.meta.url));
return captureSecretCommand([executable, ...args], env);
};
export async function localDeploymentAdmin(env: Environment, runner = captureSecretCommand): Promise<string> {
if (!['http://127.0.0.1:3210', 'http://localhost:3210'].includes(env.CONVEX_SELF_HOSTED_URL ?? '')) {
throw new Error('Local admin derivation is restricted to this host’s Convex deployment');
}
// The backend derives its admin credential from its persistent random instance
// secret. Docker-host access is already administrative; no second secret file
// or write-enabled Infisical identity is required. Only explicit --deployment
// commands receive this key; Compose never forwards it to the web container.
const key = (await runner(['docker', 'compose', 'exec', '-T', 'backend', './generate_admin_key.sh'], cleanEnvironment(env))).trim();
if (!key || /\s/.test(key) || key.length > 16_384) throw new Error('Unexpected local admin response; output suppressed');
return key;
}
export function parseExport(text: string): Record<string, string> {
try {
const parsed: unknown = JSON.parse(text);
const values: Record<string, string> = Object.create(null);
const entries: unknown[] = Array.isArray(parsed)
? parsed
: parsed && typeof parsed === 'object'
? Object.entries(parsed).map(([key, value]) => ({ key, value }))
: [];
if (!parsed || typeof parsed !== 'object') throw new Error();
for (const entry of entries) {
if (!entry || typeof entry !== 'object') throw new Error();
const row = entry as Record<string, unknown>;
const key = row.key ?? row.secretKey;
const value = row.value ?? row.secretValue;
if (typeof key !== 'string' || !/^[A-Z][A-Z0-9_]*$/.test(key) || typeof value !== 'string' || Object.hasOwn(values, key)) throw new Error();
values[key] = value;
}
return values;
} catch { throw new Error('Invalid Infisical export; values suppressed'); }
}
export async function fetchSecrets(project: VaultProject, credentials: Record<string, string>, runner: CliRunner = runCli, base: Environment = process.env): Promise<Record<string, string>> {
validateProject(project);
for (const name of BOOTSTRAP_KEYS) if (!credentials[name]) throw new Error(`Missing ${name}`);
const env = cleanEnvironment(base);
const common = ['--domain', project.domain, '--silent', '--telemetry=false'];
const bootstrap = Object.fromEntries(BOOTSTRAP_KEYS.map(key => [key, credentials[key]]));
const token = (await runner(['login', '--method=universal-auth', '--plain', ...common], { ...env, ...bootstrap })).trim();
if (!token || /\s/.test(token) || token.length > 16_384) throw new Error('Unexpected Infisical login response; values suppressed');
const output = await runner([
'export', '--projectId', project.workspaceId, '--env', project.defaultEnvironment, '--path', project.secretPath,
'--format=json', '--expand=false', '--include-imports=false', '--secret-overriding=false', ...common,
], { ...env, INFISICAL_TOKEN: token });
return parseExport(output);
}
export function cleanEnvironment(base: Environment): Environment {
const managed = new Set<string>([ADMIN_KEY, ...APPLICATION_KEYS]);
return Object.fromEntries(Object.entries(base).filter(([key]) => !key.startsWith('INFISICAL_') && !managed.has(key)));
}
const PUBLIC_KEYS = new Set([
'APP_MODE', 'APP_ORIGIN', 'APP_AUTH_ISSUER', 'EVE_CALLBACK_URL', 'PUBLIC_CONVEX_URL',
'CONVEX_URL', 'CONVEX_SELF_HOSTED_URL', 'CONVEX_SITE_ORIGIN', 'REFERENCE_DIR', 'ESI_USER_AGENT',
'WEB_BIND_ADDRESS', 'CONVEX_BIND_ADDRESS', 'WEB_PORT', 'CONVEX_PORT', 'CONVEX_SITE_PORT',
'CONVEX_IMAGE', 'CONVEX_DASHBOARD_IMAGE',
]);
export function applicationEnvironment(base: Environment, secrets: Record<string, string>, publicConfig: Environment, deployment = false): Environment {
const env = cleanEnvironment(base);
// Public file is the configured deployment, not defaults inherited from Bun's .env.local.
for (const [key, value] of Object.entries(publicConfig)) {
if (!PUBLIC_KEYS.has(key) || typeof value !== 'string') throw new Error('Unexpected public deployment configuration key');
env[key] = value;
}
// Managed app keys must come from the selected vault, never a stale ambient .env.
for (const key of APPLICATION_KEYS) {
delete env[key];
if (secrets[key] !== undefined) env[key] = secrets[key];
}
if (deployment && secrets[ADMIN_KEY]) env[ADMIN_KEY] = secrets[ADMIN_KEY];
return env;
}