package user import ( "errors" "testing" "perms-system-server/internal/consts" "perms-system-server/internal/loaders" userModel "perms-system-server/internal/model/user" "perms-system-server/internal/response" "perms-system-server/internal/svc" "perms-system-server/internal/testutil" "perms-system-server/internal/testutil/ctxhelper" "perms-system-server/internal/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // --------------------------------------------------------------------------- // 覆盖目标:审计 H-3 修复 —— "不能分配与自己同级(或更高)的角色"。 // 修复前代码仅拦 `>` 严格高于,允许 MEMBER 调用者把同级角色分配给别人,继而下一次 BindRoles 时 // 由于同级权限集相同,可用后续 upgrade 路径放大;修复后变为 `<=`(含同级)拦截。 // 本文件作为"同级也必须 403"的契约锚点。 // --------------------------------------------------------------------------- // TC-0813: H-3 —— MEMBER 调用者不能分配与自己同 permsLevel 的角色。 func TestBindRoles_EqualPermsLevel_Rejected(t *testing.T) { svcCtx := svc.NewServiceContext(testutil.GetTestConfig()) conn := testutil.GetTestSqlConn() superCtx := ctxhelper.SuperAdminCtx() deptId, deptPath, cleanupDept := setupDeptForCaller(t, svcCtx) t.Cleanup(cleanupDept) productCode := "test_product" username := testutil.UniqueId() targetUserId := insertTestUserFull(t, superCtx, &userModel.SysUser{ Username: username, Password: testutil.HashPassword("pass"), Nickname: "tgt_eq", DeptId: deptId, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: 2, Status: consts.StatusEnabled, }) mId := insertTestMember(t, svcCtx, productCode, targetUserId) const callerLevel int64 = 50 sameLevelRole := insertTestRoleWithLevel(t, svcCtx, productCode, consts.StatusEnabled, callerLevel) t.Cleanup(func() { testutil.CleanTableByField(superCtx, conn, "`sys_user_role`", "userId", targetUserId) testutil.CleanTable(superCtx, conn, "`sys_product_member`", mId) testutil.CleanTable(superCtx, conn, "`sys_user`", targetUserId) testutil.CleanTable(superCtx, conn, "`sys_role`", sameLevelRole) }) ctx := ctxhelper.CustomCtx(&loaders.UserDetails{ UserId: 999994, Username: "member_eq_level", IsSuperAdmin: false, MemberType: consts.MemberTypeMember, Status: consts.StatusEnabled, ProductCode: productCode, DeptId: deptId, DeptPath: deptPath, MinPermsLevel: callerLevel, }) err := NewBindRolesLogic(ctx, svcCtx).BindRoles(&types.BindRolesReq{ UserId: targetUserId, RoleIds: []int64{sameLevelRole}, }) require.Error(t, err, "H-3 防线:同级角色分配必须被拒绝(含同级)") var ce *response.CodeError require.True(t, errors.As(err, &ce)) assert.Equal(t, 403, ce.Code()) assert.Contains(t, ce.Error(), "不能分配权限级别高于自身的角色", "错误消息应当明确点出'含同级'的拦截语义") // 同时验证 DB 未产生任何 user-role 关系。 rids, err := svcCtx.SysUserRoleModel.FindRoleIdsByUserIdForProduct(ctx, targetUserId, productCode) require.NoError(t, err) assert.Empty(t, rids, "被拒绝的 BindRoles 不得落地任何行") }