Files
brain/tools/keychain-read.test.mjs
T

56 lines
2.7 KiB
JavaScript
Raw Normal View History

// tools/keychain-read.test.mjs
// Синхронное чтение OS-keychain через async-only keytar (у keytar НЕТ getPasswordSync).
// Обёртка запускает короткий node-subprocess (execFileSync блокирует), который await'ит
// keytar.getPassword и печатает значение → resolveReceiptKey/resolveJudgeKey остаются синхронными.
import { describe, it, expect } from 'vitest';
import { buildKeychainReadScript, parseKeychainStdout, readKeychainSync } from './keychain-read.mjs';
describe('buildKeychainReadScript (pure)', () => {
it('строит node-скрипт с async getPassword по абсолютному пути keytar', () => {
const s = buildKeychainReadScript('/abs/keytar', 'svc', 'acct');
expect(s).toContain('getPassword');
expect(s).toContain(JSON.stringify('/abs/keytar'));
expect(s).toContain(JSON.stringify('svc'));
expect(s).toContain(JSON.stringify('acct'));
expect(s).not.toContain('getPasswordSync');
});
it('JSON-экранирует аргументы (кавычки безопасны)', () => {
const s = buildKeychainReadScript('/k', 'a"b', 'c');
expect(s).toContain(JSON.stringify('a"b'));
});
});
describe('parseKeychainStdout (pure)', () => {
it('непустой stdout → значение', () => {
expect(parseKeychainStdout('secret123')).toBe('secret123');
});
it('пустой stdout → null', () => {
expect(parseKeychainStdout('')).toBe(null);
});
it('null/undefined → null', () => {
expect(parseKeychainStdout(null)).toBe(null);
expect(parseKeychainStdout(undefined)).toBe(null);
});
});
describe('readKeychainSync (sync-обёртка над async keytar)', () => {
const fakeRequire = { resolve: () => '/abs/keytar' };
it('exec вернул значение → оно же', () => {
const r = readKeychainSync('svc', 'acct', { requireImpl: fakeRequire, exec: () => 'the-key' });
expect(r).toBe('the-key');
});
it('exec вернул пусто → null', () => {
const r = readKeychainSync('svc', 'acct', { requireImpl: fakeRequire, exec: () => '' });
expect(r).toBe(null);
});
it('exec бросил → null (fail-closed, не кидает)', () => {
const r = readKeychainSync('svc', 'acct', { requireImpl: fakeRequire, exec: () => { throw new Error('spawn fail'); } });
expect(r).toBe(null);
});
it('require.resolve бросил (keytar не найден) → null', () => {
const req = { resolve: () => { throw new Error('MODULE_NOT_FOUND'); } };
const r = readKeychainSync('svc', 'acct', { requireImpl: req, exec: () => 'x' });
expect(r).toBe(null);
});
});