pmc 7a9e511132 test(03-02): Phase 3 端到端验收报告 (CRED-05 + CRED-06)
- 9 truth × 32 项独立断言全 PASS, FAIL = 0
- T1-T5: 客户端 GET 5 项 (user/admin token + 401 + swagger schema)
- T6: filter 4 种正则形态 (JSON/Pyrepr/Query/Fallback)
- T7: 不误伤 Authorization / Bearer 字段
- T8: admin PUT roundtrip + admin GET 脱敏 + client GET 明文
- T9: 端到端 logger.info 真打印 console 输出脱敏
- T_FINAL: DB 探针态还原 (probe_app/probe_secret_xxxx)
- 临时脚本均已删除 (_phase3_01_verify / _phase3_02_unit_test / _phase3_02_verify / _phase3_02_settings_check)
2026-05-08 10:28:26 +08:00

114 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase 3 端到端验收报告CRED-05 + CRED-06
**执行时间**2026-05-08
**执行命令**`python manage.py shell -c "exec(open('_phase3_02_verify.py', encoding='utf-8').read())"`
**结果**ALL PASS — 32 项独立断言全部通过FAIL 数 = 0
**临时验收脚本**:跑完即删(`_phase3_01_verify.py` / `_phase3_02_unit_test.py` / `_phase3_02_verify.py` / `_phase3_02_settings_check.py`
---
## 9 条 Truth × 32 项独立断言
### T1: client GET 携 user token → 200 + 明文
```
[PASS] T1.user_token_200: sc=200
[PASS] T1.success_true
[PASS] T1.app_id
[PASS] T1.access_token_plain: should be plaintext
[PASS] T1.no_mask_in_response
```
### T2: client GET 携 admin token → 200 + 明文(不区分 admin / user token
```
[PASS] T2.admin_token_200
[PASS] T2.access_token_plain
```
### T3: client GET 无 token → 401 + 标准壳层 success=false
```
[PASS] T3.no_token_401
[PASS] T3.success_false
```
### T4: client GET 伪造 token → 401Redis 中无该 key
```
[PASS] T4.fake_token_401
```
### T5: /swagger.json/ 含 /credential-slot/ 路径 + GET 方法
```
[PASS] T5.swagger_200
[PASS] T5.path_in_schema: keys_sample=['/achievement/achievements/', '/achievement/achievements/{id}/', '/achievement/achievements/{id}/check_achievement/', '/achievement/user-achievements/', '/achievement/user-achievements/check_and_grant/']
[PASS] T5.has_get
```
### T6: AccessTokenMaskFilter 4 种序列化形态全脱敏
```
[PASS] T6.JSON.no_plain: out='{"access_token": "********1234"}'
[PASS] T6.JSON.has_tail
[PASS] T6.Pyrepr.no_plain: out="{'access_token': '********1234'}"
[PASS] T6.Pyrepr.has_tail
[PASS] T6.Query.no_plain: out='GET /x?access_token=********1234&u=1'
[PASS] T6.Query.has_tail
[PASS] T6.Fallback.no_plain: out='access_token: ********1234'
[PASS] T6.Fallback.has_tail
```
### T7: AccessTokenMaskFilter 不误伤 Authorization header / Bearer 字段
```
[PASS] T7.unmodified_Authorization h: out='Authorization header: bearer_user_token_xxxxxxx'
[PASS] T7.unmodified_Bearer raw_toke: out='Bearer raw_token_zzz'
```
### T8: 端到端 admin PUT roundtrip → client GET 一致明文 + admin GET 脱敏
```
[PASS] T8.put_200: sc=200
[PASS] T8.admin_get_masked: admin GET should mask got='**********RT99'
[PASS] T8.admin_get_tail_RT99
[PASS] T8.client_get_plain: client GET should be plain got='rt_secret_RT99'
[PASS] T8.client_app_id
```
### T9: 端到端 logger.info 真打印 → console 输出脱敏(防御性兜底真实生效)
```
[PASS] T9.logger_info_no_plain: out='defensive_test access_token=*****************DEFC'
[PASS] T9.logger_info_tail
```
### T_FINAL: DB 探针态主动还原(给后续 phase 留稳定起点)
```
[PASS] T_FINAL.db_restored.app_id
[PASS] T_FINAL.db_restored.access_token
```
---
## 关键观察
- **明文走客户端 / 脱敏走管理端**T8 同时验证了 `/api/credential-slot/`(客户端)返回 `'rt_secret_RT99'` 明文,与 `/api/v1/admin/credential-slot/`(管理端)返回 `'**********RT99'` 末 4 位脱敏view 层差异化语义正确
- **Filter 兜底真实生效**T9 端到端调 `logger.info('access_token=defensive_secret_DEFC')`console handler 实际输出 `***...DEFC`17 个 `*` + 末 4 位 `DEFC`),证明 settings.LOGGING.handlers.console.filters 注册路径打通
- **Filter 4 种正则形态全部覆盖**T6JSON / Python dict repr / URL query / 等号或冒号兜底,每种形态 mask 后保留末 4 位明文(`1234`
- **不误伤其它敏感字段**T7filter 只识别 `access_token` 字段名前缀锚点;`Authorization header: bearer_user_token_xxxxxxx` / `Bearer raw_token_zzz` 经过 filter 后字符级一致
## 偏差记录auto-fixed
详见 `03-02-SUMMARY.md` 的 "Deviations from Plan" 段。本阶段共 fixed 2 处:
1. **[Rule 1 - Bug] 4 个 regex 正则交叉吃掉末 4 位**Pattern 4 兜底正则把 Pattern 3 已脱敏的 `********1234&u=1` 当 value 整段二次 mask`1234` 吃成 `&u=1`)— Pattern 4 终止符 `[^\s,;)\]\}"\']+` 增加 `&` / `=` 排除字符
2. **[Rule 1 - Bug] tuple 形态 args 误吃 `%s` 占位符**filter 先扫 `record.msg``access_token=%s` 中的 `%s` 当 value mask 成 `**`Formatter 阶段 `'access_token=**' % ('abcdefgh1234',)` 报 TypeError— 改为tuple args 形态先 `record.getMessage()` 拼成最终字符串再整体脱敏args 清空避免 Formatter 二次拼接
---
*Phase: 03-client-and-log-mask*
*Verification completed: 2026-05-08*