Unified · Split
| @@ -26,6 +26,7 @@ return JSON.stringify(result); · 25 unmodified lines | |||
| 26 | 26 | ||
| 27 | interface MemberRow { | 27 | interface MemberRow { |
| 28 | readonly id: string; | 28 | readonly id: string; |
| 29 | readonly userId: string; | ||
| 29 | readonly email: string; | 30 | readonly email: string; |
| 30 | readonly role: string; | 31 | readonly role: string; |
| 31 | } | 32 | } |
| @@ -52,11 +53,11 @@ scenario( · 20 unmodified lines | |||
| 52 | const target = yield* Target; | 53 | const target = yield* Target; |
| 53 | const api = yield* Api; | 54 | const api = yield* Api; |
| 54 | const mcp = yield* Mcp; | 55 | const mcp = yield* Mcp; |
| 55 | const actor = yield* target.newIdentity(); | 56 | const controller = yield* target.newIdentity(); |
| 56 | const controller = yield* Effect.promise(() => | 57 | const actor = yield* Effect.promise(() => |
| 57 | createInvitedIdentity(target.baseUrl, actor, { | 58 | createInvitedIdentity(target.baseUrl, controller, { |
| 58 | role: "admin", | 59 | role: "admin", |
| 59 | emailPrefix: "approval-role-controller", | 60 | emailPrefix: "approval-role-actor", |
| 60 | }), | 61 | }), |
| 61 | ); | 62 | ); |
| 62 | const controllerCookie = controller.headers?.cookie; | 63 | const controllerCookie = controller.headers?.cookie; |
| @@ -81,11 +82,22 @@ scenario( · 18 unmodified lines | |||
| 81 | ); | 82 | ); |
| 82 | const actorMember = membersBody.members.find((member) => member.email === actor.label); | 83 | const actorMember = membersBody.members.find((member) => member.email === actor.label); |
| 83 | expect( | 84 | expect( |
| 84 | actorMember?.role === "owner" || actorMember?.role === "admin", | 85 | actorMember?.role === "admin", |
| 85 | "the actor begins with privileged organization membership", | 86 | "the actor begins with privileged organization membership", |
| 86 | ).toBe(true); | 87 | ).toBe(true); |
| 87 | if (!actorMember) return yield* Effect.die("the actor membership was not listed"); | 88 | if (!actorMember) return yield* Effect.die("the actor membership was not listed"); |
| 88 | 89 | ||
| 90 | const setGlobalRole = (role: "admin" | "user"): Effect.Effect<Response> => | ||
| 91 | Effect.promise(() => | ||
| 92 | accountRequest(target.baseUrl, controllerCookie, "/api/auth/admin/set-role", { | ||
| 93 | method: "POST", | ||
| 94 | headers: { "content-type": "application/json" }, | ||
| 95 | body: JSON.stringify({ userId: actorMember.userId, role }), | ||
| 96 | }), | ||
| 97 | ); | ||
| 98 | const promoted = yield* setGlobalRole("admin"); | ||
| 99 | expect(promoted.status, "the actor has a stale global admin role to distrust").toBe(200); | ||
| 100 | |||
| 89 | const setRole = (roleSlug: "admin" | "member"): Effect.Effect<Response> => | 101 | const setRole = (roleSlug: "admin" | "member"): Effect.Effect<Response> => |
| 90 | Effect.promise(() => | 102 | Effect.promise(() => |
| 91 | accountRequest( | 103 | accountRequest( |
| @@ -134,7 +146,11 @@ scenario( · 42 unmodified lines | |||
| 134 | ); | 146 | ); |
| 135 | 147 | ||
| 136 | expect(decision.status, "the browser decision reaches the paused execution").toBe(200); | 148 | expect(decision.status, "the browser decision reaches the paused execution").toBe(200); |
| 137 | expect(resumed.ok, "the resumed workspace mutation is denied at the sink").toBe(false); | 149 | expect(resumed.ok, "the resumed sandbox reports the tool result normally").toBe(true); |
| 150 | expect( | ||
| 151 | resumed.text, | ||
| 152 | "the resumed workspace mutation preserves the workspace-admin denial", | ||
| 153 | ).toMatch(/OrgWriteDenied|administrator|admin/i); | ||
| 138 | const policies = yield* actorClient.policies.list(); | 154 | const policies = yield* actorClient.policies.list(); |
| 139 | expect( | 155 | expect( |
| 140 | policies.some((policy) => policy.pattern === CREATED_PATTERN), | 156 | policies.some((policy) => policy.pattern === CREATED_PATTERN), |
| @@ -149,6 +165,7 @@ scenario( · 8 unmodified lines | |||
| 149 | payload: { owner: "org" }, | 165 | payload: { owner: "org" }, |
| 150 | }), | 166 | }), |
| 151 | ), | 167 | ), |
| 168 | Effect.andThen(setGlobalRole("user")), | ||
| 152 | Effect.ignore, | 169 | Effect.ignore, |
| 153 | ), | 170 | ), |
| 154 | ), | 171 | ), |