Skip to content

工作区缺少归档(软删除)入口,且现有归档未对齐 Anthropic 的级联吊销与权限语义 #95

Description

@Postroggy

背景

当前控制台(Console)的工作区只支持创建,没有任何归档/删除入口。组织随项目演推进会积累大量历史工作区,无法清理;同时,后端 admin 层已有的归档能力存在安全语义缺口。本 issue 建议补齐工作区归档(软删除)能力,并对齐 Anthropic 官方的工作区归档语义。

现状证据(代码)

1. 后端 admin 层已有归档,但仅限 admin API,且不级联

  • 路由 internal/admin/handler.go:48r.Post("/{workspace_id}/archive", h.archiveWorkspace)
  • service internal/admin/service.go:299ArchiveWorkspace
  • DB internal/db/admin.go:396-405ArchiveAdminWorkspace
update workspaces
set archived_at = coalesce(archived_at, now()),
    updated_at = now()
where organization_id = $1 and external_id = $2
returning ...

仅对 workspaces 表设置 archived_at没有同步处理该 workspace 下的 console_api_keys

2. 控制台层(面向终端用户的 Console API)完全没有 workspace 归档端点

internal/platformapi/console_api_keys.go:52-57 的 console workspace 路由只有:

POST   /workspaces
GET    /workspaces/{workspaceId}/api_keys
POST   /workspaces/{workspaceId}/api_keys
POST   /workspaces/{workspaceId}/api_keys/{apiKeyId}
GET    /workspaces/{workspaceId}/api_keys/policy
GET    /workspaces/{workspaceId}/api_key_count

没有任何 archive / 删除端点。

3. 归档 workspace 后,其 API key 仍可查询和使用

internal/db/console_api_keys.go:329-332 的 api_key 查询只过滤 key 自身的 archived_at不 join workspace 的 archived 状态

from console_api_keys
  ...
  and archived_at is null   -- 这是 console_api_keys.archived_at,与 workspaces.archived_at 无关

因此:归档一个 workspace 后,该 workspace 下的 API key 仍然能被列出,鉴权路径也不感知 workspace 已归档——归档形同虚设。

4. 前端工作区设置页没有归档入口

web/src/features/settings/WorkspacesSettingsPage.tsx:160-169 的 Actions 列只有两个链接:

<ButtonLink variant="outline" size="sm" href={workspaceApiKeysPath(workspace.id)}>API keys</ButtonLink>
<ButtonLink variant="ghost" size="sm" href={workspaceWebhooksPath(workspace.id)}>Webhooks</ButtonLink>

没有归档/删除操作。

5. 项目已有 default workspace 机制

internal/admin/service.go:847,938 使用 s.cfg.DefaultWorkspaceExternalID 标识默认工作区,internal/platformapi/platform_bootstrap_builders.go:122IsDefault bool 字段。归档时应排除默认工作区。

Anthropic 官方文档依据

来源:Workspaces – Claude Platform DocsArchive Workspace – Claude API Reference

归档语义(原文):

Archiving:

  • Preserves historical data for reporting
  • Deactivates the workspace and all associated API keys
  • Cannot be undone

Archiving a workspace immediately revokes all API keys in that workspace. This action cannot be undone.

默认工作区不可归档(原文):

Every organization has a Default Workspace that cannot be renamed, archived, or deleted. The Default Workspace has no ID and doesn't appear in list endpoints.

权限边界(原文):

Only organization admins can create workspaces. Workspaces themselves and organization members are managed at the organization level through the Admin API, which requires an Admin API key (sk-ant-admin…).

端点(原文):

POST /v1/organizations/workspaces/{workspace_id}/archive   (x-api-key: Admin API key)
→ 返回 Workspace 对象(含 archived_at,RFC 3339;未归档为 null)

现状与官方语义的差距

维度 Anthropic 官方 当前实现 差距
删除语义 软删除、不可逆 已有 archived_at 软删除 ✅ 对齐
归档级联 立即吊销该 workspace 所有 API key 归档只盖 workspaces.archived_at,不碰 key;key 查询/鉴权不感知 workspace 归档 ❌ 安全缺口
默认工作区 不可归档 DefaultWorkspaceExternalID 配置,但归档未排除 ⚠️ 缺保护
权限边界 org admin 级(Admin API key) admin 层归档已存在且分层正确,但 console / 前端无入口 ⚠️ 缺入口
端点 POST .../workspaces/{id}/archive admin 层已有;console 层缺失 ⚠️ 缺 console 端点

建议的修复方向(概要)

  1. 在 console 层补 POST /workspaces/{id}/archive(面向 Console 用户),鉴权要求 org admin。
  2. 归档时级联吊销该 workspace 下所有 console_api_keys(设 archived_at = now()),对齐官方「立即吊销所有 API key」。
  3. 禁止归档默认工作区(DefaultWorkspaceExternalID)与当前激活工作区(防自锁)。
  4. 前端 WorkspacesSettingsPage 的 Actions 列改为 DropdownMenu,加「归档」项 + 破坏性确认 AlertDialog(参考 WorkspaceApiKeysPage 的删除=归档范本)。
  5. 同步设计文档与测试。

详细的方案、改动清单、验证计划与待拍板的决策点见下方讨论 comment。

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions