Skip to content

Commit

Permalink
feat: granular permission assignment for organization members (#6231)
Browse files Browse the repository at this point in the history
  • Loading branch information
n1ru4l authored Jan 29, 2025
1 parent 946ba18 commit b7e4052
Show file tree
Hide file tree
Showing 75 changed files with 5,718 additions and 2,556 deletions.
16 changes: 16 additions & 0 deletions .changeset/tall-islands-occur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
'hive': major
---

Introduce new permission system for organization member roles.

The existing scopes assigned to organization member users are now replaced with permissions.
Using the permissions allows more granular access control to features in Hive.

This introduces the following breaking changes:

- Organization members with the default `Viewer` role, will experience downgraded permissions. They will no longer be able to create targets or projects.
- Organization member roles permissions for inviting, removing or assigning roles have been revoked. A organization admin will have to re-apply the permissions to the desired member roles.
- Organization members with permissions for managing invites, removing members, assigning roles or modifying roles are no longer restrained in granting more rights to other users. Please be aware when granting these permissions to a user role. We recommend only assigning these to member roles that are considered "Admin" user roles.

A future update will introduce resource based access control (based on project, target, service or app deployments) for organization members.
31 changes: 13 additions & 18 deletions integration-tests/testkit/flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ export function createOrganization(input: CreateOrganizationInput, authToken: st
slug
owner {
id
organizationAccessScopes
projectAccessScopes
targetAccessScopes
role {
id
permissions
}
}
memberRoles {
id
Expand Down Expand Up @@ -178,9 +179,11 @@ export function joinOrganization(code: string, authToken: string) {
user {
id
}
organizationAccessScopes
projectAccessScopes
targetAccessScopes
role {
id
name
permissions
}
}
}
}
Expand Down Expand Up @@ -213,10 +216,8 @@ export function getOrganizationMembers(selector: OrganizationSelectorInput, auth
role {
id
name
permissions
}
organizationAccessScopes
projectAccessScopes
targetAccessScopes
}
}
}
Expand Down Expand Up @@ -664,9 +665,7 @@ export function createMemberRole(input: CreateMemberRoleInput, authToken: string
name
description
locked
organizationAccessScopes
projectAccessScopes
targetAccessScopes
permissions
}
}
}
Expand Down Expand Up @@ -724,9 +723,7 @@ export function deleteMemberRole(input: DeleteMemberRoleInput, authToken: string
name
description
locked
organizationAccessScopes
projectAccessScopes
targetAccessScopes
permissions
}
}
}
Expand Down Expand Up @@ -754,9 +751,7 @@ export function updateMemberRole(input: UpdateMemberRoleInput, authToken: string
name
description
locked
organizationAccessScopes
projectAccessScopes
targetAccessScopes
permissions
}
}
error {
Expand Down
30 changes: 12 additions & 18 deletions integration-tests/testkit/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import {
updateMemberRole,
updateTargetValidationSettings,
} from './flow';
import * as GraphQLSchema from './gql/graphql';
import {
BreakingChangeFormula,
OrganizationAccessScope,
Expand Down Expand Up @@ -185,10 +186,10 @@ export function initSeed() {

return members;
},
async projects() {
async projects(token = ownerToken) {
const projectsResult = await getOrganizationProjects(
{ organizationSlug: organization.slug },
ownerToken,
token,
).then(r => r.expectNoGraphQLErrors());

const projects = projectsResult.organization?.organization.projects.nodes;
Expand Down Expand Up @@ -806,6 +807,7 @@ export function initSeed() {
input: {
roleId: string;
userId: string;
resources?: GraphQLSchema.ResourceAssignmentInput;
},
options: { useMemberToken?: boolean } = {
useMemberToken: false,
Expand All @@ -816,6 +818,10 @@ export function initSeed() {
organizationSlug: organization.slug,
userId: input.userId,
roleId: input.roleId,
resources: input.resources ?? {
mode: GraphQLSchema.ResourceAssignmentMode.All,
projects: [],
},
},
options.useMemberToken ? memberToken : ownerToken,
).then(r => r.expectNoGraphQLErrors());
Expand Down Expand Up @@ -847,11 +853,7 @@ export function initSeed() {
return memberRoleDeletionResult.deleteMemberRole.ok?.updatedOrganization;
},
async createMemberRole(
scopes: {
organization: OrganizationAccessScope[];
project: ProjectAccessScope[];
target: TargetAccessScope[];
},
permissions: Array<string>,
options: { useMemberToken?: boolean } = {
useMemberToken: false,
},
Expand All @@ -867,9 +869,7 @@ export function initSeed() {
organizationSlug: organization.slug,
name,
description: 'some description',
organizationAccessScopes: scopes.organization,
projectAccessScopes: scopes.project,
targetAccessScopes: scopes.target,
selectedPermissions: permissions,
},
options.useMemberToken ? memberToken : ownerToken,
).then(r => r.expectNoGraphQLErrors());
Expand Down Expand Up @@ -908,11 +908,7 @@ export function initSeed() {
name: string;
description: string;
},
scopes: {
organization: OrganizationAccessScope[];
project: ProjectAccessScope[];
target: TargetAccessScope[];
},
permissions: Array<string>,
options: { useMemberToken?: boolean } = {
useMemberToken: false,
},
Expand All @@ -923,9 +919,7 @@ export function initSeed() {
roleId: role.id,
name: role.name,
description: role.description,
organizationAccessScopes: scopes.organization,
projectAccessScopes: scopes.project,
targetAccessScopes: scopes.target,
selectedPermissions: permissions,
},
options.useMemberToken ? memberToken : ownerToken,
).then(r => r.expectNoGraphQLErrors());
Expand Down
Loading

0 comments on commit b7e4052

Please sign in to comment.