docs: 2026-09-11 安全事件复盘 + 新建服务器暴露面清单 + M3.5 报告 03/04/05 入档
CI / docs-build (push) Successful in 1m59s
CI / docs-build (push) Successful in 1m59s
安全事件(已闭环,服务恢复): - 根因链:Gitea 3000 对公网开放 → 外部调用 /api/internal/manager/add-logger 注入 gitconfig 的 uploadpack.packObjectsHook → 指向不存在的脚本 → upload-pack 发 NAK 后无法产出 pack → 全仓 HTTPS clone 失败(CI 全挂) - 攻击未达成代码执行(hook 目标脚本不存在);三仓 ref 与本地逐一核对未被篡改; 无系统层入侵(无陌生 key/crontab/挖矿进程/陌生登录) - 新建常设「服务器暴露面清单」:补上服务器侧「决策变了环境没跟上」的核对机制 (Nacos 在 ADR-002 移除后仍暴露公网近两个月) - CI Runner 手册排障表增三条:CI 秒失败先在本机复现 checkout、跨仓比 CI 须核对时间戳、clone 坏而 push 正常时查 packObjectsHook 注入 M3.5 交付报告:03 后端资料与头像(api 334→379)、04 契约冻结 v1.4.0 (31→32 路径、矩阵 173→181 格、11 格红转绿)、05 资料页与头像 UI(flutter 526→597) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -166,3 +166,57 @@ _(待真机到位后填写:日期、设备型号/Android 版本、两项结
|
||||
## 执行记录(M3)
|
||||
|
||||
_(待补)_
|
||||
|
||||
---
|
||||
|
||||
# M3.5 预登记(用户资料与头像,2026-09-11 登记)
|
||||
|
||||
M3.5 第二波(T3.5-08/09/10)交付后新增的真机专属项。**桌面已覆盖的不重复登记**:注册/登录 → 资料页真实化 → 设昵称 → 传用户头像 → Feed 作者名同步 → 宠物头像上传的整条链路已在 Linux 桌面对 compose 真后端跑通并逐步截图(`integration_test/profile_avatar_live_test.dart`,见 iteration-3.5/05 号报告 §4);下列四项是**桌面替代不了**的部分。
|
||||
|
||||
1. **头像上传弱网表现**(T3.5-08/09 收口登记):真机蜂窝/弱 Wi-Fi 下「选图 → 压缩 → 预签名直传 → confirm → PATCH 挂载」全链路。
|
||||
|
||||
**前置**:通用前置准备的后端六容器在位;`PATBOND_MINIO_PUBLIC_ENDPOINT` 必须配置为手机可达地址(工作机局域网 IP:9000,.env 覆盖后重启 compose)——头像直传与预签名读都直指 MinIO,漏配则手机端必失败;`flutter run` 四个 base URL 全传。入口:我的资料 → 编辑资料 → 更换头像;档案 → 宠物详情 → 点头像。
|
||||
|
||||
**与第 1 项(媒体上传弱网)的差异**:头像走的是**单图、单并发**的 `MediaUploader`(`maxImages: 1`、`maxConcurrentUploads: 1`),且交付口是「预览后点『使用这张』才落 assetId」,不是九宫格的批量 gating。故槽位调度与孤儿防护的表现需单独看。
|
||||
|
||||
**步骤与通过标准**:
|
||||
- [ ] (a)**正常网真机相册**:从相册选一张 12MP 竖拍照 → sheet 内出线性进度条与递增百分比(非一跳 100%)→ 出圆形预览 → 点「使用这张」→ 回编辑页显示「已选择新头像」→ 保存后资料页头像**真的画出图**(不是爪印/人形占位)。此项同时验证原生压缩层(桌面实测用的是透传替身,真机才走 flutter_image_compress)。
|
||||
- [ ] (b)**弱网中断重试**:上传中开飞行模式掐断 → sheet 转失败态并给「重试 + 重新选择」两个按钮 → 恢复网络点「重试」→ 转就绪可确认。中断产生的旧 asset 保持 `uploading`(属服务端超时清理范围,不算失败);核对 `identity.users.avatar_asset_id` / `pet_health.pets.avatar_asset_id` **未**指向中断的那个 assetId。
|
||||
- [ ] (c)**压缩后仍超限**:选一张超大原图(若压缩后仍 >10 MiB)→ 失败态**只给「重新选择」、不给「重试」**(重试同一张必然再失败)。
|
||||
- [ ] (d)**凭据过期**:选图后把 App 挂起 >10 分钟再回前台触发重试 → 自动换新凭据完成上传,用户无感知,不弹「签名过期」类错误。
|
||||
- [ ] (e)**中途退出不留引用**:上传中直接关掉 sheet → 无 SnackBar 报错、资料/宠物头像不变;`post_media_upload_failed(failureReason=cancelled)` 一条(头像沿用同一套媒体埋点)。
|
||||
- [ ] (f)**HEIC 与方向**:iPhone 传输的 HEIC 与横拍各一张 → 压缩层统一出 jpeg 且方向正确(服务端 mime 白名单不收 HEIC,只能真机验原生编解码)。
|
||||
|
||||
2. **头像缓存表现**(T3.5-08/09 收口登记):预签名 URL 每次响应现签,缓存 key 已剥 `X-Amz-*`;真机需确认同一张头像不会反复下载、过期后能重取。
|
||||
|
||||
**前置**:同第 1 项。数据:本人已设头像、至少一只宠物已设头像、Feed 内有本人发布的帖(作者头像与资料页头像同一对象)。
|
||||
|
||||
**步骤与通过标准**:
|
||||
- [ ] (a)**跨页命中**:资料页 → 首页 Feed(作者头像)→ 档案列表 → 宠物详情,来回切三轮 → 已展示过的头像**不再转圈**;抓包或 MinIO 访问日志核对同一 object key 未重复 GET(缓存 key 剥签名参数生效;若「每次进页面同图重下」即为 `presignedImageCacheKey` 回归,判失败)。
|
||||
- [ ] (b)**下拉刷新后仍命中**:Feed 下拉刷新(服务端重新现签、URL 必变)→ 作者头像即时出图不转圈。
|
||||
- [ ] (c)**过期后重取**:停留 >1 小时(预签名 TTL 默认 1h)后进未加载过的页 → 旧 URL 过期走占位属预期;下拉刷新/重进页面取新签 URL 后恢复出图,无崩溃、不缓存坏图。
|
||||
- [ ] (d)**清除头像后不留残影**:编辑页「清除头像」保存 → 资料页立刻回人形占位,Feed 作者头像在服务端作者缓存过期后(≤60s,见下方备注)也回占位;重启 App 后仍是占位(URL 不得被持久化,纪律 R2)。
|
||||
|
||||
3. **caregiver 账号改宠物头像**(T3.5-09 收口登记;ADR-022 D3.5-3 的 WRITE 档实证):桌面实测只跑了 owner 路径,caregiver 需第二个账号 + 一条协作关系。
|
||||
|
||||
**前置**:两个账号 A(owner)/ B(caregiver),B 对 A 的宠物有 caregiver 角色(关系授予入口尚未开放,按 `pet_health` 的协作表直接造数据,收口时补 SQL)。
|
||||
|
||||
**步骤与通过标准**:
|
||||
- [ ] (a)B 打开该宠物详情 → **头像铅笔角标在**(WRITE 档),但「编辑资料」入口**不在**(MANAGE 档,仅 owner)。
|
||||
- [ ] (b)B 上传头像 → 成功;A 侧刷新详情看到同一张。
|
||||
- [ ] (c)viewer 角色的第三个账号 C → 头像不可点、无角标。
|
||||
|
||||
4. **获赞数与帖子点赞数对账**(T3.5-08 收口登记):资料页「获赞」= 本人已发布未删帖的 `like_count` 之和(**含自赞**,与帖子详情同口径)。
|
||||
|
||||
**步骤与通过标准**:
|
||||
- [ ] (a)自己给自己的帖点赞 → 帖子详情 likeCount +1,资料页「获赞」也 +1(两处数字必须能对上;对不上说明口径分叉)。
|
||||
- [ ] (b)他人点赞 2 次不同帖 → 资料页「获赞」为各帖 likeCount 之和。
|
||||
- [ ] (c)软删一篇被赞的帖 → 「获赞」与「我的作品」同时回落(删帖即撤回其数字)。
|
||||
- [ ] (d)存一篇草稿 → 「我的作品」**不**变(草稿尚非作品)。
|
||||
|
||||
> **备注(服务端刻意的滞后,不是缺陷)**:改昵称/换头像后,**Feed 与帖子详情里的作者名与作者头像**最多滞后 60 秒才更新——community 侧 `AuthorProfileGateway` 把 `/internal/users/profiles` 的结果放在 60s TTL 的进程内缓存里(`patbond.author-profile.cache-ttl`,M3 T3-05)。资料页与首页问候语读的是 `/me`,**没有这层缓存,立即生效**。真机执行第 2、4 项时若看到「资料页已变、Feed 还是旧名」,先等过 60 秒再判定。
|
||||
|
||||
## 执行记录(M3.5)
|
||||
|
||||
_(待补)_
|
||||
|
||||
|
||||
Reference in New Issue
Block a user