fix(m5): F-6 — нижняя граница времени в floor-decide approvalOpen

approvalOpen считал свежим одобрение с будущим ts (now - ts < 0 <= window) — часовой
сдвиг/подлог открывал дверь владельца. Добавлена нижняя граница now - ts >= 0: свежесть =
ts в прошлом И в пределах окна.

Аудит Машины 5 (объектив корректность). TDD RED->GREEN. Регрессия tools-only 2789 + 2 skip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-06-07 16:18:44 +03:00
parent 7dd3a16531
commit 849723bc04
2 changed files with 12 additions and 1 deletions
+4 -1
View File
@@ -76,7 +76,10 @@ export function approvalOpen(command, approvedGitOps, now) {
const target = normCmd(command);
if (!target) return false;
return approvedGitOps.some(
(op) => op && normCmd(op.command) === target && typeof op.ts === 'number' && now - op.ts <= APPROVE_WINDOW_MS,
// F-6: свежесть = ts в прошлом И в пределах окна. Нижняя граница (now - ts >= 0) отсекает
// одобрение с будущим ts (часовой сдвиг/подлог), которое иначе открывало бы дверь.
(op) => op && normCmd(op.command) === target && typeof op.ts === 'number'
&& now - op.ts >= 0 && now - op.ts <= APPROVE_WINDOW_MS,
);
}
+8
View File
@@ -99,6 +99,14 @@ describe('floorDecide — дверь владельца Δ1 (read-only approval,
const r = floorDecide({ toolUse: bash('php artisan migrate:fresh'), approvedGitOps: [], now, normalizeImpl: id });
expect(r.block).toBe(true);
});
// F-6 (аудит 2026-06-07): floor-decide.mjs approvalOpen без нижней границы времени —
// одобрение с будущим ts (now - ts < 0 ≤ window) открывало дверь. Свежесть требует ts в прошлом.
it('одобрение с будущим ts (часовой сдвиг/подлог) → block (нижняя граница времени)', () => {
const cmd = 'php artisan migrate:fresh';
const approvedGitOps = [{ command: cmd, ts: now + 60 * 1000 }];
const r = floorDecide({ toolUse: bash(cmd), approvedGitOps, now, normalizeImpl: id });
expect(r.block).toBe(true);
});
});
describe('floorDecide — observe-only / прочее не блокируется', () => {