# IAM 规则自查（阶段 8 收尾）

> 对 `09-iam-security.md` 的 17 条关键设计决策 × 22 条禁止事项逐项核对代码实现。
> 非强制业务接入项（"Service 接入 assertAccess" 等）标注为"基础设施就位 / 业务增量"。

## 17 条关键设计决策

| # | 决策 | 代码落地 | 状态 |
|---|---|---|---|
| 1 | Guard 只管权限码，DataScope 管数据范围 | `permissions.guard.ts` 精简；`DataScopeInterceptor` 全局注册 | ✅ |
| 2 | 不做端点级 ceiling；做**配置级 ceiling** | `PermissionDelegationService` 预留 ceiling 钩子；角色-DataScope 分配接口未实现 | 🔶 基础设施就位，UI / Controller 接入待业务 |
| 3 | 规则层不分期，一次定义终态 | 09-iam-security.md 纯规则；09-iam-implementation-plan.md 只追踪进度 | ✅ |
| 4 | @DataScope 装饰器携带字段映射 | `data-scope.decorator.ts` + `DataScopeFieldMapping` | ✅ |
| 5 | 写操作 Service 层 assertAccess | `DataScopeService.assertAccess` + 静态契约检查脚本 + pre-commit | ✅ 基础设施 |
| 6 | JWT payload 仅存身份标识，权限走 Redis 缓存 | `TokenService.issuePair` 签发 `{sub,jti,exp}`；`AuthCacheService` 5min TTL | ✅ |
| 7 | 部门树递归 maxDepth=10 | `OrganizationContextService.expandChildren` + `DepartmentTreeTooDeepException` | ✅ |
| 8 | 无 DataScope 配置时默认 SELF | `DataScopeService.resolveEffectiveScope` fallback | ✅ |
| 9 | CUSTOM 类型永久禁用 | `DataScopeService.buildFilter` / `isRecordInScope` 遇到抛 `NotImplementedException` | ✅ |
| 10 | 身份维度归 DataScope，业务维度归 Service | 文档职责边界声明；DataScope 仅支持 6 枚举值 | ✅ |
| 11 | 读未授权返回 404；写未授权返回 403 | `<NotFoundPage>` + `<ForbiddenPage>`；`DataScopeInterceptor` 注入 WHERE 让 findUnique 返 null → 404 | ✅ 基础设施 |
| 12 | 跨组织数据范围仅取当前组织合并 | `AuthCacheService` 按组织分层存储；`sliceAuthPayload` 仅取 systemRoles + currentOrg | ✅ |
| 13 | DataScope 配置变更必审计 | `IamAuditService.record` + `iam_audit_log` 表 | ✅ 基础设施 |
| 14 | 异步任务必须显式携带 actor | `SystemPrincipalService` + `MissingActorException` | ✅ 基础设施 |
| 15 | 委托（Delegation）一等公民，仅一级，必审计 | `PermissionDelegation` schema + `PermissionDelegationService.assertNotChained` | ✅ |
| 16 | 用户-角色绑定 90 天内必须 Access Review | `UserRole.lastReviewedAt` + `AccessReviewService` | ✅ |
| 17 | IDOR 零容忍：静态检查 + 集成测试 + PR Review 三重防护 | `assert-access-check.ts` + pre-commit 阻断 + 规范写入 PR checklist | ✅ 基础设施 |

## 22 条禁止事项

| # | 禁止 | 代码兑现 | 状态 |
|---|---|---|---|
| 1 | 禁止 DISABLE_AUTH_GUARDS | `permissions.guard.ts` 已移除环境变量 bypass | ✅ |
| 2 | 禁止 @Roles | 无 @Roles 引用 | ✅ |
| 3 | 禁止带 Scope 装饰器 | `permissions.decorator.ts` 只 export `RequirePermissions`，orphan 已删 | ✅ |
| 4 | 禁止冗余 @UseGuards | 批量 controller 迁移已删 | ✅ |
| 5 | 禁止无装饰器端点 | `PermissionsGuard` 逻辑：无 @RequirePermissions 必须有 @Public() | 🔶 部分 controller 仍需补全 |
| 6 | 禁止手动数据范围过滤 | DataScopeService 统一出口；规范已发 | 🔶 业务逐步替换 |
| 7 | 禁止手动角色检查 | AuthContext 提供 hasRole；规范已发 | 🔶 业务逐步替换 |
| 8 | 禁止内存 Token 黑名单 | 已切到 Redis via `TokenService` | ✅ |
| 9 | 禁止 CUSTOM 类型 | runtime throw | ✅ |
| 10 | 禁止写操作跳过 assertAccess | 静态检查 + pre-commit 阻断 | ✅ 基础设施 |
| 11 | 禁止 JWT payload 携带权限数据 | 签发时只含 `sub/jti/exp` | ✅ |
| 12 | 禁止跨组织合并 DataScope | AuthCacheService 按组织分层 | ✅ |
| 13 | 禁止配置超过自己 scope 的 DataScope | PermissionDelegation 有钩子；Controller 接入待业务 | 🔶 基础设施 |
| 14 | 禁止客户端直接设置 organizationId | 规则写明"服务端覆盖"；各 Service 需按规范接入 | 🔶 业务逐步替换 |
| 15 | 禁止读操作单条查询不带 dataScopeFilter | DataScopeInterceptor 注入；Service 层合并模式文档化 | 🔶 业务逐步替换 |
| 16 | 禁止在本文件维护实施进度 | 实施进度全在 09-iam-implementation-plan.md / todo.md | ✅ |
| 17 | 禁止异步任务无显式 actor | `SystemPrincipalService.validateAndAuditActor` | ✅ 基础设施 |
| 18 | 禁止链式委托 | `PermissionDelegationService.assertNotChained` | ✅ |
| 19 | 禁止部门树超限静默截断 | `DepartmentTreeTooDeepException` 抛出 | ✅ |
| 20 | 禁止单实例 Redis 部署 | 规则文档声明；运维部署层强制 | 📋 部署规范，代码不可兜底 |
| 21 | 禁止未知 resource 静默降级 | `DataScopeService.resolveEffectiveScope` WARN + metric | ✅ |
| 22 | 禁止跳过静态契约检查 | pre-commit 挂载；`@SkipAssertAccess('理由')` 必填理由 | ✅ |

## 图例

- ✅ 完全实现：代码层已兑现规则要求
- ✅ 基础设施：核心能力已就位，细节接入由业务模块增量推进
- 🔶 部分实现：基础设施在位，业务需逐步迁移
- 📋 非代码兜底：规则由部署/运维/组织规范保证

## 合并前强制动作

1. **迁移生成**：在有真实 dev 数据库的环境下执行：
   ```bash
   cd backend
   npx prisma migrate dev --name iam_full_terminal_state
   ```
   会生成一个涵盖所有 IAM schema 变更的迁移目录（DataScope / RoleDataScope / PermissionDelegation / FieldPermission / IamAuditLog / UserRole.lastReviewed* 字段 / DataScopeType / FieldAccess 枚举）。

2. **种子数据检查**：确保 `data-scopes.seed.ts` 不会创建 CUSTOM 类型记录；运行 seed 验证 IAM 基础配置完整。

3. **Redis 验证**：
   - `REDIS_HOST` / `REDIS_PORT` 已配置
   - 生产环境用 Sentinel 或 Cluster 模式（非单实例）
   - 客户端重试策略已启用

4. **Env 检查**：补齐 `JWT_ACCESS_TTL=30m` / `JWT_REFRESH_TTL=30d` / `AUTH_THROTTLER_*`（默认值已在 configuration.ts）。

5. **UAT smoke test**：
   - 登录获得 access + refresh
   - 业务请求成功（任意高频 API）
   - 登出后旧 token 被拒
   - 黑名单持久化跨重启
   - 部门树查询不爆（如果业务深部门场景）

## 已知非阻塞待办（后续增量推进）

- [x] PermissionsGuard 里 Administrator bypass 接入 `IamAuditService.recordAdminBypass`（commit 76fe93f3）
- [x] `AuthService.validateUser` 合并 `PermissionDelegationService.loadActiveInboundScopes`（commit 76fe93f3）
- [ ] IAM 治理 REST API（Controller）：委托 / Access Review（Service 已就位，API 层接入）
- [ ] `@nestjs/schedule` 注册 AccessReviewService.scanAndAlert 定时任务
- [ ] 各业务 controller 逐步加 `@DataScope` 装饰器
- [ ] 各业务 Service 逐步加 `assertAccess` / `@SkipAssertAccess`
- [ ] 各 cron / queue / webhook 处理器接入 `SystemPrincipalService`
- [ ] 业务列表里按需加 `<SystemRecordBadge>` / `<DisabledForSystemRecord>`
- [ ] 业务按钮逐步包裹 `<Can>`
- [ ] FieldPermission 具体字段配置（业务需求驱动）
- [ ] Resource 命名统一 seed 校验脚本
