Skip to content

feat: Organization 支持 + namespace 权限隔离#31

Merged
cunoe merged 2 commits intomainfrom
feat/issue-5-6-org-and-namespace-permission
Apr 4, 2026
Merged

feat: Organization 支持 + namespace 权限隔离#31
cunoe merged 2 commits intomainfrom
feat/issue-5-6-org-and-namespace-permission

Conversation

@cunoe
Copy link
Copy Markdown
Contributor

@cunoe cunoe commented Apr 1, 2026

Summary

新增命令

命令 说明
envx org create <name> 创建组织,可选 --display-name
envx org list / envx org ls 列出所属组织
envx org switch <slug> 切换当前组织上下文
envx org current 显示当前选中的组织
envx org members [slug] 查看组织成员

权限错误示例

❌ Permission denied: You don't have access to namespace "acme".
💡 Tip: Check that you have push permission, or ask the namespace owner to grant access.
💡 Tip: Use `envx org list` to see your organizations.

Closes #6
Closes #5

Test plan

  • envx org create test-org 成功创建并自动切换
  • envx org list 显示组织列表,标记当前组织
  • envx org switch 切换上下文并持久化
  • envx org current 显示当前组织
  • envx org members 显示成员列表
  • push/pull 对 403 显示友好权限错误
  • 未认证时所有 org 命令提示先登录

)

Organization support (#6):
- Add `envx org create/list/switch/current/members` commands
- Store current org context in ~/.envx/credentials.json
- Auto-switch to newly created org

Namespace permission isolation (#5):
- Handle 403 Forbidden in push/pull with clear error messages
- Guide users to check permissions and org membership
Copy link
Copy Markdown

@leaperone-bot leaperone-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Code Review 🟡

总体评价

PR 结构清晰,新增了 envx org 命令组和 403 权限错误提示。代码风格与已有的 whoami.ts 等命令保持一致。以下是需要关注的问题:


🔴 关键问题

1. currentOrg 存储了但从未在 push/pull 请求中使用

setCurrentOrg / getCurrentOrg 在 credentials 中持久化了当前组织,但 push.tspull.ts 中的请求完全没有读取或发送 currentOrg(比如作为 header 或 query param)。这意味着:

  • 用户执行 envx org switch acme 后,push / pull 的行为不会有任何变化
  • 组织上下文切换实际上是个"空操作"(只有 org currentorg list 的标记功能用到了它)

如果 namespace 权限隔离依赖服务端识别组织上下文,客户端应该在请求中传递 org 信息(例如 X-Org-Slug header)。否则这个 feature 的核心目标没有实现。


🟡 建议改进

2. requireAuth() 与已有模式不一致

org.ts 中定义了局部的 requireAuth()authHeaders() 辅助函数,但 whoami.tspush.tspull.ts 都是直接调用 getCredential() + 内联构建 headers。建议统一到一处(比如 credentials.ts 里导出一个公共的 requireAuth),避免后续维护多份重复逻辑。

3. 非空断言 data.data! 的安全性

typescript
console.log(chalk.green(✅ Organization "${data.data!.slug}" created successfully));
setCurrentOrg(data.data!.slug);
res.ok && data.success 成功的分支里使用了 data.data!,但 TypeScript 类型定义中 data 是 optional (data?)。虽然逻辑上服务端应该返回 data,但更健壮的做法是做一次判空:

if (!res.ok || !data.success || !data.data) { ... }

这样后续就不需要 ! 断言了。这个问题在 createswitch 两处都存在。

4. 缺少测试

PR 描述中有 Test plan checklist,但全是手动测试项。作为一个新增的完整命令模块(240 行),建议至少增加单元测试覆盖核心路径(如 setCurrentOrg/getCurrentOrg 的持久化逻辑、各命令的 error handling 分支)。

5. org create 自动 switch 没有告知用户是否需要确认

创建组织后自动 setCurrentOrg,这在多数场景下合理,但如果用户已经在某个组织上下文中工作,自动切换可能出乎意料。可以考虑加个 --no-switch 选项,或至少在切换前显示"从 X 切换到 Y"的信息。

6. org members 缺少分页支持

如果组织成员很多,一次性全量拉取可能有性能问题。建议后续考虑分页参数。


✅ 做得好的地方

  • URL 中正确使用了 encodeURIComponent(slug) 防止注入
  • 403 错误提示信息清晰且有引导性
  • spinner 在 error 路径下也正确 stop 了
  • 命令结构(create/list/switch/current/members)设计合理

总结:最核心的疑问是 currentOrg 是否需要在 push/pull 请求中传递给服务端。如果当前服务端纯靠 namespace 路径来做权限判断,那 org context 在 CLI 侧只是个"标签"功能,这需要明确。其余问题不阻塞合并但建议跟进。

@cunoe cunoe merged commit f480a3f into main Apr 4, 2026
1 of 2 checks passed
@leaperone-bot leaperone-bot deleted the feat/issue-5-6-org-and-namespace-permission branch April 4, 2026 04:09
Copy link
Copy Markdown

@leaperone-bot leaperone-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Code Review 🟡

PR 审查:feat: Organization 支持 + namespace 权限隔离

整体来看,这是一个结构清晰的 PR,新增了 envx org 命令组并为 push/pull 添加了 403 权限提示。代码风格与现有代码基本一致,但有以下值得注意的问题:

🔶 中等问题

1. currentOrg 存储了但从未在 push/pull 请求中使用

setCurrentOrg() / getCurrentOrg() 在 credentials 中持久化了当前组织上下文,但 push.tspull.ts 在构建 API 请求时完全没有读取或发送 currentOrg。这意味着:

  • 用户执行 envx org switch acme 后,push/pull 行为不会有任何变化
  • currentOrg 目前只在 org list 标记当前组织和 org members 作为默认参数时使用

这可能是有意为之(等待后续 PR 接入),但如果是这样,建议在 PR 描述或代码注释中明确说明,避免用户误解 org switch 的作用范围。

2. org create 命令中 --name 选项与位置参数命名冲突

typescript
.command('create ')
.option('-n, --name ', 'Display name for the organization')
位置参数叫 name--name 选项也叫 name(PR 描述里写的是 --display-name,但实际代码是 --name)。这可能让用户困惑:位置参数实际是 slug--name 才是显示名称。建议:

  • 将命令改为 create <slug>(虽然 action 参数名已经是 slug,但命令帮助文本显示的是 <name>
  • 或将选项改为 --display-name

3. requireAuthauthHeaders 是重复的工具函数

whoami.tslogin.ts 等已有类似的认证检查和 header 构建逻辑(虽然是内联的)。org.ts 中提取成了 requireAuth()authHeaders() 独立函数,但它们是模块私有的。随着命令增多,建议将这些抽取到 utils/ 中统一复用,减少重复代码。

🟡 小问题

4. 非空断言 data.data! 的使用

console.log(chalk.green(`✅ Organization "${data.data!.slug}" created successfully`));

org create 中在检查 !data.success 后使用了 data.data! 非空断言。虽然逻辑上 data.success === truedata.data 应该存在,但类型定义中 data 是可选的(data?: {...})。更安全的做法是提前赋值并做 guard check:

if (!res.ok || !data.success || !data.data) { ... }
const org = data.data;

5. 缺少测试

整个仓库似乎没有测试文件。虽然这不是本 PR 引入的问题,但新增了 5 个子命令和 2 个工具函数(getCurrentOrg/setCurrentOrg),至少 credentials.ts 的新函数值得添加单元测试。

✅ 做得好的地方

  • encodeURIComponent(slug) 正确处理了 URL 中的特殊字符
  • 403 错误提示信息友好且有 actionable tips
  • org switch 会先验证远程组织存在性再写入本地
  • spinner 在所有 error path 中都正确 stop 了
  • 文件权限 0o600 保护 credentials 文件(已有逻辑,未被破坏)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Organization 支持 namespace 权限隔离 — 关联用户/组织

2 participants