DEPLOY PREFLIGHT
deploy-preflight.ts
Pre-deploy secret + sensitive-path scan. Catches credentials in env files, methodology paths reachable from CDN root, missing ignore patterns.
StarkWHAT THIS PATTERN TEACHES
How to scan the deploy artifact directory BEFORE upload. Forbidden filenames, forbidden content patterns, allowlist escape hatch, never auto-filter — a hit means the operator must investigate.
WHEN TO USE THIS
Every deploy. Wired into .claude/commands/deploy.md Step 2.5. Catches the 32-day credential leak class and the methodology-exposure class.
AT A GLANCE
// CI step before wrangler/vercel/firebase: // - run: npx tsx docs/patterns/deploy-preflight.ts ./dist // Exits non-zero on any hit. Never auto-filters.
FRAMEWORK IMPLEMENTATIONS
TypeScript
import { readdirSync, readFileSync } from 'node:fs';
import { extname, join, relative, sep } from 'node:path';
import { argv, env, exit } from 'node:process';
const FORBIDDEN_NAME_PATTERNS = [
{ id: 'env-file', test: (n: string) => /^\.env(\..+)?$/.test(n) && !/\.(example|template|sample)$/.test(n) },
{ id: 'pem-file', test: (n: string) => n.endsWith('.pem') },
{ id: 'key-file', test: (n: string) => n.endsWith('.key') },
{ id: 'ssh-private-key', test: (n: string) => /^id_(rsa|ed25519|ecdsa|dsa)(\..+)?$/.test(n) && !n.endsWith('.pub') },
{ id: 'methodology-claude', test: (_: string, rel: string) => rel.split(sep)[0] === '.claude' },
{ id: 'methodology-docs-methods', test: (_: string, rel: string) => rel.startsWith(`docs${sep}methods${sep}`) },
{ id: 'methodology-docs-patterns', test: (_: string, rel: string) => rel.startsWith(`docs${sep}patterns${sep}`) },
{ id: 'methodology-holocron', test: (n: string) => n === 'HOLOCRON.md' },
{ id: 'methodology-version', test: (n: string) => n === 'VERSION.md' },
{ id: 'build-logs', test: (_: string, rel: string) => rel.split(sep)[0] === 'logs' },
];
const FORBIDDEN_CONTENT_PATTERNS = [
{ id: 'aws-access-key', re: /\bAKIA[0-9A-Z]{16}\b/ },
{ id: 'github-pat', re: /\bgh[pousr]_[A-Za-z0-9]{36,}\b/ },