fix(content-floor): quote-aware redirect in matchBashHardBlacklist (port b0cd18d7 after --ours merge)
This commit is contained in:
@@ -152,6 +152,16 @@ export function stderrRedirectBlock(cmd) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// quote-aware redirect (порт прод-фикса b0cd18d7): `>` / `2>` внутри кавычек — литерал, не
|
||||
// редирект (напр. `git commit -m "a > b"`). Стрип применяется ТОЛЬКО к redirect-проверке;
|
||||
// остальной BASH_HARD_BLACKLIST идёт по СЫРОЙ строке (паттерны #4 node-inline-fs и пр. смотрят
|
||||
// ВНУТРЬ кавычек — стрипать для них нельзя). Массив сохранён целым (инварианты §12 не трогаем).
|
||||
export function stripQuotedSpans(s) {
|
||||
return String(s || '').replace(/"[^"]*"|'[^']*'/g, ' ');
|
||||
}
|
||||
const STDOUT_REDIRECT_REASON = 'stdout redirect (>/>>) запрещён';
|
||||
const STDOUT_REDIRECT_RE = /(?:^|[^0-9>&])>{1,2}(?![>&])/;
|
||||
|
||||
export const BASH_HARD_BLACKLIST = [
|
||||
// v3.9 keep
|
||||
{ re: /(^|\s|;|&&|\|\|)rm\b/, reason: 'rm запрещён' },
|
||||
@@ -160,7 +170,7 @@ export const BASH_HARD_BLACKLIST = [
|
||||
{ re: /(^|\s|;|&&|\|\|)chmod\b/, reason: 'chmod запрещён' },
|
||||
{ re: /(^|\s|;|&&|\|\|)chown\b/, reason: 'chown запрещён' },
|
||||
{ re: /(^|\s|;|&&|\|\|)chgrp\b/, reason: 'chgrp запрещён' },
|
||||
{ re: /(?:^|[^0-9>&])>{1,2}(?![>&])/, reason: 'stdout redirect (>/>>) запрещён' },
|
||||
{ re: STDOUT_REDIRECT_RE, reason: STDOUT_REDIRECT_REASON },
|
||||
{ re: /\b(?:node|nodejs)\s+(?:[^|;]*\s)?(?:-e|--eval|-p|--print)\b/, reason: 'node -e/--eval/-p запрещён' },
|
||||
{ re: /\bnode\s+(?:[^|;]*\s)?(?:-r|--require|--import|--experimental-loader)\b/, reason: 'node -r/--import запрещён' },
|
||||
{ re: /\bpython3?\s+-c\b/, reason: 'python -c запрещён' },
|
||||
@@ -185,9 +195,16 @@ export const BASH_HARD_BLACKLIST = [
|
||||
export function matchBashHardBlacklist(command) {
|
||||
const s = String(command || '');
|
||||
if (hasInjection(s)) return '#34: echo/printf prompt-injection запрещён';
|
||||
const stderr = stderrRedirectBlock(s);
|
||||
const stripped = stripQuotedSpans(s);
|
||||
const stderr = stderrRedirectBlock(stripped);
|
||||
if (stderr) return stderr;
|
||||
return matchAny(BASH_HARD_BLACKLIST, s);
|
||||
for (const { re, reason } of BASH_HARD_BLACKLIST) {
|
||||
if (!re.test(s)) continue;
|
||||
// redirect-паттерн судим по строке без кавычек: `>` внутри кавычек — не редирект
|
||||
if (reason === STDOUT_REDIRECT_REASON && !STDOUT_REDIRECT_RE.test(stripped)) continue;
|
||||
return reason;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// ── PowerShell hard-blacklist — единый дом (M7 PS single-source, зеркало BASH_HARD_BLACKLIST/P-1) ──
|
||||
|
||||
@@ -318,6 +318,22 @@ describe('matchBashHardBlacklist hosted in shell-content-rules (M7 P-1)', () =>
|
||||
});
|
||||
});
|
||||
|
||||
// quote-aware redirect (порт прод-фикса b0cd18d7 после --ours merge): `>` внутри кавычек —
|
||||
// не настоящий редирект (напр. commit message с `>`), не ложно-блокируется; реальный
|
||||
// редирект вне кавычек по-прежнему рубится. Стрип кавычек применяется ТОЛЬКО к redirect-
|
||||
// проверке (паттерны вроде #4 node-inline-fs смотрят внутрь кавычек и идут по сырой строке).
|
||||
describe('matchBashHardBlacklist — quote-aware redirect (порт b0cd18d7)', () => {
|
||||
it('> внутри кавычек НЕ редирект (commit message не ложно-блокируется)', () => {
|
||||
expect(matchBashHardBlacklist('git commit -m "fix: a > b"')).toBe(null);
|
||||
});
|
||||
it('реальный stdout redirect вне кавычек по-прежнему блокируется', () => {
|
||||
expect(matchBashHardBlacklist('echo secret > /tmp/x')).toBe('stdout redirect (>/>>) запрещён');
|
||||
});
|
||||
it('реальный stderr redirect к файлу по-прежнему блокируется', () => {
|
||||
expect(matchBashHardBlacklist('git status 2> /tmp/err')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
import { matchPsHardBlacklist, PS_HARD_BLACKLIST } from './shell-content-rules.mjs';
|
||||
|
||||
// M7 PS single-source (variant-analysis закрыл дрейф): PS_HARD_BLACKLIST переехал в единый дом
|
||||
|
||||
Reference in New Issue
Block a user