UNPKG

@stackmemoryai/stackmemory

Version:

Lossless, project-scoped memory for AI coding tools. Durable context across sessions with 56 MCP tools, FTS5 search, conductor orchestrator, loop/watch monitoring, snapshot capture, pre-flight overlap checks, Claude/Codex/OpenCode wrappers, Linear sync, a

113 lines (112 loc) 4.15 kB
import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename); const SENSITIVE_PATTERNS = [ // API keys — common prefixes { pattern: /\bsk-[a-zA-Z0-9]{20,}/, label: "API key (sk-)" }, { pattern: /\bsk-ant-[a-zA-Z0-9-]{20,}/, label: "Anthropic key" }, { pattern: /\bAKIA[A-Z0-9]{12,}/, label: "AWS access key" }, { pattern: /\bghp_[a-zA-Z0-9]{30,}/, label: "GitHub PAT" }, { pattern: /\bgho_[a-zA-Z0-9]{30,}/, label: "GitHub OAuth" }, { pattern: /\bghs_[a-zA-Z0-9]{30,}/, label: "GitHub App" }, { pattern: /\bglpat-[a-zA-Z0-9_-]{20,}/, label: "GitLab PAT" }, { pattern: /\bnpm_[a-zA-Z0-9]{30,}/, label: "npm token" }, { pattern: /\bxox[bpsar]-[a-zA-Z0-9-]{10,}/, label: "Slack token" }, { pattern: /\blin_api_[a-zA-Z0-9]{20,}/, label: "Linear API key" }, { pattern: /\blin_oauth_[a-zA-Z0-9]{20,}/, label: "Linear OAuth" }, { pattern: /\bSG\.[a-zA-Z0-9_-]{20,}/, label: "SendGrid key" }, { pattern: /\brk_live_[a-zA-Z0-9]{20,}/, label: "Stripe key" }, { pattern: /\bsk_(?:live|test)_[a-zA-Z0-9]{20,}/, label: "Stripe secret" }, { pattern: /\bwhsec_[a-zA-Z0-9]{20,}/, label: "Webhook secret" }, // Private keys and certificates { pattern: /-----BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY-----/, label: "Private key (PEM)" }, { pattern: /-----BEGIN\s+CERTIFICATE-----/, label: "Certificate (PEM)" }, { pattern: /-----BEGIN\s+(?:EC\s+)?PRIVATE\s+KEY-----/, label: "EC private key" }, // JWT tokens (header.payload.signature format) { pattern: /\beyJ[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}/, label: "JWT token" }, { pattern: /\bBearer\s+eyJ[a-zA-Z0-9_-]{10,}/, label: "Bearer JWT" }, // Connection strings with credentials { pattern: /(?:mysql|postgres|postgresql|mongodb|redis):\/\/[^:]+:[^@]+@/, label: "DB connection string" }, // Generic high-entropy secrets (base64 blocks in config-like context) { pattern: /(?:password|secret|token|api[_-]?key|auth[_-]?token)\s*[:=]\s*["'][^"']{8,}["']/i, label: "Credential assignment" }, { pattern: /(?:PASSWORD|SECRET|TOKEN|API_KEY|AUTH_TOKEN)\s*=\s*\S{8,}/, label: "Env var credential" } ]; const APPROVED_PROVIDERS = /* @__PURE__ */ new Set(["anthropic", "anthropic-batch"]); function checkString(text) { const matches = []; for (const { pattern, label } of SENSITIVE_PATTERNS) { if (pattern.test(text)) { matches.push(label); } } return { sensitive: matches.length > 0, matches }; } function detectSensitiveContent(task, context) { const allMatches = []; const taskResult = checkString(task); allMatches.push(...taskResult.matches); if (context) { for (const value of Object.values(context)) { if (typeof value === "string") { const r = checkString(value); allMatches.push(...r.matches); } else if (Array.isArray(value)) { for (const item of value) { if (typeof item === "string") { const r = checkString(item); allMatches.push(...r.matches); } } } else if (value && typeof value === "object") { for (const nested of Object.values(value)) { if (typeof nested === "string") { const r = checkString(nested); allMatches.push(...r.matches); } } } } } const unique = [...new Set(allMatches)]; return { sensitive: unique.length > 0, matches: unique }; } function isApprovedProvider(provider) { return APPROVED_PROVIDERS.has(provider); } function shouldBlockProvider(provider, task, context) { if (isApprovedProvider(provider)) { return { blocked: false }; } const check = detectSensitiveContent(task, context); if (!check.sensitive) { return { blocked: false }; } return { blocked: true, reason: `Sensitive content detected (${check.matches.join(", ")}). Blocked routing to ${provider}; using approved provider instead.` }; } export { detectSensitiveContent, isApprovedProvider, shouldBlockProvider };