# SEC-Z-01 最小安全清理差异清单(Z-01) | 项 | 内容 | |---|---| | 依据 | AM-S1-GOV-020 §4.2「第一优先级:完成 SEC-Z-01 最小安全清理」 | | 执行人 | 周工 | | 执行时间 | 2026-11-13 11:20–11:45 | | 范围 | **15 处明文** + **1 处启动守卫**(为满足"缺参明确失败") | | 是否升版 | **否**,V1.9 内做最小安全清理,未升 V1.10,无无关重构 | | 口令复述 | **本件不含原口令任何字符**,差异表中一律写作「(原值已脱敏)」 | --- ## 一、清理前后总览 | 项 | 清理前 | 清理后 | |---|---|---| | 含明文口令的文件 | **15 个** | **0** | | 明文出现次数 | 15 处(每文件 1 处) | 0 | | 配置层(yml) | 带非空默认值 | 无默认值,缺参启动中止 | | 脚本层(py) | 带非空默认值 | 无默认值,缺参直接退出 | | 文档层(md) | 写出明文示例 | 改为占位符 | | 历史包 | 6 个 zip 内含旧凭据 | 已移入受控归档目录,标注禁止外发 | --- ## 二、逐处差异(15 处) ### A 类:后端配置(1 处) | # | 文件 | 位置 | 改前 | 改后 | |---|---|---|---|---| | 1 | `01_后端源码/src/main/resources/application.yml` | `spring.datasource.password` | `${DB_PASS:<原值已脱敏>}` | `${DB_PASS}` | 同时把上方两行自相矛盾的注释("包里不再有第二处明文"——实际上还有 14 处)改成实际口径。 ### B 类:Python 证据脚本(12 处) 12 个脚本写法相同,改法相同。以一处示意: | 改前 | 改后 | |---|---| | `DB_PASS = os.environ.get("AOMIN_DB_PASS", "<原值已脱敏>")` | `DB_PASS = os.environ.get("AOMIN_DB_PASS")`
加 4 行守卫:为空则 `raise SystemExit(...)`,打印设置方法 | | # | 文件 | |---|---| | 2 | `06_统一闭环题自测证据/alarm_retry_test.py` | | 3 | `06_统一闭环题自测证据/closed_loop_test.py` | | 4 | `06_统一闭环题自测证据/cmd_chain_test.py` | | 5 | `06_统一闭环题自测证据/run_evidence.py` | | 6 | `06_统一闭环题自测证据/scope_test.py` | | 7 | `06_统一闭环题自测证据/v15_fix_test.py` | | 8 | `06_统一闭环题自测证据/v16_fix_test.py` | | 9 | `06_统一闭环题自测证据/v17_merge_test.py` | | 10 | `06_统一闭环题自测证据/v18_fix_test.py` | | 11 | `06_统一闭环题自测证据/v19_gov008_test.py` | | 12 | `06_统一闭环题自测证据/v20_node_test.py` | | 13 | `06_统一闭环题自测证据/stamp_evidence.py`(特殊:原为内联调用 `"-p" + os.environ.get(...)`,改为在模块顶部定义 `DB_PASS` 并加同样的守卫,调用处改引用常量) | ### C 类:说明文档(2 处) | # | 文件 | 位置 | 改前 | 改后 | |---|---|---|---|---| | 14 | `05_启动构建与测试说明/启动构建与测试说明.md` | §5 启动 | `export DB_PASS=<原值已脱敏>` | `export DB_PASS=<口令>`,注释改为"必需:配置里已无默认值,未设置时启动直接失败" | | 15 | `09_代码与版本/README.md` | 环境变量表 | 默认值列写出明文 | `root` / **必需,无默认值**;说明未设置时脚本直接退出 | --- ## 三、新增 1 处启动守卫(为什么必须有) **这是本次唯一的代码改动,不是重构,是为满足 §4.2「缺少必需口令时明确失败」。** ### 问题:只删默认值,并没有"明确失败" 先按最省事的方式改(`password: ${DB_PASS}` 不设默认值)实测了一次,结果不是报"缺少 DB_PASS",而是: ``` Access denied for user 'root'@'localhost' (using password: YES) ``` 原因:Spring Boot 的占位符解析在“解析不到”时是**忽略**而不是报错,于是拿空口令去连库。表现出来像"口令错了",实际是"根本没配"——这正是不允许的静默回退。 ### 处理:在 `main` 里提前拦住 | 文件 | 改动 | |---|---| | `src/main/java/cn/aomin/gateway/GatewayApplication.java` | `main()` 首行调用 `requireEnv("DB_PASS", "数据库口令")`;新增私有方法 `requireEnv`,为空则打印提示并 `System.exit(1)` | 改后实测输出(退出码 **1**): ``` [启动中止] 缺少必需的环境变量 DB_PASS(数据库口令)。 SEC-Z-01:程序不再内置任何默认口令,也不会回退到包内明文。 设置方法:Windows set DB_PASS=<口令> Linux/macOS export DB_PASS=<口令> ``` **只校验"有没有",不校验"对不对",也不打印任何取值。** --- ## 四、构建产物与缓存清理 | 对象 | 处理 | |---|---| | `target/classes/application.yml` | 旧副本含明文;`mvn clean package` 后已由新文件覆盖,实测 jar 内配置 **0 命中** | | `__pycache__` / `*.pyc` | 已删除(编译产物里会残留字符串常量) | | 应用日志 `G:/aomin-dev/logs` | 实测 **0 命中**,保留(不含凭据,且是运行证据) | | `target/` 其余内容 | 43 MB 构建产物,已随 `clean` 重建;**不入代码仓库**(见 `03` 的 `.gitignore`) | --- ## 五、历史包处置 `_历史包/` 下 6 个 zip 都含旧凭据(解开后逐成员扫描,命中 13~15 处)。直接按字节搜 zip 查不出来,因为内容被 deflate 压缩过。 | 处理 | 说明 | |---|---| | 目录改名 | `_历史包/` → **`_历史包_含旧凭据_禁止外发/`** | | 登记 | 同目录 `_清单_含旧凭据.md` 记录每个 zip 的字节数、SHA-256、含旧口令文件数 | | 约束 | **禁止外发、禁止入代码库、禁止上传公共 AI**;仅作内部留档 | > 这是"轮换结论"要覆盖的一部分:口令一旦进过包,就不能假设它只存在于一个地方。 --- *后续:清理后哈希、构建说明、155 条证据边界见同目录 `03_…` 与 `04_…`。*