Files
portal/tools/askuser-answer-parser-floor-escape.test.mjs
T
Дмитрий 7faef3c93f feat(escape-sign): домен FLOOR_ESCAPE + sign/verify helpers (M6 FIX-5 Task 1)
Defense-in-depth для escape-гранта: подпись пропуска floor_escape, чтобы форж
без секретного ключа отвергался (поверх content-floor). Task 1 — фундамент:

- receipt-sign.mjs: +домен RECEIPT_DOMAINS.FLOOR_ESCAPE='floor-escape' (R-31,
  изолирует подпись floor-escape от approval/frozen-plan).
- askuser-answer-parser.mjs: +signFloorEscapeRecord/verifyFloorEscapeRecord —
  зеркало signApprovalRecord/verifyApprovalRecord, домен FLOOR_ESCAPE. Чистые,
  без ключа → sig:null.

TDD: 5 новых тестов (доменная изоляция, подпись/верификация целой записи,
подделка/без sig/без ключа/чужой ключ/чужой домен → false). Регрессия по
затронутым файлам 82 GREEN, 0 регрессий.

Спека: docs/superpowers/specs/2026-06-10-floor-escape-signing-design.md
План:  docs/superpowers/plans/2026-06-10-floor-escape-signing.md (Task 1)
Прод-код инертен до провижининга ключа (Фаза 8).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 05:13:20 +03:00

31 lines
1.6 KiB
JavaScript

// tools/askuser-answer-parser-floor-escape.test.mjs
import { describe, it, expect } from 'vitest';
import { signFloorEscapeRecord, verifyFloorEscapeRecord } from './askuser-answer-parser.mjs';
import { signApprovalRecord } from './askuser-answer-parser.mjs';
const KEY = 'test-receipt-key';
const REC = { type: 'floor_escape', action: 'bash:git push --force', ts: 1000 };
describe('signFloorEscapeRecord / verifyFloorEscapeRecord', () => {
it('подписывает (+sig 64hex) и верифицирует целую запись', () => {
const signed = signFloorEscapeRecord(REC, KEY);
expect(signed.sig).toMatch(/^[0-9a-f]{64}$/);
expect(signed.action).toBe(REC.action);
expect(verifyFloorEscapeRecord(signed, KEY)).toBe(true);
});
it('false на подделке / без sig / без ключа / чужом ключе', () => {
const signed = signFloorEscapeRecord(REC, KEY);
expect(verifyFloorEscapeRecord({ ...signed, action: 'bash:rm -rf /' }, KEY)).toBe(false);
expect(verifyFloorEscapeRecord(REC, KEY)).toBe(false); // нет sig
expect(verifyFloorEscapeRecord(signed, null)).toBe(false);
expect(verifyFloorEscapeRecord(signed, 'other-key')).toBe(false);
});
it('доменная изоляция: approval-подпись НЕ проходит как floor-escape', () => {
const asApproval = signApprovalRecord(REC, KEY); // домен APPROVAL
expect(verifyFloorEscapeRecord(asApproval, KEY)).toBe(false);
});
it('без ключа → sig:null', () => {
expect(signFloorEscapeRecord(REC, null).sig).toBe(null);
});
});