问题(2026-09-23 用户报障):
本地 `npm run dev` 启动即崩:
SequelizeAccessDeniedError: Access denied for user '<生产库账号>'@'localhost' (using password: YES)
→ [agent_worker] start error, exiting with code:1 → master 退出 → 7001 无监听。
根因:
config/config.default.js 顶部的 loadDeployEnv() 在**模块加载期**无条件把
deploy/.env.production 的全部 27 个键灌进 process.env,其中 DB_USER 指向生产库账号,
而本机 MySQL 并无该账号。且 deploy/ 不在任何 git 仓库内 ⇒ 该文件变更无 diff、无 review。
改动 A —— 新增 config/config.local.js(已由 .gitignore 排除,不入库):
仅在 serverEnv=local 时被 Egg 加载并「覆盖」config.default.js。
合并语义已取证:egg-core/lib/loader/mixin/config.js:61-71 `_preloadAppConfig()`
对 ['config.default', `config.${serverEnv}`] 逐项执行 extend(true, ...) ⇒ 深合并、后者覆盖前者。
本文件只覆盖 sequelize.username / password 两个字段,
dialect/database/host/port/timezone/define/dialectOptions/pool/logging 全部沿用 default。
生产 serverEnv=prod ⇒ Egg 只找 config.prod.js ⇒ 本文件不加载 ⇒ 零生产影响。
改动 B —— config/config.default.js:
① 执行时机:模块级 IIFE → module.exports(appInfo) 内部调用(此时 appInfo.env 已确定);
② 作用范围:非生产环境跳过 DB_ / REDIS_ / ALIYUN_ / SMS_ 前缀键
(连接类 / 凭据类 / 网关开关类),并在日志打印被跳过的键名(绝不打印值)。
生产判定 = appInfo.env==='prod' || NODE_ENV==='production'。生产必然成立的三重依据:
a) egg-scripts/lib/cmd/start.js:109 无条件 `env.NODE_ENV='production'`;
b) deploy/.env.production:17 NODE_ENV=production,且 start-backend.sh 以
`set -a; source "$ENV_FILE"` 注入 shell 后再 exec node;
c) start.js:126 注释:argv → EGG_SERVER_ENV → 兜底 egg 取 prod。
⇒ 生产**不跳过任何键**,行为逐键不变。外部显式注入的键仍优先(判定在 `!== undefined` 之后)。
改动 C —— .gitignore:排除 config/config.local.js(含本地口令)。
验证(全部实测):
· 双向对照探针:本地跳过 15 键、生产跳过 0 键且 DB_USER 正常注入;
合并后 pool.max=20 / define.charset=utf8mb4 / dialectOptions.charset 均保留 ⇒ 深合并成立。
· 纯裸启动(不带任何 DB 变量):egg started on :7001;health db:ok;admin-login code=0;
MySQL 侧 information_schema.processlist 独立取证 user=root / db=competition_db。
· 变异测试(config.local 口令改为错值):报 1045 且报错用户名仍是 root
⇒ 一次实验同时证明 A 被加载且优先生效、B 已挡住生产账号。
· 门禁回归:verify_scoring_e2e 17/0、verify_big_question --cleanup 52/0、
verify_exam_submit_integrity 46/0、check_no_proxy_guard 5 变异全检出。
不变量(本次未改,勿顺手改):
· deploy/.env.production 一字未动 —— README L57 明确它是**拷往服务器的权威源**,改它生产连不上库;
· sequelize 的 dialect/database/host/port/timezone/define/pool/logging 全部沿用 config.default.js;
· 环境变量优先级不变:外部显式注入 > .env.production 兜底 > 代码默认值。
56 lines
997 B
Plaintext
56 lines
997 B
Plaintext
# Dependencies
|
||
node_modules/
|
||
|
||
# Build output
|
||
dist/
|
||
dist-ssr/
|
||
|
||
# Logs
|
||
logs/
|
||
*.log
|
||
npm-debug.log*
|
||
yarn-debug.log*
|
||
yarn-error.log*
|
||
pnpm-debug.log*
|
||
|
||
# Runtime (egg)
|
||
run/
|
||
.wb_*/
|
||
.wb_check_state.js
|
||
.egg-config.json
|
||
|
||
# Env / secrets (defense-in-depth; real .env.production lives outside this repo)
|
||
.env*
|
||
!.env.example
|
||
|
||
# 本地开发配置(Egg 仅在 serverEnv=local 时加载,生产不加载)
|
||
# 含本地 DB 口令,故排除入库;如需团队共享请提交不含口令的 config.local.example.js
|
||
config/config.local.js
|
||
|
||
# Coverage / cache
|
||
coverage/
|
||
.cache/
|
||
|
||
# Agent / tooling state
|
||
.workbuddy/
|
||
|
||
# Editor
|
||
.vscode/*
|
||
!.vscode/extensions.json
|
||
.idea
|
||
.DS_Store
|
||
|
||
# Uploaded / runtime data under app/public (keep templates as source)
|
||
app/public/uploads/
|
||
app/public/answers/
|
||
app/public/works/
|
||
app/public/materials/
|
||
app/public/news/
|
||
app/public/carousel/
|
||
app/public/tmp/
|
||
app/public/exports/
|
||
|
||
# Tests (non-required; code runs without them) — 上传目的=运行必须,test 不入库
|
||
test/
|
||
test_dir/
|