feat(vnext): complete vNext.1 release gate — default chain admission, idempotent init, user key skeleton
- DEFAULT_CHAIN_ADMISSION.md: reviewed and approved, real artifact refs added - DEFAULT_DATA_IDEMPOTENT_RELEASE_GATE.md: reviewed and approved - scripts/setup_default_data.sh: idempotent init with --dry-run/--apply/artifact - scripts/test/test_default_data.sh: 4 test cases all pass - scripts/acceptance/verify_user_key_self_service.sh: Phase 0 skeleton - .gitignore: add generated artifact directories
This commit is contained in:
226
docs/2026-06-04-KEY_SELF_SERVICE_API.md
Normal file
226
docs/2026-06-04-KEY_SELF_SERVICE_API.md
Normal file
@@ -0,0 +1,226 @@
|
||||
# Key Self-Service API
|
||||
|
||||
日期:2026-06-04
|
||||
状态:待审核
|
||||
适用版本:vNext.2
|
||||
|
||||
## 目的
|
||||
|
||||
定义用户 key 自助申请流程中的 API 契约,包括 key 的创建、展示、重置、暂停、恢复、查询。当前版本仅做设计,不实现。
|
||||
|
||||
## 实体与状态
|
||||
|
||||
### KeyRecord
|
||||
|
||||
| field | type | 说明 |
|
||||
| ---------------- | -------- | ------------------------------------ |
|
||||
| key_id | string | 唯一 ID |
|
||||
| owner_subject_id | string | 属主 |
|
||||
| key_fingerprint | string | 生成时对完整 key 取 sha256 |
|
||||
| masked_preview | string | 最后 4 位或 `sk-****....abcd` |
|
||||
| display_name | string | 用户可编辑名称 |
|
||||
| logical_group_id | string | 对应逻辑分组 |
|
||||
| allowed_models | []string | 该 key 可调用的模型列表 |
|
||||
| admin_status | string | active / paused / disabled / retired |
|
||||
| quota_status | string | ok / exhausted / limited / unknown |
|
||||
| last_used_at | datetime | 空表示从未使用 |
|
||||
| created_at | datetime | 创建时间 |
|
||||
| expires_at | datetime | 可选失效时间 |
|
||||
|
||||
### 审计事件
|
||||
|
||||
| field | type | 说明 |
|
||||
| ---------------- | -------- | ---------------------------------------- |
|
||||
| event_id | string | 唯一 ID |
|
||||
| actor_subject_id | string | 操作者 |
|
||||
| actor_role | string | admin / user |
|
||||
| target_key_id | string | 受影响的 key |
|
||||
| action | string | create / reset / pause / resume / delete |
|
||||
| result | string | success / denied / failed |
|
||||
| reason | string | 操作说明 |
|
||||
| created_at | datetime | 事件时间 |
|
||||
|
||||
## REST API 契约
|
||||
|
||||
### POST /api/keys
|
||||
|
||||
创建 key。明文 key 在返回的 `plaintext_key` 字段返回一次。
|
||||
|
||||
请求体:
|
||||
|
||||
```json
|
||||
{
|
||||
"logical_group_id": "gpt-shared",
|
||||
"display_name": "test key",
|
||||
"allowed_models": ["gpt-5.4"]
|
||||
}
|
||||
```
|
||||
|
||||
响应 201:
|
||||
|
||||
```json
|
||||
{
|
||||
"key": {
|
||||
"key_id": "key_abc123",
|
||||
"plaintext_key": "sk-...full-key...",
|
||||
"masked_preview": "sk-****abcd",
|
||||
"display_name": "test key",
|
||||
"logical_group_id": "gpt-shared",
|
||||
"allowed_models": ["gpt-5.4"],
|
||||
"admin_status": "active",
|
||||
"quota_status": "ok",
|
||||
"created_at": "2026-06-04T..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `plaintext_key` 只在本响应返回
|
||||
- 后续所有列表/详情接口都不包含 `plaintext_key`
|
||||
|
||||
### GET /api/keys
|
||||
|
||||
获取当前用户自己的 key 列表。
|
||||
|
||||
响应 200:
|
||||
|
||||
```json
|
||||
{
|
||||
"keys": [
|
||||
{
|
||||
"key_id": "key_abc123",
|
||||
"masked_preview": "sk-****abcd",
|
||||
"display_name": "test key",
|
||||
"logical_group_id": "gpt-shared",
|
||||
"allowed_models": ["gpt-5.4"],
|
||||
"admin_status": "active",
|
||||
"quota_status": "ok",
|
||||
"last_used_at": null,
|
||||
"created_at": "2026-06-04T..."
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
约束:
|
||||
|
||||
- 只返回当前 subject 的 key
|
||||
- 不返回 `plaintext_key`
|
||||
- 不返回 `route_id`、`shadow_group_id`、`host_account_id`
|
||||
|
||||
### GET /api/keys/:id
|
||||
|
||||
获取单个 key 元数据。校验属主或管理员权限。
|
||||
|
||||
响应 200:同上(无 `plaintext_key`)。
|
||||
|
||||
### POST /api/keys/:id/reset
|
||||
|
||||
重置 key。旧 key 失效,新明文 key 在响应中返回一次。
|
||||
|
||||
响应 200:
|
||||
|
||||
```json
|
||||
{
|
||||
"plaintext_key": "sk-...new-full-key...",
|
||||
"masked_preview": "sk-****wxyz",
|
||||
"admin_status": "active"
|
||||
}
|
||||
```
|
||||
|
||||
约束:
|
||||
|
||||
- 写入审计事件
|
||||
- 旧 `plaintext_key` 立即失效
|
||||
- 重置后当前 subject 的 sticky binding 应重新评估
|
||||
|
||||
### POST /api/keys/:id/pause
|
||||
|
||||
暂停 key。请求体可选 `reason`。
|
||||
|
||||
响应 200:
|
||||
|
||||
```json
|
||||
{
|
||||
"key_id": "key_abc123",
|
||||
"admin_status": "paused",
|
||||
"reason": "admin initiated"
|
||||
}
|
||||
```
|
||||
|
||||
约束:
|
||||
|
||||
- 暂停后用户调用应失败
|
||||
- 暂停原因应对用户可见
|
||||
- 写入审计事件
|
||||
|
||||
### POST /api/keys/:id/resume
|
||||
|
||||
恢复暂停的 key。
|
||||
|
||||
响应 200:
|
||||
|
||||
```json
|
||||
{
|
||||
"key_id": "key_abc123",
|
||||
"admin_status": "active"
|
||||
}
|
||||
```
|
||||
|
||||
约束:
|
||||
|
||||
- 仅暂停状态的 key 可恢复
|
||||
- 写入审计事件
|
||||
|
||||
### DELETE /api/keys/:id
|
||||
|
||||
删除/退役 key。
|
||||
|
||||
响应 200:
|
||||
|
||||
```json
|
||||
{
|
||||
"key_id": "key_abc123",
|
||||
"admin_status": "retired"
|
||||
}
|
||||
```
|
||||
|
||||
约束:
|
||||
|
||||
- 退役后不再参与分发
|
||||
- 写入审计事件
|
||||
- 不真正删除记录,保留审计一致性
|
||||
|
||||
## 授权规则
|
||||
|
||||
用户侧:
|
||||
|
||||
- 仅管理自己的 key
|
||||
- 不能查看他人 key、metadata、audit log
|
||||
|
||||
管理员侧:
|
||||
|
||||
- 可查看所有 key 的 metadata
|
||||
- 可暂停 / 恢复 / 重置 / 退役任意 key
|
||||
- 可查看审计事件
|
||||
- 禁止查看已收回的 `plaintext_key`
|
||||
|
||||
## 安全限制
|
||||
|
||||
1. 创建 key 限频:每 subject 每小时 5 次(vNext.2 建议值)
|
||||
2. 重置 key 限频:每 subject 每 24 小时 2 次(vNext.2 建议值)
|
||||
3. key 最短存活时间:至少存活 1 小时才允许退役(可讨论)
|
||||
4. 管理员暂停 key 不需要 subject 同意,但需要记录 reason
|
||||
|
||||
## 测试要求
|
||||
|
||||
- 用户 A 创建 key → 用户 B 不能看到
|
||||
- 用户 A 创建 key → 用户 B 不能重置
|
||||
- 创建后 `plaintext_key` 只返回一次
|
||||
- 管理员暂停后,用户调用返回 403 且 reason 明确
|
||||
- 重置后旧 key 失效,新 key 唯一可用的证据
|
||||
|
||||
## 与本轮范围关系
|
||||
|
||||
属于 vNext.2 设计产物。在 vNext.1 审核通过前,不允许实现。
|
||||
Reference in New Issue
Block a user