/** * Shared path-rule semantics for profile validation, setup preflight, and * ingestion. Paths use repository-relative POSIX form at this boundary. * * @module src/core/path-rules */ const GLOB_META_PATTERN = /[*?[\]{}]/; const SECRET_FILE_PATTERNS = [ /^\.env(?:\.|$)/i, /^credentials?(?:\.|$)/i, /^id_(?:rsa|dsa|ecdsa|ed25519)(?:\.|$)/i, /^secrets?(?:\.|$)/i, /\.(?:key|pem|p12|pfx)$/i, ]; export function hasLikelySecretPath(path: string): boolean { const normalized = path.replaceAll("\\", "/"); const fileName = normalized.slice(normalized.lastIndexOf("/") + 1); return SECRET_FILE_PATTERNS.some((pattern) => pattern.test(fileName)); } export function hasGlobMeta(pattern: string): boolean { return GLOB_META_PATTERN.test(pattern); } /** * Bare values preserve historical component/prefix semantics. Values with * glob metacharacters match the complete normalized relative path. */ export function matchesCollectionExclusion( relPath: string, excludes: readonly string[] ): boolean { const normalizedPath = relPath.replaceAll("\\", "/"); const parts = normalizedPath.split("/"); for (const rawPattern of excludes) { const pattern = rawPattern.replaceAll("\\", "/"); if (hasGlobMeta(pattern)) { if (new Bun.Glob(pattern).match(normalizedPath)) return true; continue; } if ( parts.includes(pattern) || normalizedPath === pattern || normalizedPath.startsWith(`${pattern}/`) ) { return true; } } return false; } /** * Whether a known directory is the root of a fully excluded subtree. * A trailing `/**` excludes every descendant even though Bun.Glob does not * match the directory root itself. Other partial glob shapes must still be * traversed because they may leave eligible descendants. */ export function matchesCollectionSubtreeExclusion( relPath: string, excludes: readonly string[] ): boolean { const normalizedPath = relPath.replaceAll("\\", "/"); if (matchesCollectionExclusion(normalizedPath, excludes)) { return true; } for (const rawPattern of excludes) { const pattern = rawPattern.replaceAll("\\", "/"); if (pattern === "**") { return true; } if (!pattern.endsWith("/**")) { continue; } const subtreeRootPattern = pattern.slice(0, -3); if ( subtreeRootPattern.length > 0 && new Bun.Glob(subtreeRootPattern).match(normalizedPath) ) { return true; } } return false; }