Commit 5adbe9db33f4c91547c6a84c1eb02f8425b885e1

Authored by zichun
1 parent c3a7467c

templates(test-db): drop ALLOW_REMOTE/ALLOW_PROD_NAME hatches and slim env-local warnings

skills/plan/skeleton-gen/templates/env-local-template
1 -# .env.local — 本地开å‘凭æ®ï¼ˆå…¥ .gitignoreï¼Œä¸æäº¤ï¼‰  
2 -#  
3 -# 规则:  
4 -# 1. å€¼å« `$`ã€å引å·ã€ç©ºæ ¼ã€`!` ç­‰ shell 特殊字符时,必须用å•引å·åŒ…裹:  
5 -# DB_PASSWORD='p@ss$w0rd!'  
6 -# å¦åˆ™ `set -a; . .env.local; set +a` 会åšå˜é‡å±•开导致密ç é”™ä¹±ã€‚  
7 -# 2. DB_HOST å»ºè®®ä¿æŒ localhost / 127.0.0.1ï¼›éžæœ¬åœ° host 默认会被 scripts/setup-test-db.mjs 防护拒ç»ã€‚  
8 -# 若必须用远程测试库,把 host 列入下方 TEST_DB_ALLOWED_HOSTS。  
9 -# 3. DB_SCHEMA 建议命åå« test / _dev / _local / _ci,é¿å…与生产库åŒå。 1 +# Local dev credentials — gitignored.
  2 +# Quote values containing $/space/!/backtick with single quotes: DB_PASSWORD='p@ss$w0rd!'
10 3
11 DB_HOST=ã€äººå·¥å¡«å†™ï¼šMySQL host,推è localhost】 4 DB_HOST=ã€äººå·¥å¡«å†™ï¼šMySQL host,推è localhost】
12 DB_PORT=ã€äººå·¥å¡«å†™ï¼šMySQL port,默认 3306】 5 DB_PORT=ã€äººå·¥å¡«å†™ï¼šMySQL port,默认 3306】
@@ -15,11 +8,5 @@ DB_PASSWORD=ã€äººå·¥å¡«å†™ï¼šå¯¹åº”密ç ï¼Œå«ç‰¹æ®Šå­—符时用å•引å·åŒ…è£ @@ -15,11 +8,5 @@ DB_PASSWORD=ã€äººå·¥å¡«å†™ï¼šå¯¹åº”密ç ï¼Œå«ç‰¹æ®Šå­—符时用å•引å·åŒ…è£
15 DB_SCHEMA=ã€äººå·¥å¡«å†™ï¼šschema å,推èå« test/_dev/_local,例如 erp_dev】 8 DB_SCHEMA=ã€äººå·¥å¡«å†™ï¼šschema å,推èå« test/_dev/_local,例如 erp_dev】
16 JWT_SECRET=ã€äººå·¥å¡«å†™ï¼šJWT ç­¾å密钥,256+ bit éšæœºä¸²ã€‘ 9 JWT_SECRET=ã€äººå·¥å¡«å†™ï¼šJWT ç­¾å密钥,256+ bit éšæœºä¸²ã€‘
17 10
18 -# å¯é€‰ï¼šé¢å¤–å…许 DROP CREATE 的远程 host(空格或逗å·åˆ†éš”)。仅当 DB_HOST 指å‘公叿µ‹è¯• MySQL ç­‰  
19 -# éžæœ¬åœ°æœåŠ¡å™¨æ—¶å¡«å†™ï¼›ç•™ç©ºè¡¨ç¤ºåªå…许 localhost / 127.0.0.1 / ::1。  
20 -# 示例:TEST_DB_ALLOWED_HOSTS="118.178.19.35 test-mysql.internal"  
21 -#  
22 -# âš ï¸ åˆ—å…¥åŽè¯¥ host æ¯æ¬¡ test.mjs 都会被 DROP CREATE(无二次确认)。  
23 -# ä»…ç”¨äºŽä½ å®Œå…¨å¯æŽ§çš„æµ‹è¯•åº“ï¼›ç”Ÿäº§/共享库/多人共享的 staging 库**åƒä¸‡åˆ«åˆ—**。  
24 -# (防护 2 还会检查 schema åé¡»å« test/_dev/_local/_ci,独立兜底。) 11 +# å¯é€‰ï¼šé¢å¤–å…许 DROP CREATE 的远程 host(空格或逗å·åˆ†éš”)。
25 TEST_DB_ALLOWED_HOSTS= 12 TEST_DB_ALLOWED_HOSTS=
skills/plan/skeleton-gen/templates/scripts-setup-test-db-template.mjs
1 #!/usr/bin/env node 1 #!/usr/bin/env node
2 -// scripts/setup-test-db.mjs — 数据库重置脚本:drop + create 空库。  
3 -// schema apply 由 Flyway 在 Spring Boot 启动时自动处理(见 docs/04 技术栈 + sql/migrations/V*.sql)。  
4 -// seed 数据由测试框架负责(Spring @Sql / Flyway R__seed.sql / data.sql)。  
5 -//  
6 -// 使用场景:  
7 -// - scripts/test.mjs 开头:清空库,让 Spring 启动时 Flyway 从 V1 开始重放所有 migration  
8 -// - scripts/test.mjs 结尾:清空库,避免测试遗留污染下次运行  
9 -// - 手动调试时:reset 到零状态  
10 -//  
11 -// 跨平台:用纯 JS 解析 .env.local(dotenv 风格,逐行 KEY=VALUE),**绝不** shell-source,  
12 -// 因此 mac / Windows 原生 node 均可运行,且消除 shell 注入 / 变量展开隐患。  
13 -// DROP/CREATE 通过 `mysql` 客户端以 argv 数组方式执行(不经 shell),密码不进命令行解析层。  
14 -//  
15 -// 防护:本脚本只允许在本地 host + 测试库名上执行;非预期目标会被拒绝,  
16 -// 避免 .env.local 误指向 staging/prod 时触发不可逆 DROP。 2 +// scripts/setup-test-db.mjs — DROP + CREATE 空测试库。
  3 +// 由 coding.mjs 的 test-gate 调用;schema 由 Flyway 在 Spring Boot 启动时重放。
  4 +// 只允许本地 host(或 TEST_DB_ALLOWED_HOSTS 白名单内的 host)+ 测试库名(含 test/_dev/_local/_ci)。
17 5
18 import { spawnSync } from 'node:child_process' 6 import { spawnSync } from 'node:child_process'
19 import { existsSync, readFileSync } from 'node:fs' 7 import { existsSync, readFileSync } from 'node:fs'
@@ -23,8 +11,6 @@ import { fileURLToPath } from 'node:url' @@ -23,8 +11,6 @@ import { fileURLToPath } from 'node:url'
23 const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url)) 11 const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url))
24 const ENV_FILE = join(SCRIPT_DIR, '..', '.env.local') 12 const ENV_FILE = join(SCRIPT_DIR, '..', '.env.local')
25 13
26 -// dotenv 风格解析:逐行 KEY=VALUE,跳过空行与 # 注释,去除两侧空白,  
27 -// 可选地剥离一层成对单/双引号。**不做**变量展开,特殊字符按字面保留。  
28 function parseEnv(text) { 14 function parseEnv(text) {
29 const env = {} 15 const env = {}
30 for (const rawLine of text.split(/\r?\n/)) { 16 for (const rawLine of text.split(/\r?\n/)) {
@@ -59,9 +45,6 @@ const DB_PORT = env.DB_PORT ?? '3306' @@ -59,9 +45,6 @@ const DB_PORT = env.DB_PORT ?? '3306'
59 const DB_USER = env.DB_USER ?? '' 45 const DB_USER = env.DB_USER ?? ''
60 const DB_PASSWORD = env.DB_PASSWORD ?? '' 46 const DB_PASSWORD = env.DB_PASSWORD ?? ''
61 const DB_SCHEMA = env.DB_SCHEMA ?? '' 47 const DB_SCHEMA = env.DB_SCHEMA ?? ''
62 -const TEST_DB_ALLOW_REMOTE = env.TEST_DB_ALLOW_REMOTE ?? process.env.TEST_DB_ALLOW_REMOTE ?? '0'  
63 -const TEST_DB_ALLOW_PROD_NAME =  
64 - env.TEST_DB_ALLOW_PROD_NAME ?? process.env.TEST_DB_ALLOW_PROD_NAME ?? '0'  
65 48
66 // 防护 1:默认只允许本地 host(localhost / 127.0.0.1 / ::1)。 49 // 防护 1:默认只允许本地 host(localhost / 127.0.0.1 / ::1)。
67 // 额外允许的远程 host 在 .env.local 的 TEST_DB_ALLOWED_HOSTS 中(空格或逗号分隔)。 50 // 额外允许的远程 host 在 .env.local 的 TEST_DB_ALLOWED_HOSTS 中(空格或逗号分隔)。
@@ -73,22 +56,19 @@ if (!allowedHosts.includes(DB_HOST)) { @@ -73,22 +56,19 @@ if (!allowedHosts.includes(DB_HOST)) {
73 console.error(`[setup-test-db] 拒绝在非白名单 host (${DB_HOST}) 上执行 DROP DATABASE`) 56 console.error(`[setup-test-db] 拒绝在非白名单 host (${DB_HOST}) 上执行 DROP DATABASE`)
74 console.error(` 当前白名单:${allowedHosts.join(' ')}`) 57 console.error(` 当前白名单:${allowedHosts.join(' ')}`)
75 console.error(' 加入 host:在 .env.local 追加 TEST_DB_ALLOWED_HOSTS="<host1> <host2>"') 58 console.error(' 加入 host:在 .env.local 追加 TEST_DB_ALLOWED_HOSTS="<host1> <host2>"')
76 - console.error(' 一次性绕过:在 .env.local 设 TEST_DB_ALLOW_REMOTE=1')  
77 - if (TEST_DB_ALLOW_REMOTE !== '1') process.exit(1) 59 + process.exit(1)
78 } 60 }
79 61
80 -// 防护 2:schema 名需像测试/开发库(含 test / _dev / _local / _ci),否则要求显式确认 62 +// 防护 2:schema 名需像测试/开发库(含 test / _dev / _local / _ci),否则拒绝
81 const schemaLooksLikeTest = 63 const schemaLooksLikeTest =
82 /test/.test(DB_SCHEMA) || /_dev$/.test(DB_SCHEMA) || /_local$/.test(DB_SCHEMA) || /_ci$/.test(DB_SCHEMA) 64 /test/.test(DB_SCHEMA) || /_dev$/.test(DB_SCHEMA) || /_local$/.test(DB_SCHEMA) || /_ci$/.test(DB_SCHEMA)
83 if (!schemaLooksLikeTest) { 65 if (!schemaLooksLikeTest) {
84 console.error( 66 console.error(
85 `[setup-test-db] schema '${DB_SCHEMA}' 不像测试库(期望命名含 test / _dev / _local / _ci)` 67 `[setup-test-db] schema '${DB_SCHEMA}' 不像测试库(期望命名含 test / _dev / _local / _ci)`
86 ) 68 )
87 - console.error(' 如确为期望行为,请显式声明:在 .env.local 设 TEST_DB_ALLOW_PROD_NAME=1')  
88 - if (TEST_DB_ALLOW_PROD_NAME !== '1') process.exit(1) 69 + process.exit(1)
89 } 70 }
90 71
91 -// 防护 3:显式 banner,让人看见自己在 drop 什么;远程 host 额外提示白名单内容。  
92 console.log(`[setup-test-db] 即将 DROP + CREATE \`${DB_SCHEMA}\` on ${DB_HOST}:${DB_PORT}`) 72 console.log(`[setup-test-db] 即将 DROP + CREATE \`${DB_SCHEMA}\` on ${DB_HOST}:${DB_PORT}`)
93 if (!['localhost', '127.0.0.1', '::1'].includes(DB_HOST)) { 73 if (!['localhost', '127.0.0.1', '::1'].includes(DB_HOST)) {
94 console.log( 74 console.log(
@@ -104,7 +84,6 @@ const sql = @@ -104,7 +84,6 @@ const sql =
104 `DROP DATABASE IF EXISTS \`${DB_SCHEMA}\`; ` + 84 `DROP DATABASE IF EXISTS \`${DB_SCHEMA}\`; ` +
105 `CREATE DATABASE \`${DB_SCHEMA}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;` 85 `CREATE DATABASE \`${DB_SCHEMA}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;`
106 86
107 -// 以 argv 数组调用 mysql(不经 shell):密码不进 shell 解析,跨平台一致。  
108 const mysqlArgs = [ 87 const mysqlArgs = [
109 `-h${DB_HOST}`, 88 `-h${DB_HOST}`,
110 `-P${DB_PORT}`, 89 `-P${DB_PORT}`,