Files
eden/tests/infisical.test.ts
T

123 lines
8.0 KiB
TypeScript

import { describe, expect, test } from 'bun:test';
import { chmod, mkdtemp, rm, symlink, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import {
ADMIN_KEY, applicationEnvironment, BOOTSTRAP_KEYS, fetchSecrets,
localDeploymentAdmin, parseExport, readCredentials, validateProject,
type Environment, type VaultProject,
} from '../scripts/lib/infisical';
import { parseArguments } from '../scripts/secrets';
const project: VaultProject = {
workspaceId: 'e176b742-85cd-4af6-96a7-f33ab7c2c709', defaultEnvironment: 'dev',
domain: 'https://secrets.jb.codes', secretPath: '/',
};
const credentials = { [BOOTSTRAP_KEYS[0]]: 'fake-client-id', [BOOTSTRAP_KEYS[1]]: 'fake-client-secret' };
describe('Infisical boundary', () => {
test('accepts Bun-forwarded commands and preserves child --help arguments', () => {
expect(parseArguments(['run', 'docker', 'compose', 'config', '--quiet']).command).toEqual(['docker', 'compose', 'config', '--quiet']);
expect(parseArguments(['run', '--deployment', '--', 'bun', 'tool.ts', '--help'])).toMatchObject({ deployment: true, command: ['bun', 'tool.ts', '--help'] });
expect(parseArguments(['run', '--worker', '--', 'bun', 'workers/sync.ts'])).toMatchObject({ worker: true, command: ['bun', 'workers/sync.ts'] });
expect(() => parseArguments(['run', '--configure', '--', 'bun', 'scripts/configure-convex.ts'])).toThrow('--configure requires --deployment');
expect(parseArguments(['run', '--deployment', '--configure', '--', 'bun', 'scripts/configure-convex.ts'])).toMatchObject({ deployment: true, configure: true, command: ['bun', 'scripts/configure-convex.ts'] });
expect(() => parseArguments(['run', '--worker', '--deployment', '--', 'bun', 'worker.ts'])).toThrow();
expect(parseArguments(['status']).action).toBe('status');
expect(() => parseArguments(['run', '--unknown'])).toThrow();
expect(() => parseArguments(['status', '--', 'printenv'])).toThrow();
});
test('reads only protected regular credentials files without evaluating dotenv', async () => {
const directory = await mkdtemp(join(tmpdir(), 'eve-vault-'));
try {
const file = join(directory, 'identity.env');
await writeFile(file, `${BOOTSTRAP_KEYS[0]}="fake-client-id"\n${BOOTSTRAP_KEYS[1]}='fake-client-secret'\nNODE_OPTIONS=untrusted\n`, { mode: 0o600 });
expect(await readCredentials(file)).toEqual(credentials);
await symlink(file, join(directory, 'link'));
await expect(readCredentials(join(directory, 'link'))).rejects.toThrow('0600');
await chmod(file, 0o644);
await expect(readCredentials(file)).rejects.toThrow('0600');
} finally { await rm(directory, { recursive: true, force: true }); }
});
test('pins the authorized vault before sending any credential', async () => {
expect(validateProject(project)).toEqual(project);
let called = false;
await expect(fetchSecrets({ ...project, domain: 'https://attacker.invalid' }, credentials, async () => { called = true; return ''; })).rejects.toThrow('approved instance');
expect(called).toBe(false);
});
test('authenticates and exports only the selected scope; never places credentials in argv', async () => {
const calls: { args: string[]; env: Environment }[] = [];
const values = await fetchSecrets(project, credentials, async (args, env) => {
calls.push({ args, env });
return args[0] === 'login' ? 'fake-access-token\n' : '[{"key":"TYPESAFE_API_KEY","value":"fake-key"}]';
}, { PATH: '/usr/bin', INFISICAL_TOKEN: 'stale-token', [ADMIN_KEY]: 'admin', ...credentials });
expect(values.TYPESAFE_API_KEY).toBe('fake-key');
expect(calls[0].env[BOOTSTRAP_KEYS[1]]).toBe('fake-client-secret');
expect(calls[0].env.INFISICAL_TOKEN).toBeUndefined();
expect(calls[1].env.INFISICAL_TOKEN).toBe('fake-access-token');
expect(calls[1].env[BOOTSTRAP_KEYS[1]]).toBeUndefined();
expect(calls[1].env[ADMIN_KEY]).toBeUndefined();
expect(calls[1].args).toContain(project.workspaceId);
expect(calls[1].args).toContain('--expand=false');
expect(calls[1].args).toContain('--include-imports=false');
expect(calls.every(call => call.args.includes(project.domain))).toBe(true);
expect(JSON.stringify(calls.map(call => call.args))).not.toContain('fake-client');
expect(JSON.stringify(calls.map(call => call.args))).not.toContain('fake-access-token');
});
test('derives admin credentials only for the local deployment and keeps other secrets out of Docker argv/env', async () => {
let calls = 0;
const runner = async (argv: string[], env: Environment) => {
calls++;
expect(argv).toEqual(['docker', 'compose', 'exec', '-T', 'backend', './generate_admin_key.sh']);
expect(env.INFISICAL_TOKEN).toBeUndefined();
expect(env.EVE_CLIENT_SECRET).toBeUndefined();
return 'fake-admin\n';
};
expect(await localDeploymentAdmin({ CONVEX_SELF_HOSTED_URL: 'http://127.0.0.1:3210', INFISICAL_TOKEN: 'token', EVE_CLIENT_SECRET: 'secret' }, runner)).toBe('fake-admin');
await expect(localDeploymentAdmin({ CONVEX_SELF_HOSTED_URL: 'https://other.example' }, runner)).rejects.toThrow('restricted');
expect(calls).toBe(1);
});
test('rejects malformed/duplicate exports without echoing values', () => {
expect(parseExport('{"TYPESAFE_API_KEY":"test"}')).toEqual({ TYPESAFE_API_KEY: 'test' });
for (const raw of ['secret-in-malformed-json', '[{"key":"KEY","value":1}]', '[{"key":"KEY","value":"a"},{"key":"KEY","value":"b"}]', 'null']) {
expect(() => parseExport(raw)).toThrow('Invalid Infisical export; values suppressed');
}
});
test('child processes receive only managed app keys, without bootstrap or ambient admin credentials', () => {
const base = { PATH: '/usr/bin', INFISICAL_TOKEN: 'token', [ADMIN_KEY]: 'ambient-admin', ...credentials, TYPESAFE_API_KEY: 'stale-key' };
const values = { EVE_CLIENT_ID: 'client', EVE_CLIENT_SECRET: 'secret', CONVEX_BRIDGE_SECRET: 'bridge', CONVEX_SYNC_WORKER_SECRET: 'worker', APP_AUTH_PRIVATE_KEY: 'private', APP_AUTH_JWKS: 'jwks', [ADMIN_KEY]: 'vault-admin', NODE_OPTIONS: 'not-injected' };
const config = { APP_ORIGIN: 'https://dev.evebot.app' };
const env = applicationEnvironment(base, values, config);
expect(env.EVE_CLIENT_SECRET).toBe('secret');
expect(env.CONVEX_SYNC_WORKER_SECRET).toBeUndefined();
expect(env.PATH).toBe('/usr/bin');
expect(env.APP_ORIGIN).toBe(config.APP_ORIGIN);
expect(env.TYPESAFE_API_KEY).toBeUndefined();
expect(env[ADMIN_KEY]).toBeUndefined();
expect(env.NODE_OPTIONS).toBeUndefined();
expect(Object.keys(env).some(key => key.startsWith('INFISICAL_'))).toBe(false);
expect(applicationEnvironment(base, values, config, true)[ADMIN_KEY]).toBe('vault-admin');
const workerEnv = applicationEnvironment(base, values, config, false, 'worker');
expect(workerEnv.CONVEX_SYNC_WORKER_SECRET).toBe('worker');
expect(workerEnv.CONVEX_BRIDGE_SECRET).toBeUndefined();
expect(workerEnv.APP_AUTH_PRIVATE_KEY).toBeUndefined();
expect(workerEnv.APP_AUTH_JWKS).toBeUndefined();
const configureEnv = applicationEnvironment(base, values, { ...config, APP_AUTH_ISSUER: 'https://issuer.example', APP_CAPABILITY_ALLOWLIST: 'asset_sync' }, true, 'configure');
expect(configureEnv.CONVEX_BRIDGE_SECRET).toBe('bridge');
expect(configureEnv.CONVEX_SYNC_WORKER_SECRET).toBe('worker');
expect(configureEnv.APP_AUTH_JWKS).toBe('jwks');
expect(configureEnv[ADMIN_KEY]).toBe('vault-admin');
expect(configureEnv.APP_AUTH_ISSUER).toBe('https://issuer.example');
expect(configureEnv.APP_CAPABILITY_ALLOWLIST).toBe('asset_sync');
for (const excluded of ['TOKEN_ENCRYPTION_KEY', 'APP_AUTH_PRIVATE_KEY', 'EVE_CLIENT_ID', 'EVE_CLIENT_SECRET', 'TYPESAFE_API_KEY']) expect(configureEnv[excluded]).toBeUndefined();
expect(() => applicationEnvironment(base, values, { INFISICAL_TOKEN: 'do-not-forward' })).toThrow('Unexpected public');
expect(() => applicationEnvironment(base, values, { NODE_OPTIONS: 'do-not-execute' })).toThrow('Unexpected public');
});
});