397777089e
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
56 lines
2.7 KiB
JavaScript
56 lines
2.7 KiB
JavaScript
// 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);
|
||
});
|
||
});
|