-
xiye authored
发现(2026-09-27 第二轮独立复核,逐条可复现): - 测试服 /oauth2/jwks 公布的公钥就是仓库里那把历史上已随版本库公开的开发私钥 (实测:jar 内嵌公钥 modulus == 运行时 JWKS 公钥;外置挂载的那把根本没被使用); - 原因是容器跑 test profile,而 application-test.yml 只覆盖 issuer,基础配置仍是 classpath:keys/jwt/*.pem;compose 注入的 UAS_JWT_* 当时没有任何配置项消费; - 且 HEAD 打包仍把 private-key.pem 打进 BOOT-INF/classes/** —— 拿到 jar 或仓库历史 的人可以伪造任意用户令牌(UAS 签发、CMS/devprogress/push 都信任同一把公钥)。 修复: - 删除 src/main/resources/keys/jwt/*.pem;evelan-auth-boot/pom.xml 显式排除 keys/** 与 **/*.pem,fat jar 内不再有任何私钥(构建后实测 pem 条目 = 0); - 密钥改为三档外置注入:dev 用 $HOME/.evelan/keys/jwt(新增 scripts/gen-jwt-keys.ps1 生成,start-uas-dev.ps1 在缺密钥时自动生成);test/prod profile 用无默认值的 UAS_JWT_*(缺配启动失败,fail-fast);集成测试改用 src/test/resources/keys/test-jwt 下的新密钥对(与历史泄露那把无关); - JwtProperties 增加启动自检:key-id / 公钥位置 / 私钥位置若仍是未解析的占位符, 直接启动失败。实测坑:Spring 对无法解析的占位符是"原样保留",compose 漏传 UAS_JWT_KEY_ID 时不报错,而是把字面量当 kid 发到 /oauth2/jwks; - 回归守卫:JwtKeyMaterialPackagingTest(类路径或 main 资源里再出现 pem 即变红)+ JwtPropertiesValidationTest(回退成静默兜底即变红)。 验证: - 单测:evelan-auth-web 9/9(JwtConfigTest 5 + JwtPropertiesValidationTest 4)、 evelan-auth-boot 35/35(含 oauth2it 集成测试 14 例,已换用测试专用密钥); evelan-auth-web 全量 436 例里 3 例 Testcontainers 用例因本机无 Docker 报环境错, 与本改动无关(同机上一轮日志中该 3 例为通过); - 测试服部署(docker compose -p evelan-infra -f docker-compose.infra.yml -f docker-compose.agent.yml --env-file .env.test up -d --build --no-deps evelan-uas)后: 容器内 jar sha 与本地一致(c58b3fbb3f502d89)、jar 内 pem 条目 0、 JWKS kid=evelan-auth-rsa-key-20260912-030509 且 modulus == 外置挂载公钥、 四容器 healthy、启动 ERROR 0; - 重启三宿主刷新 JWKS 缓存(12h)后回归:UAS UI 冒烟 6/6、push WS 7/7、 push 管理端 6/6、越权探针 10/10、LinkDev 远端 E2E 59 通过/0 失败/11 跳过、 CMS 远端 E2E 11 通过/0 失败/3 跳过。
c591893a