# S03 生产配置、简历隐私与 Actuator 隔离实施指令 项目根目录:`C:\Users\15642\Desktop\zhilai` 候选基线:S02 已完成独立代码复验、真实 MySQL/Docker 黑盒、精确提交并推送;功能分支提交为 `f399060edb2ff778322a4f021c93213f39a6f6bf`。 本轮必须先完整阅读 `docs/s03-production-security-and-resume-privacy-design.md`。该文档是 S03 权威口径;发生冲突时停止并报告,不得自行扩大语义。 ## 一、开始前核查 执行: ```powershell cd C:\Users\15642\Desktop\zhilai git branch --show-current git status --short git diff --cached --name-only git log -5 --oneline git diff --check ``` 要求: - 从 S02 已提交基线创建独立分支 `feat/s03-production-privacy`; - 切分支前确认暂存区和已跟踪工作区为空; - 保留全部历史未跟踪脚本、日志、JSON、SQL、xlsx、`.env` 和验收目录; - 不执行 `git reset/restore/checkout -- /clean`;创建新分支仅允许 `git switch -c feat/s03-production-privacy`; - 不执行 `git add -A`、commit、push; - 实施阶段不操作 Docker,不执行真实 MySQL 黑盒; - 搜索并完整阅读适用的 `AGENTS.md`,不存在则记录。 如已有修改与 S03 目标文件重叠,停止并报告。 ## 二、必须完整阅读 迁移与模型: - `V1__base_schema.sql` - `V1_1__seed_data.sql` - `V2__business_schema.sql` - `V27__student_privacy_settings.sql` - `V42__auth_token_sessions.sql` - `User`、`UserRepository`、`Company`、`CompanyRepository` - `Application`、`ApplicationRepository`、`Job`、`StudentProfile` 隐私与简历: - `PrivacySettingsService`、`StudentPrivacySettings`、`ResumeVisibility` - `ApplicationController`、`ApplicationService`、`CandidateDetailView` - `ProfileController`、`ProfileService` - `ResumeStorageService`、`LocalResumeStorageService` - `ResumeFilenameSanitizer`、`ResumeFileValidator` - 全部 `profile`、`resume`、`privacy`、`application` 测试 认证与运维: - `SecurityConfig`、`CurrentUserAccessor` - `AuthService`、`AuthSessionService`、`JwtAuthenticationFilter` - `application.yml` 及所有 profile 配置 - `ErrorCode`、`GlobalExceptionHandler` - `pom.xml` 与 Actuator 测试 文档: - S03 权威设计文档 - `privacy-settings-api.md` - `resume-api.md` - `frontend-integration.md` - `backend-development-roadmap.md` - `phase1-scope-and-acceptance.md` - `openapi-rc.json` - `verify_openapi.py` 先执行搜索并记录所有企业侧简历暴露点: ```powershell rg -n -i "resumeUrl|resume_url|download.*resume|resume.*download|ResumeStorageService\.read|canCompanyViewResume|studentUserId" mydreamjob-server/src/main/java ``` ## 三、S03-A:禁用历史种子账号 新增且仅新增 `V43__disable_legacy_seed_accounts.sql`。 要求: 1. 不修改 V1–V42。 2. 不按固定 ID 匹配。 3. 每条 UPDATE 必须同时匹配 V1_1 中的原手机号、原邮箱、原 bcrypt 哈希、原角色、`is_active=1`。 4. ADMIN、STUDENT、COMPANY 三条分别处理。 5. 仅更新 `is_active=0`,不删除 users/user_roles,不修改历史业务表。 6. 改过手机号、邮箱、哈希或角色的同源账号不得被禁用。 7. 重复执行效果稳定。 新增迁移集成测试,至少覆盖:完整指纹命中、每个单字段偏差不命中、非固定 ID 也能命中、重复执行、关联数据保留、V1–V42 校验和不变。 ## 四、S03-A:一次性管理员初始化 新增强类型配置和条件装配,例如: - `AdminBootstrapProperties` - `AdminBootstrapRunner` - 必要的内部 Service 严格按设计文档执行:默认关闭;只有严格 `true` 才装配;手机号来自环境变量;无默认手机号;不打印手机号;不提供公网接口。 核心行为: - 已有活动 ADMIN:无副作用跳过; - 无活动 ADMIN + 手机号不存在:创建活动且已验证 ADMIN,`users.role` 与 `user_roles` 一致; - 手机号已属于任何用户或角色状态异常:启动失败,禁止提权、复活或覆盖; - 重复启动幂等; - 多实例冲突安全失败; - 不签发 Token、不发送短信、不写默认密码。 错误信息必须固定且不包含手机号、用户对象、SQL 或环境变量值。日志只能使用固定事件文本。 必须先写失败测试,覆盖:disabled、missing phone、invalid phone、existing active admin、new admin、duplicate run、existing student/company/inactive user、users/user_roles 一致性、日志脱敏、并发冲突。 ## 五、S03-B:企业简历下载与隐私 新增唯一公网接口: `GET /company/candidates/{applicationId}/resume` 推荐新增: - `CompanyResumeAccessPolicy` - `CompanyResumeService` - 必要的文件响应 record/DTO 不得将文件访问逻辑塞入现有候选人 DTO,不得返回 `resumeUrl`。 授权必须在 Service/Policy 中完成,不可信任 Controller 传入的归属信息。按以下顺序:当前 COMPANY 用户 → 当前 Company → Application+Job → Job.companyId → Student → privacy setting → profile/file。 必须修复现有 `canCompanyViewResume` 的公司归属缺失:`APPLIED_COMPANIES` 不能只校验学生和状态;必须证明 application 对应 Job 属于当前 company。允许替换该方法或让它委托给新 Policy,但不得保留一个可被误用的宽松生产方法。 语义严格使用设计文档决策表: - 默认/null 与 PRIVATE:全部企业 403; - APPLIED_COMPANIES:仅本企业有效投递,WITHDRAWN/REJECTED 拒绝; - VERIFIED_COMPANIES:企业 verified=true 且拥有 application 的岗位,状态不额外限制; - 跨企业、未认证、错误角色均拒绝; - 人才发现本轮不能借 candidateKey 下载简历。 响应要求: - 使用安全 `Content-Disposition`; - content type 只能来自已验证的白名单; - 不返回内部路径、studentUserId、手机号、邮箱; - 拒绝路径不得调用 storage `read`; - 文件不存在安全失败,不回显路径; - 不缓存私有文件,至少返回 `Cache-Control: no-store`; - 不把简历正文写入日志、审计或异常。 权限测试必须使用真实 SecurityFilterChain/MockMvc,并覆盖 COMPANY、其他企业、未认证企业、STUDENT、ADMIN、匿名。集成测试必须使用真实 H2 Repository 和真实本地临时存储,不得 Mock 掉被验证的授权链。 对所有状态 `SUBMITTED/VIEWED/INTERVIEW/HIRED/REJECTED/WITHDRAWN` 分别验证三种 visibility。验证企业候选人列表/详情仍不含 `resumeUrl`。 ## 六、S03-C:Actuator 隔离 按设计新增: ```yaml management: server: port: ${MANAGEMENT_SERVER_PORT:8081} address: ${MANAGEMENT_SERVER_ADDRESS:127.0.0.1} ``` 并将 health details/components 设为 `never`。不要使用业务 JWT 角色代替运维网络隔离,不新增运维公网接口。 必须验证: - 业务端口无法访问 metrics/prometheus; - 管理端口只绑定配置地址; - health 仅返回最小状态,不含 DB/Redis/RabbitMQ/磁盘/连接池详情; - metrics/prometheus 只在管理端口存在; - STUDENT/COMPANY/ADMIN Token 不会使业务端口指标可见; - dev/test/integration-test 不发生随机端口冲突。 若 Spring Boot 独立 management context 与当前 SecurityFilterChain 行为不一致,先新增真实上下文失败测试,再做最小配置;不得通过重新公开指标绕过。 ## 七、数据与副作用测试 前后保存完整摘要,至少覆盖: - users、user_roles; - student_profiles、resume_versions; - applications、jobs、companies; - auth_tokens、audit_logs; - candidate_dimension_scores; - notifications、messages; - scoring_risk_events/actions; - talent_invitations。 企业下载只允许读取;不得修改上述业务表,不发送 RabbitMQ、短信、邮件或通知。若记录下载审计,字段必须为固定白名单且不得包含路径、文件名、学生 ID 或内容。 ## 八、OpenAPI 与文档 从运行时契约更新 `docs/openapi-rc.json`,不得手工伪造。 更新: - `privacy-settings-api.md` - `resume-api.md` - `frontend-integration.md` - `backend-development-roadmap.md` - `phase1-scope-and-acceptance.md` - `verify_openapi.py` 校验器必须递归断言: - 只有一个新增路径/operation; - 下载接口无 requestBody; - 企业候选人 DTO 不含 `resumeUrl/studentUserId/phone/email/storagePath`; - 不存在按 studentUserId/candidateKey 的简历下载路径; - Actuator 不进入业务 OpenAPI; - 预期基线为 176 paths / 214 operations,最终以运行时生成结果为准。 ## 九、验证顺序 先运行 S03 新增定向测试,再运行: ```powershell cd C:\Users\15642\Desktop\zhilai\mydreamjob-server mvn -Dtest="*AdminBootstrap*Test,*LegacySeed*Test,*Privacy*Test,*Resume*Test,*CompanyCandidate*Test,*Actuator*Test" test mvn -Dtest="*Auth*Test,*Security*Test,*Application*Test,*Company*Test,*Privacy*Test,*Resume*Test" test mvn test mvn clean verify python ..\docs\verify_openapi.py ``` 最后执行: ```powershell cd C:\Users\15642\Desktop\zhilai git diff --check git status --short git diff --cached --name-only git diff --name-only -- mydreamjob-server/src/main/resources/db/migration ``` 必须满足 Failures=0、Errors=0、Skipped=0、clean verify 成功、静态 OpenAPI 校验通过、暂存区为空、V43 为唯一迁移、未新增 ErrorCode。 ## 十、实施结束状态 实施结束立即停止,不操作 Docker,不执行真实 MySQL 黑盒,不暂存、不提交、不推送,不进入 Q01。 最终报告必须列出: 1. V43 精确匹配条件和各账号命中结果; 2. 被修改过的种子账号不受影响证据; 3. 管理员初始化配置、幂等、冲突与并发结果; 4. 是否打印手机号或创建默认密码; 5. 企业简历权限完整决策矩阵; 6. `APPLIED_COMPANIES` 公司归属缺陷修复方式; 7. 拒绝路径文件读取次数; 8. 完整响应与响应头脱敏结果; 9. Actuator 业务端口/管理端口结果; 10. 数据库副作用与 RabbitMQ 结果; 11. 专项、关联、全量测试数及 Failures/Errors/Skipped; 12. clean verify 与 OpenAPI 结果; 13. 精确修改文件和 Git 状态; 14. 是否新增 Flyway、表、索引、ErrorCode、路径; 15. 明确未执行 git add -A、commit、push、Docker/MySQL 黑盒; 16. 明确真实 MySQL/Docker 黑盒仍待独立验收。 最终状态只能写: “S03 已实现并完成自动化验证与干净构建,待独立代码复验及真实 MySQL/Docker 黑盒验收。”