check-sensitive-data.js 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. #!/usr/bin/env node
  2. import { existsSync, readFileSync, readdirSync } from 'node:fs'
  3. import { dirname, join, resolve } from 'node:path'
  4. import { fileURLToPath } from 'node:url'
  5. const scriptDir = dirname(fileURLToPath(import.meta.url))
  6. const config = JSON.parse(readFileSync(resolve(scriptDir, 'community-db.config.json'), 'utf8'))
  7. const target = resolve(process.cwd(), process.argv[2] || resolve(scriptDir, config.exportDir))
  8. if (!existsSync(target)) {
  9. console.log(JSON.stringify({ target, checkedFiles: 0, findings: [] }, null, 2))
  10. process.exit(0)
  11. }
  12. const files = listSqlFiles(target)
  13. const sensitiveWords = config.sensitiveColumns.map(word => new RegExp(`\\b${escapeRegExp(word)}\\b`, 'i'))
  14. const sensitivePatterns = config.sensitivePatterns.map(pattern => new RegExp(pattern, 'i'))
  15. const findings = []
  16. for (const file of files) {
  17. const content = readFileSync(file, 'utf8')
  18. const lines = content.split('\n')
  19. lines.forEach((line, index) => {
  20. const matchedWord = sensitiveWords.find(pattern => pattern.test(line))
  21. const matchedPattern = sensitivePatterns.find(pattern => pattern.test(line))
  22. if (matchedWord || matchedPattern) {
  23. findings.push({ file, line: index + 1, text: line.trim().slice(0, 160) })
  24. }
  25. })
  26. }
  27. const summary = { target, checkedFiles: files.length, findings }
  28. console.log(JSON.stringify(summary, null, 2))
  29. if (findings.length > 0) {
  30. process.exit(1)
  31. }
  32. function listSqlFiles(root) {
  33. return readdirSync(root, { withFileTypes: true }).flatMap((entry) => {
  34. const absolutePath = join(root, entry.name)
  35. if (entry.isDirectory()) {
  36. return listSqlFiles(absolutePath)
  37. }
  38. return entry.name.endsWith('.sql') ? [absolutePath] : []
  39. })
  40. }
  41. function escapeRegExp(value) {
  42. return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
  43. }