| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 |
- package auth
- import (
- "context"
- "os"
- "testing"
- "perms-system-server/internal/consts"
- "perms-system-server/internal/loaders"
- "perms-system-server/internal/middleware"
- "perms-system-server/internal/response"
- "perms-system-server/internal/svc"
- "perms-system-server/internal/testutil"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- )
- // ---------------------------------------------------------------------------
- // 审计 L-3(第 8 轮仍未落地)—— checkDeptHierarchy 对 caller.DeptId=0 / DeptPath=""
- // 的历史 MEMBER / DEVELOPER 账号直接 403。
- //
- // 契约期望(fix 后):历史账号任意一次管理动作时,CheckManageAccess 要么走
- // (a) 明确的"未归属部门,拒绝管理他人"403(当前行为,方向正确但文案 / 审计缺失)
- // (b) 自动把缺失部门挪到默认部门 → 正常走部门链校验
- // 无论走 (a) 还是 (b),都需要有 **response.CodeError 结构** 而不是普通 string error,
- // 否则前端做不到"按错误码触发数据迁移工单"。
- //
- // 本测试用 skipPending 标签,方便 report 识别未落地审计项;fix 落地(或数据迁移脚本
- // 跑完)后把 AUDIT_RUN_PENDING=1 打开并调整断言即可切换成真正的回归保护。
- // ---------------------------------------------------------------------------
- const auditPendingEnv = "AUDIT_RUN_PENDING"
- func skipPending(t *testing.T, marker, reason string) {
- t.Helper()
- if os.Getenv(auditPendingEnv) != "" {
- return
- }
- t.Skipf("AUDIT_PENDING %s (Round 8 fix 未落地) —— %s", marker, reason)
- }
- // TC-0993: 历史 DEVELOPER(DeptId=0)对合法目标的管理操作 —— fix 后必须是
- // 可识别的 response.CodeError,且带有迁移提示("您未归属任何部门"),让运维据此跑数据迁移。
- func TestCheckManageAccess_L3_LegacyDeveloperWithDeptZero_MustReturnCodedError(t *testing.T) {
- skipPending(t, "L-3",
- "当前返回 403 但文案分叉('您未归属任何部门' / '您的部门信息异常'),审计建议"+
- "合一为 '您未归属任何部门' 且带 CodeError.Code=403;fix 落地后移除 Skip")
- ctx := context.Background()
- svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
- // caller 是 legacy developer,DeptId=0 / DeptPath=""。
- callerCtx := middleware.WithUserDetails(ctx, &loaders.UserDetails{
- UserId: 999001, Username: "legacy_dev", IsSuperAdmin: false,
- MemberType: consts.MemberTypeDeveloper, Status: consts.StatusEnabled,
- ProductCode: "test_product",
- // DeptId=0, DeptPath="" —— legacy 账号
- })
- err := CheckManageAccess(callerCtx, svcCtx, 999002 /* target */, "test_product")
- require.Error(t, err, "L-3:legacy caller 必须被拒绝")
- var ce *response.CodeError
- require.ErrorAs(t, err, &ce, "L-3:必须是 response.CodeError,不得为裸 error(前端无法据此触发迁移)")
- assert.Equal(t, 403, ce.Code(), "L-3:必须是 403 以便前端分类")
- assert.Contains(t, ce.Error(), "未归属",
- "L-3:文案必须显式提示'未归属任何部门',便于人工判定是否需要跑数据迁移")
- }
|