Description 矛盾清单(按风险排序)
F1 [P2] 产品会话 JWT 缺少 clock skew leeway
两个时间量 :产品 JWT ParseToken leeway = 0s vs capability token / edge validate leeway = 30s
证据 :hub-server/internal/jwtutil/jwt.go:97 (ParseToken) 和 :351 (KeyManager.ParseToken) 调用 jwt.ParseWithClaims 时未传 jwt.WithLeeway;而 hub-server/internal/jwtutil/tokendance.go:269 和 edge-server/internal/jwtutil/validate.go:64 均使用 jwt.WithLeeway(30*time.Second)
风险 :Hub 与客户端/Edge 时钟偏移 >0s 时,产品会话 JWT 比 capability token 更早被拒;合法用户在 NTP 不同步场景下被踢出会话
修复切片 :给 ParseToken / KeyManager.ParseToken 加 jwt.WithLeeway(30*time.Second),与 capability/edge 对齐
F2 [P2] Edge delivery journal retention > run terminal TTL(缓存比数据活得久)
两个时间量 :journal retention = 7d vs run terminal cleanup TTL = 24h
证据 :edge-server/internal/hub/delivery_journal_sqlite.go:280 (DefaultJournalRetention = 7 * 24 * time.Hour) vs edge-server/internal/runcontrol/runcontrol.go:39 (DefaultRunCleanupTerminalTTL = 24 * time.Hour)
风险 :run 在 24h 后被清理,但 journal 中引用该 run 的条目保留至 7d;reconciliation/replay 时可能查到孤儿 journal 条目,导致无效重试或错误状态
修复切片 :将 journal retention 降至 ≤ run TTL(如 24h),或将 run TTL 提升至 ≥ journal retention;推荐前者(journal 是 run 的派生数据)
F3 [P3] Edge TokenProvider 刷新延迟依赖本地时钟
两个时间量 :tokenRefreshLead = 1min vs accessTTL = 15min (lead 占比 6.7%)
证据 :edge-server/internal/hub/token_provider.go:156 (time.Until(time.Unix(exp, 0)) - tokenRefreshLead),:52 (tokenRefreshLead = time.Minute)
风险 :time.Until 用本地时钟,exp 由 Hub 签发(Hub 本地时钟)。两节点 NTP 偏移 >1min 时,Edge 可能在 token 已过期后才触发刷新,导致 API 调用失败
修复切片 :增加 refresh lead 至 2-3min,或在 refresh 失败时指数退避+立即重试
F4 [P3] WS ReadTimeout 与 pong-miss 检测边界竞争
两个时间量 :WSReadTimeout = 60s (2×30s heartbeat) vs pong-miss 检测 ≈ 65s (2×30s + 5s ping timeout)
证据 :hub-server/internal/ws/conn.go:19 (WSReadTimeout = 2 * config.WSHeartbeatInterval),hub-server/internal/config/constants.go:172,175,179 (Heartbeat=30s, PingTimeout=5s, MaxMissedPongs=2)
风险 :完全静默连接上,read timeout 和 pong-miss 几乎同时触发;半开连接上 read timeout 可能先于 pong-miss 关闭连接,跳过 metrics 记录
修复切片 :将 WSReadTimeout 调整为 2*Heartbeat + PingTimeout (65s) 或 3*Heartbeat (90s),确保 pong-miss 检测优先触发
边界问题(非矛盾但需注意)
JWT 签发/校验均用 time.Now()(本地时钟) :hub jwt.go:33,56,276,299,edge token_provider.go:156。无显式 UTC 归一化。当前依赖 Go runtime 默认行为(Unix 时间戳本质是 UTC),但代码意图不明确,未来重构易引入时钟源混用
OIDC state 双重过期 :Redis TTL=10min + 代码检查=10min (oidc.go:55,149,264)。正确但冗余;代码检查用 time.Since 本地时钟,Redis TTL 是权威
基线
未覆盖面
Mobile/Web 前端 token 刷新逻辑(app/ 目录)
TokenDance ID 侧 OIDC provider 时钟行为
生产环境 NTP 同步状态实测
DB 层 expire_at 字段与时钟源一致性(GORM time.Now() 注入)
Reactions are currently unavailable
You can’t perform that action at this time.
矛盾清单(按风险排序)
F1 [P2] 产品会话 JWT 缺少 clock skew leeway
hub-server/internal/jwtutil/jwt.go:97(ParseToken) 和:351(KeyManager.ParseToken) 调用jwt.ParseWithClaims时未传jwt.WithLeeway;而hub-server/internal/jwtutil/tokendance.go:269和edge-server/internal/jwtutil/validate.go:64均使用jwt.WithLeeway(30*time.Second)jwt.WithLeeway(30*time.Second),与 capability/edge 对齐F2 [P2] Edge delivery journal retention > run terminal TTL(缓存比数据活得久)
edge-server/internal/hub/delivery_journal_sqlite.go:280(DefaultJournalRetention = 7 * 24 * time.Hour) vsedge-server/internal/runcontrol/runcontrol.go:39(DefaultRunCleanupTerminalTTL = 24 * time.Hour)F3 [P3] Edge TokenProvider 刷新延迟依赖本地时钟
edge-server/internal/hub/token_provider.go:156(time.Until(time.Unix(exp, 0)) - tokenRefreshLead),:52(tokenRefreshLead = time.Minute)time.Until用本地时钟,exp由 Hub 签发(Hub 本地时钟)。两节点 NTP 偏移 >1min 时,Edge 可能在 token 已过期后才触发刷新,导致 API 调用失败F4 [P3] WS ReadTimeout 与 pong-miss 检测边界竞争
hub-server/internal/ws/conn.go:19(WSReadTimeout = 2 * config.WSHeartbeatInterval),hub-server/internal/config/constants.go:172,175,179(Heartbeat=30s, PingTimeout=5s, MaxMissedPongs=2)2*Heartbeat + PingTimeout(65s) 或3*Heartbeat(90s),确保 pong-miss 检测优先触发边界问题(非矛盾但需注意)
time.Now()(本地时钟):hubjwt.go:33,56,276,299,edgetoken_provider.go:156。无显式 UTC 归一化。当前依赖 Go runtime 默认行为(Unix 时间戳本质是 UTC),但代码意图不明确,未来重构易引入时钟源混用oidc.go:55,149,264)。正确但冗余;代码检查用time.Since本地时钟,Redis TTL 是权威基线
未覆盖面
time.Now()注入)