Files
portal/tools/receipt-key-config.test.mjs
T
Дмитрий 24ce7b39f1 feat(m5): запрет env-fallback ключа + сужение node-whitelist (Пакет 4, Блок 2 RISK, Δ4)
4.1 env-fallback УБРАН (receipt-key-config + judge-key-config):
- resolveReceiptKey/resolveJudgeKey читают ТОЛЬКО keychain; ROUTER_MENTOR_*_KEY env
  больше не читается (анти-казуальная утечка через env/логи; шов под HSM). `env` убран
  из сигнатуры (extra-проп игнорируется); KEY_ENV сохранён в _internals (domain-тест R-31).
- Критерий: env задан, keychain пуст → null.

4.2 node-whitelist сужен (enforce-router-gate, RISK):
- широкое `node <любой-файл>` правило удалено из SAFE_EXACT; новая ветвь classifyWhitelist
  через nodeScriptAllowed: allow только плоский tools/<file>.{mjs,cjs,js} + vitest-runner
  + node --version/-v; иначе default-deny. Инспекция ТОКЕНА пути (shell-quote сохраняет
  бэкслеши Windows-пути — инвариант запиннен тестом), нормализация \\ → /.
- verify (живой): после правки `node vitest.mjs` отработал по всем 147 тест-файлам —
  тул-чейн не сломан (canary). Гейт жив в сессии (powershell+router фаеры подтвердили).

Δ4 честно (§7): сужение — анти-казуальная мера, НЕ полный close. Остаток «контроллер
commit'ит разрешённый tools-скрипт и запускает» принят; file-watcher блокирует
session-edited до commit. Полная изоляция ключа — только HSM/YubiKey (v4.2).

TDD RED-GREEN per задача; tools-only регрессия 2677 passed + 2 skip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 12:19:02 +03:00

28 lines
1.4 KiB
JavaScript

// tools/receipt-key-config.test.mjs
import { describe, it, expect } from 'vitest';
import { resolveReceiptKey } from './receipt-key-config.mjs';
describe('resolveReceiptKey', () => {
it('returns keychain key when present', () => {
const r = resolveReceiptKey({ env: {}, keychainGet: () => 'k-from-chain' });
expect(r).toBe('k-from-chain');
});
// Пакет 4.1 (Δ4): env-fallback УБРАН — receipt-key-config больше НЕ читает
// ROUTER_MENTOR_RECEIPT_KEY (анти-казуальная утечка ключа через env/логи; шов под HSM).
it('env-fallback УБРАН: env задан, keychain пуст → null', () => {
const r = resolveReceiptKey({ env: { ROUTER_MENTOR_RECEIPT_KEY: 'k-env' }, keychainGet: () => null });
expect(r).toBe(null);
});
it('keychain держит ключ, env полностью игнорируется', () => {
const r = resolveReceiptKey({ env: { ROUTER_MENTOR_RECEIPT_KEY: 'k-env' }, keychainGet: () => 'k-chain' });
expect(r).toBe('k-chain');
});
it('returns null when neither present', () => {
expect(resolveReceiptKey({ env: {}, keychainGet: () => null })).toBe(null);
});
it('never throws when keychainGet throws → null', () => {
const r = resolveReceiptKey({ env: {}, keychainGet: () => { throw new Error('boom'); } });
expect(r).toBe(null);
});
});