Files
brain/tools/url-whitelist-rules.mjs
T
2026-06-15 17:37:47 +03:00

43 lines
2.6 KiB
JavaScript

#!/usr/bin/env node
/** url-whitelist-rules — дом сборки project-URL-whitelist паттернов (config-seam).
* База неизменна; проектные домены приходят списком; пусто = fail-CLOSED. Чистый. */
export const DEFAULT_PROJECT_URL_WHITELIST = Object.freeze(['liderra.ru', 'github.com/liderra']);
export const BASE_NAVIGATE_HOSTS = Object.freeze(['localhost', '127.0.0.1']);
export const BASE_WEBFETCH_WHITELIST_PATTERNS = Object.freeze([
'^https?://docs\\.anthropic\\.com/',
'^https?://github\\.com/(?:anthropics|deck|deck-platform)/',
'^https?://(?:www\\.)?npmjs\\.com/package/',
'^https?://stackoverflow\\.com/questions/',
]);
export const WEBFETCH_SCHEME_BLOCK_PATTERNS = Object.freeze(['^data:', '^javascript:']);
export const BASE_COMMIT_MSG_FRAGS = Object.freeze([
'github\\.com/(?:deck|deck-platform)', 'api\\.anthropic\\.com', 'docs\\.anthropic\\.com',
]);
/** Экранировать regex-спецсимволы; `/` не трогаем (литеральный разделитель пути). */
export function escapeDomain(d) {
return String(d).replace(/[.+^${}()|[\]\\?*]/g, '\\$&');
}
function hostOnly(domains) {
return (domains || []).filter((d) => typeof d === 'string' && d && !d.includes('/'));
}
/** navigate: один host-альтернация-паттерн с границей (?:[:/?#]|$); возврат — одноэлементный массив. */
export function buildNavigateWhitelistPatterns(projectDomains) {
const hosts = [...BASE_NAVIGATE_HOSTS, ...hostOnly(projectDomains)];
return ['^https?://(?:' + hosts.map(escapeDomain).join('|') + ')(?:[:/?#]|$)'];
}
/** WebFetch: база + на каждый проектный домен `^https?://<d>/`. */
export function buildWebFetchWhitelistPatterns(projectDomains) {
const proj = (projectDomains || []).filter((d) => typeof d === 'string' && d);
return [...BASE_WEBFETCH_WHITELIST_PATTERNS, ...proj.map((d) => '^https?://' + escapeDomain(d) + '/')];
}
/** commit-message negative-lookahead: блок URL, чей домен НЕ из (база ∪ проект). */
export function buildCommitMessageUrlPattern(projectDomains) {
const proj = (projectDomains || []).filter((d) => typeof d === 'string' && d);
const frags = [...BASE_COMMIT_MSG_FRAGS, ...proj.map(escapeDomain)];
// Host-terminator (?:[:/?#]|$) after the allowlist alternation closes subdomain-suffix
// spoofs (liderra.ru.evil.com / github.com/liderra-evil); mirrors buildNavigateWhitelistPatterns.
return new RegExp('\\bhttps?:\\/\\/(?!(?:' + frags.join('|') + ')(?:[:/?#]|$))\\S+', 'i');
}