Files
ccs/src/utils/sensitive-keys.ts
T
kaitranntt b621b8e47b feat(config): add unified YAML config with migration support
Implements unified config.yaml format consolidating:
- config.json (API profiles)
- profiles.json (account metadata)
- *.settings.json (env vars)

Features:
- Auto-migration from v1 JSON to v2 YAML with backup
- Secrets separation into secrets.yaml (chmod 600)
- Enhanced YAML output with section comments
- CLIProxy OAuth settings migration with env var support
- Feature flag for gradual rollout (CCS_UNIFIED_CONFIG=1)
- Rollback support via ccs migrate --rollback

New commands:
- ccs migrate - Run migration
- ccs migrate --dry-run - Preview changes
- ccs migrate --rollback <path> - Restore from backup
- ccs migrate --list-backups - List available backups

Closes #75
2025-12-10 17:42:40 -05:00

65 lines
2.1 KiB
TypeScript

/**
* Sensitive Key Detection Utilities
*
* Shared patterns for detecting secret/sensitive environment variable keys.
* Used by migration (secrets separation) and UI (masking).
*/
/**
* Patterns that match sensitive keys (API keys, tokens, passwords).
* More specific than substring matching to avoid false positives.
*/
export const SENSITIVE_KEY_PATTERNS = [
/^ANTHROPIC_AUTH_TOKEN$/, // Exact match for Anthropic auth token
/_API_KEY$/, // Keys ending with _API_KEY
/_AUTH_TOKEN$/, // Keys ending with _AUTH_TOKEN
/_SECRET$/, // Keys ending with _SECRET
/_SECRET_KEY$/, // Keys ending with _SECRET_KEY
/^API_KEY$/, // Exact match for API_KEY
/^AUTH_TOKEN$/, // Exact match for AUTH_TOKEN
/^SECRET$/, // Exact match for SECRET
/_PASSWORD$/, // Keys ending with _PASSWORD
/^PASSWORD$/, // Exact match for PASSWORD
/_CREDENTIAL$/, // Keys ending with _CREDENTIAL
/_PRIVATE_KEY$/, // Keys ending with _PRIVATE_KEY
];
/**
* Check if a key name contains a secret/sensitive value.
* Used during migration to separate secrets from config.
*
* @param key - Environment variable key name
* @returns true if the key likely contains sensitive data
*/
export function isSensitiveKey(key: string): boolean {
return SENSITIVE_KEY_PATTERNS.some((pattern) => pattern.test(key));
}
/**
* Mask a sensitive value for display.
* Shows first 4 and last 4 characters, replaces middle with asterisks.
*
* @param value - The sensitive value to mask
* @returns Masked value like "sk-a****xyz1"
*/
export function maskSensitiveValue(value: string): string {
if (!value || value.length <= 8) {
return '*'.repeat(value?.length || 0);
}
return value.slice(0, 4) + '*'.repeat(Math.max(0, value.length - 8)) + value.slice(-4);
}
/**
* Mask all sensitive keys in an env object.
*
* @param env - Environment variables object
* @returns New object with sensitive values masked
*/
export function maskSensitiveEnv(env: Record<string, string>): Record<string, string> {
const masked: Record<string, string> = {};
for (const [key, value] of Object.entries(env)) {
masked[key] = isSensitiveKey(key) ? maskSensitiveValue(value) : value;
}
return masked;
}