22b84fbb2e
Пакет 1 Машины 5 (роутер-наставник, пол). Единый источник разрушительности classify-destructive.mjs: floor (точный необратимый набор, hard-block) + suspicious (грубый набор для голосов судьи), инвариант floor => suspicious. - N1: голый migrate/migrate:rollback/migrate --force => suspicious, НЕ floor (деплой не ломается). - rewire a2CaseSelect (M4) и detectHighRisk (M3) на classifyDestructive.suspicious; оба локальных DESTRUCTIVE_RE удалены (Δ9-б — единственный источник). - Δ9(б) seed CI-инвариант m5-floor-invariants.test.mjs (positive-control, не вакуумный). - sharp-edges (Step 1.9): floor force-push выровнен с каноном shell-content — закрыт обход кавычками git push "--force" (длинные флаги без обязательного \s; -f/+ с \s). - parity к двум прежним regex сохранён (format/db:wipe/force-push-литерал). Регрессия tools-only: 2608 passed + 2 skip (+48). Residuals (chaining/reset-quote) переданы Пакету 2 (tokenizeBash посегментно). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
57 lines
3.7 KiB
JavaScript
57 lines
3.7 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* classify-destructive (§4, N1) — единый двухуровневый классификатор разрушительности
|
||
* по СУТИ команды. floor — точный необратимый набор (hard-block пола). suspicious —
|
||
* грубый набор для голосов судьи. Инвариант: floor ⇒ suspicious. Один источник правды
|
||
* (Δ9-б: другого regex разрушительных команд в tools/ быть не должно).
|
||
*
|
||
* Parity (Step 1.0 audit-context): suspicious — надмножество двух прежних DESTRUCTIVE_RE
|
||
* (judge-orchestrator:84 + router-engine:12). Источник 1 давал голый `migrate`+`drop table`,
|
||
* источник 2 — `format`+`force-push`-литерал. Оба покрыты ниже. Standalone `-rf`-литерал
|
||
* (over-broad FP источника 1, ловил `tar -rf`) намеренно НЕ перенесён — `rm -rf` покрыт
|
||
* словом `rm` + rmIsFloor.
|
||
*/
|
||
|
||
// F2: rm разрушителен (floor) только если есть И рекурсия (-r/-R/--recursive), И force
|
||
// (-f/--force) — слитно (-rf), раздельно, короткими ИЛИ длинными флагами. Длинно-флаговый
|
||
// `rm --recursive --force` так же необратим → floor (старый regex его терял).
|
||
function rmIsFloor(cmd) {
|
||
if (!/\brm\b/i.test(cmd)) return false;
|
||
const rec = /-[a-z]*r/i.test(cmd) || /--recursive\b/i.test(cmd);
|
||
const force = /-[a-z]*f/i.test(cmd) || /--force\b/i.test(cmd);
|
||
return rec && force;
|
||
}
|
||
|
||
// Точный необратимый набор — то, что пол блокирует НАГЛУХО (rm — через rmIsFloor).
|
||
const FLOOR_RE = [
|
||
// force-push/перепись. NB (sharp-edges Step 1.9): длинные флаги --force/--force-with-lease
|
||
// БЕЗ обязательного \s перед ними — иначе `git push "--force"` (кавычки) обходил floor,
|
||
// а shell кавычки снимает → реальный force-push. Выровнено с каноном shell-content-rules.
|
||
// Короткий -f и refspec + требуют \s (чтобы не ловить подстроки/-rf).
|
||
/\bgit\s+push\b[^\n]*(?:--force\b|--force-with-lease\b|\s-f\b|\s\+\S)/i,
|
||
/\breset\s+--hard\b/i,
|
||
/\bartisan\s+migrate:(?:fresh|reset|refresh)\b/i,
|
||
/\bartisan\s+db:wipe\b/i,
|
||
];
|
||
|
||
// Грубый набор для судьи (надмножество floor) — лишний голос не вредит.
|
||
// F1: +format (его содержал detectHighRisk М3 — иначе rewire потеряет триггер форматирования диска).
|
||
// +force-push-литерал: источник 2 (router-engine:12) ловил его как отдельную альтернативу —
|
||
// сохраняем строгую parity (синтетический токен, реальный `git push --force` покрыт `--force`).
|
||
const SUSPICIOUS_RE = [
|
||
/\b(?:rm|rmdir|drop|delete|truncate|migrate|format)\b/i,
|
||
/--force\b/i,
|
||
/\bforce-push\b/i,
|
||
/\breset\s+--hard\b/i,
|
||
/\bartisan\s+migrate:(?:fresh|reset|refresh)\b/i,
|
||
/\bartisan\s+db:wipe\b/i,
|
||
];
|
||
|
||
export function classifyDestructive(command) {
|
||
const cmd = String(command || '');
|
||
const floor = rmIsFloor(cmd) || FLOOR_RE.some((re) => re.test(cmd));
|
||
const suspicious = floor || SUSPICIOUS_RE.some((re) => re.test(cmd));
|
||
const reason = floor ? 'необратимая команда (floor)' : suspicious ? 'подозрительная команда (suspicious)' : 'не разрушительная';
|
||
return { floor, suspicious, reason };
|
||
}
|