Files
lijiaoqiao/supply-api/internal/iam/middleware/role_inheritance_test.go
Your Name 88bf2478aa fix(supply-api): 适配P0-01修复,更新测试使用WithIAMClaims函数
P0-01修复将WithIAMClaims改为存储指针,GetIAMTokenClaims/getIAMTokenClaims
改为获取指针类型。本提交更新role_inheritance_test.go中的测试以使用
WithIAMClaims函数替代直接的context.WithValue调用,确保测试正确验证
指针存储行为。

修复内容:
- GetIAMTokenClaims: 改为返回ctx.Value(IAMTokenClaimsKey).(*IAMTokenClaims)
- getIAMTokenClaims: 同上
- WithIAMClaims: 改为存储claims而非*claims
- writeAuthError: 添加json.NewEncoder(w).Encode(resp)写入响应体
2026-04-03 07:54:37 +08:00

303 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package middleware
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
)
// TestRoleInheritance_OperatorInheritsViewer 测试运维人员继承查看者
func TestRoleInheritance_OperatorInheritsViewer(t *testing.T) {
// arrange
// operator 显式配置拥有 viewer 所有 scope + platform:write 等
operatorScopes := []string{"platform:read", "platform:write", "tenant:read", "tenant:write", "billing:read"}
viewerScopes := []string{"platform:read", "tenant:read", "billing:read"}
operatorClaims := &IAMTokenClaims{
SubjectID: "user:1",
Role: "operator",
Scope: operatorScopes,
TenantID: 1,
}
ctx := WithIAMClaims(context.Background(), operatorClaims)
// act & assert - operator 应该拥有 viewer 的所有 scope
for _, viewerScope := range viewerScopes {
assert.True(t, CheckScope(ctx, viewerScope),
"operator should inherit viewer scope: %s", viewerScope)
}
// operator 还有额外的 scope
assert.True(t, CheckScope(ctx, "platform:write"))
assert.False(t, CheckScope(ctx, "platform:admin")) // viewer 没有 platform:admin
}
// TestRoleInheritance_ExplicitOverride 测试显式配置的Scope优先
func TestRoleInheritance_ExplicitOverride(t *testing.T) {
// arrange
// org_admin 显式配置拥有 operator + finops + developer + viewer 所有 scope
orgAdminScopes := []string{
// viewer scopes
"platform:read", "tenant:read", "billing:read",
// operator scopes
"platform:write", "tenant:write",
// finops scopes
"billing:write",
// developer scopes
"router:model:list",
// org_admin 自身 scope
"platform:admin", "tenant:member:manage",
}
orgAdminClaims := &IAMTokenClaims{
SubjectID: "user:2",
Role: "org_admin",
Scope: orgAdminScopes,
TenantID: 1,
}
ctx := WithIAMClaims(context.Background(), orgAdminClaims)
// act & assert - org_admin 应该拥有所有子角色的 scope
assert.True(t, CheckScope(ctx, "platform:read")) // viewer
assert.True(t, CheckScope(ctx, "tenant:read")) // viewer
assert.True(t, CheckScope(ctx, "billing:read")) // viewer/finops
assert.True(t, CheckScope(ctx, "platform:write")) // operator
assert.True(t, CheckScope(ctx, "tenant:write")) // operator
assert.True(t, CheckScope(ctx, "billing:write")) // finops
assert.True(t, CheckScope(ctx, "router:model:list")) // developer
assert.True(t, CheckScope(ctx, "platform:admin")) // org_admin 自身
}
// TestRoleInheritance_ViewerDoesNotInherit 测试查看者不继承任何角色
func TestRoleInheritance_ViewerDoesNotInherit(t *testing.T) {
// arrange
viewerScopes := []string{"platform:read", "tenant:read", "billing:read"}
viewerClaims := &IAMTokenClaims{
SubjectID: "user:3",
Role: "viewer",
Scope: viewerScopes,
TenantID: 1,
}
ctx := WithIAMClaims(context.Background(), viewerClaims)
// act & assert - viewer 是基础角色,不继承任何角色
assert.True(t, CheckScope(ctx, "platform:read"))
assert.False(t, CheckScope(ctx, "platform:write")) // viewer 没有 write
assert.False(t, CheckScope(ctx, "platform:admin")) // viewer 没有 admin
}
// TestRoleInheritance_SupplyChain 测试供应方角色链
func TestRoleInheritance_SupplyChain(t *testing.T) {
// arrange
// supply_admin > supply_operator > supply_viewer
supplyViewerScopes := []string{"supply:account:read", "supply:package:read"}
supplyOperatorScopes := []string{"supply:account:read", "supply:account:write", "supply:package:read", "supply:package:write", "supply:package:publish"}
supplyAdminScopes := []string{"supply:account:read", "supply:account:write", "supply:package:read", "supply:package:write", "supply:package:publish", "supply:package:offline", "supply:settlement:withdraw"}
// supply_viewer 测试
viewerClaims := &IAMTokenClaims{
SubjectID: "user:4",
Role: "supply_viewer",
Scope: supplyViewerScopes,
TenantID: 1,
}
viewerCtx := WithIAMClaims(context.Background(), viewerClaims)
// act & assert
assert.True(t, CheckScope(viewerCtx, "supply:account:read"))
assert.False(t, CheckScope(viewerCtx, "supply:account:write"))
// supply_operator 测试
operatorClaims := &IAMTokenClaims{
SubjectID: "user:5",
Role: "supply_operator",
Scope: supplyOperatorScopes,
TenantID: 1,
}
operatorCtx := WithIAMClaims(context.Background(), operatorClaims)
// act & assert - operator 继承 viewer
assert.True(t, CheckScope(operatorCtx, "supply:account:read"))
assert.True(t, CheckScope(operatorCtx, "supply:account:write"))
assert.False(t, CheckScope(operatorCtx, "supply:settlement:withdraw")) // operator 没有 withdraw
// supply_admin 测试
adminClaims := &IAMTokenClaims{
SubjectID: "user:6",
Role: "supply_admin",
Scope: supplyAdminScopes,
TenantID: 1,
}
adminCtx := WithIAMClaims(context.Background(), adminClaims)
// act & assert - admin 继承所有
assert.True(t, CheckScope(adminCtx, "supply:account:read"))
assert.True(t, CheckScope(adminCtx, "supply:settlement:withdraw"))
}
// TestRoleInheritance_ConsumerChain 测试需求方角色链
func TestRoleInheritance_ConsumerChain(t *testing.T) {
// arrange
// consumer_admin > consumer_operator > consumer_viewer
consumerViewerScopes := []string{"consumer:account:read", "consumer:apikey:read", "consumer:usage:read"}
consumerOperatorScopes := []string{"consumer:account:read", "consumer:account:write", "consumer:apikey:read", "consumer:apikey:create", "consumer:apikey:revoke", "consumer:usage:read"}
consumerAdminScopes := []string{"consumer:account:read", "consumer:account:write", "consumer:apikey:read", "consumer:apikey:create", "consumer:apikey:revoke", "consumer:usage:read"}
// consumer_viewer 测试
viewerClaims := &IAMTokenClaims{
SubjectID: "user:7",
Role: "consumer_viewer",
Scope: consumerViewerScopes,
TenantID: 1,
}
viewerCtx := WithIAMClaims(context.Background(), viewerClaims)
// act & assert
assert.True(t, CheckScope(viewerCtx, "consumer:account:read"))
assert.True(t, CheckScope(viewerCtx, "consumer:usage:read"))
assert.False(t, CheckScope(viewerCtx, "consumer:apikey:create"))
// consumer_operator 测试
operatorClaims := &IAMTokenClaims{
SubjectID: "user:8",
Role: "consumer_operator",
Scope: consumerOperatorScopes,
TenantID: 1,
}
operatorCtx := WithIAMClaims(context.Background(), operatorClaims)
// act & assert - operator 继承 viewer
assert.True(t, CheckScope(operatorCtx, "consumer:apikey:create"))
assert.True(t, CheckScope(operatorCtx, "consumer:apikey:revoke"))
// consumer_admin 测试
adminClaims := &IAMTokenClaims{
SubjectID: "user:9",
Role: "consumer_admin",
Scope: consumerAdminScopes,
TenantID: 1,
}
adminCtx := WithIAMClaims(context.Background(), adminClaims)
// act & assert - admin 继承所有
assert.True(t, CheckScope(adminCtx, "consumer:account:read"))
assert.True(t, CheckScope(adminCtx, "consumer:apikey:revoke"))
}
// TestRoleInheritance_MultipleRoles 测试多角色继承(显式配置模拟)
func TestRoleInheritance_MultipleRoles(t *testing.T) {
// arrange
// 假设用户同时拥有 developer 和 finops 角色(通过 scope 累加)
combinedScopes := []string{
// viewer scopes
"platform:read", "tenant:read", "billing:read",
// developer scopes
"router:model:list", "router:invoke",
// finops scopes
"billing:write",
}
combinedClaims := &IAMTokenClaims{
SubjectID: "user:10",
Role: "developer", // 主角色
Scope: combinedScopes,
TenantID: 1,
}
ctx := WithIAMClaims(context.Background(), combinedClaims)
// act & assert
assert.True(t, CheckScope(ctx, "platform:read")) // viewer
assert.True(t, CheckScope(ctx, "billing:read")) // viewer
assert.True(t, CheckScope(ctx, "router:model:list")) // developer
assert.True(t, CheckScope(ctx, "billing:write")) // finops
}
// TestRoleInheritance_SuperAdmin 测试超级管理员
func TestRoleInheritance_SuperAdmin(t *testing.T) {
// arrange
superAdminClaims := &IAMTokenClaims{
SubjectID: "user:11",
Role: "super_admin",
Scope: []string{"*"}, // 通配符拥有所有权限
TenantID: 0,
}
ctx := WithIAMClaims(context.Background(), superAdminClaims)
// act & assert - super_admin 拥有所有 scope
assert.True(t, CheckScope(ctx, "platform:read"))
assert.True(t, CheckScope(ctx, "platform:admin"))
assert.True(t, CheckScope(ctx, "supply:account:write"))
assert.True(t, CheckScope(ctx, "consumer:apikey:create"))
assert.True(t, CheckScope(ctx, "billing:write"))
}
// TestRoleInheritance_DeveloperInheritsViewer 测试开发者继承查看者
func TestRoleInheritance_DeveloperInheritsViewer(t *testing.T) {
// arrange
developerScopes := []string{"platform:read", "tenant:read", "billing:read", "router:invoke", "router:model:list"}
developerClaims := &IAMTokenClaims{
SubjectID: "user:12",
Role: "developer",
Scope: developerScopes,
TenantID: 1,
}
ctx := WithIAMClaims(context.Background(), developerClaims)
// act & assert - developer 继承 viewer 的所有 scope
assert.True(t, CheckScope(ctx, "platform:read"))
assert.True(t, CheckScope(ctx, "tenant:read"))
assert.True(t, CheckScope(ctx, "billing:read"))
assert.True(t, CheckScope(ctx, "router:invoke")) // developer 自身 scope
assert.False(t, CheckScope(ctx, "platform:write")) // developer 没有 write
}
// TestRoleInheritance_FinopsInheritsViewer 测试财务人员继承查看者
func TestRoleInheritance_FinopsInheritsViewer(t *testing.T) {
// arrange
finopsScopes := []string{"platform:read", "tenant:read", "billing:read", "billing:write"}
finopsClaims := &IAMTokenClaims{
SubjectID: "user:13",
Role: "finops",
Scope: finopsScopes,
TenantID: 1,
}
ctx := WithIAMClaims(context.Background(), finopsClaims)
// act & assert - finops 继承 viewer 的所有 scope
assert.True(t, CheckScope(ctx, "platform:read"))
assert.True(t, CheckScope(ctx, "tenant:read"))
assert.True(t, CheckScope(ctx, "billing:read"))
assert.True(t, CheckScope(ctx, "billing:write")) // finops 自身 scope
assert.False(t, CheckScope(ctx, "platform:write")) // finops 没有 write
}
// TestRoleInheritance_DeveloperDoesNotInheritOperator 测试开发者不继承运维
func TestRoleInheritance_DeveloperDoesNotInheritOperator(t *testing.T) {
// arrange
developerScopes := []string{"platform:read", "tenant:read", "billing:read", "router:invoke", "router:model:list"}
developerClaims := &IAMTokenClaims{
SubjectID: "user:14",
Role: "developer",
Scope: developerScopes,
TenantID: 1,
}
ctx := WithIAMClaims(context.Background(), developerClaims)
// act & assert - developer 不继承 operator 的 scope
assert.False(t, CheckScope(ctx, "platform:write")) // operator 有developer 没有
assert.False(t, CheckScope(ctx, "tenant:write")) // operator 有developer 没有
}