fix(mcp): code review I2 — admin expires_at must be future + Part 3 tx TODO + scope JSON round-trip tests

- IssueAdmin now rejects past/now ExpiresAt with CodeMcpTokenExpiresRequired
- TestIssueAdmin_ExpiresMustBeFuture covers the new path
- IssueSystemToken doc comment notes pgRepo currently ignores ctx tx; Part 3
  must add Repository.WithTx for true same-transaction guarantee with
  acp_sessions (spec §6.1)
- New scope_test.go (whitebox) verifies JSON round-trip preserves nil-vs-empty
  semantics on Tools / ProjectIDs and exercises AllowsTool / AllowsProject
  edges that Authenticate / future tool gating depend on
This commit is contained in:
2026-05-08 08:30:26 +08:00
parent c046d77a6e
commit 71a3a85b26
3 changed files with 107 additions and 0 deletions
+9
View File
@@ -79,6 +79,9 @@ func (s *tokenService) IssueAdmin(ctx context.Context, in IssueAdminInput) (Issu
if in.ExpiresAt.IsZero() {
return IssueResult{}, errs.New(errs.CodeMcpTokenExpiresRequired, "expires_at is required for admin token")
}
if !in.ExpiresAt.After(time.Now()) {
return IssueResult{}, errs.New(errs.CodeMcpTokenExpiresRequired, "expires_at must be in the future")
}
plain, hash, err := NewToken()
if err != nil {
@@ -128,6 +131,12 @@ func (s *tokenService) IssueAdmin(ctx context.Context, in IssueAdminInput) (Issu
// FK 校验失败。spec §6.1 明确建议同事务提交。本 service 不直接管事务边界(由
// ACP SessionService 在 Create 流程内编排),但调用顺序由调用方保证。
//
// TODO(Part 3): 当前 pgRepo 持有 *pgxpool.Pool 并忽略 ctx 中可能存在的 pgx tx,
// 因此严格意义上 IssueSystemToken 与 acp_sessions row 的写入并不在同一事务里 ——
// 调用顺序虽然能避开 FK 错误,但不是真正的原子提交。要兑现 spec §6.1 同事务
// 保证,Part 3 需要为 Repository 增加 `WithTx(tx pgx.Tx) Repository` 构造,
// 并在 acp.SessionService.Create 中以同一事务执行 acp_sessions 插入与本次签发。
//
// 默认 ExpiresIn = 24h;默认 Tools 为内置 PM 工具白名单(spec §6.2)。
// 写一条 audit `mcp.token.create_system`。
func (s *tokenService) IssueSystemToken(ctx context.Context, in IssueSystemTokenInput) (IssueResult, error) {