feat: first iteration changes for sub org routers

This commit is contained in:
=
2025-10-20 18:57:03 +05:30
parent 00c19455af
commit ef6282968b
23 changed files with 529 additions and 77 deletions
@@ -15,6 +15,11 @@ export enum OrgPermissionActions {
Delete = "delete"
}
export enum OrgPermissionChildOrgActions {
Create = "create",
DirectAccess = "direct-access"
}
export enum OrgPermissionAppConnectionActions {
Read = "read",
Create = "create",
@@ -117,7 +122,8 @@ export enum OrgPermissionSubjects {
Kmip = "kmip",
Gateway = "gateway",
Relay = "relay",
SecretShare = "secret-share"
SecretShare = "secret-share",
ChildOrganization = "child-organization"
}
export type AppConnectionSubjectFields = {
@@ -128,6 +134,7 @@ export type OrgPermissionSet =
| [OrgPermissionActions.Create, OrgPermissionSubjects.Workspace]
| [OrgPermissionActions.Create, OrgPermissionSubjects.Project]
| [OrgPermissionActions, OrgPermissionSubjects.Role]
| [OrgPermissionChildOrgActions, OrgPermissionSubjects.ChildOrganization]
| [OrgPermissionActions, OrgPermissionSubjects.Member]
| [OrgPermissionActions, OrgPermissionSubjects.Settings]
| [OrgPermissionActions, OrgPermissionSubjects.IncidentAccount]
@@ -185,6 +192,12 @@ export const OrgPermissionSchema = z.discriminatedUnion("subject", [
subject: z.literal(OrgPermissionSubjects.Role).describe("The entity this permission pertains to."),
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionActions).describe("Describe what action an entity can take.")
}),
z.object({
subject: z.literal(OrgPermissionSubjects.ChildOrganization).describe("The entity this permission pertains to."),
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionChildOrgActions).describe(
"Describe what action an entity can take."
)
}),
z.object({
subject: z.literal(OrgPermissionSubjects.Member).describe("The entity this permission pertains to."),
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionActions).describe("Describe what action an entity can take.")
@@ -308,6 +321,10 @@ const buildAdminPermission = () => {
// ws permissions
can(OrgPermissionActions.Create, OrgPermissionSubjects.Workspace);
can(OrgPermissionActions.Create, OrgPermissionSubjects.Project);
can(OrgPermissionChildOrgActions.Create, OrgPermissionSubjects.ChildOrganization);
can(OrgPermissionChildOrgActions.DirectAccess, OrgPermissionSubjects.ChildOrganization);
// role permission
can(OrgPermissionActions.Read, OrgPermissionSubjects.Role);
can(OrgPermissionActions.Create, OrgPermissionSubjects.Role);
@@ -19,6 +19,7 @@ interface TPermissionDataReturn extends TMemberships {
orgAuthEnforced?: boolean | null;
orgGoogleSsoAuthEnforced?: boolean | null;
shouldUseNewPrivilegeSystem?: boolean | null;
parentOrgId?: boolean | null;
bypassOrgAuthEnabled?: boolean | null;
roles: {
id: string;
@@ -273,7 +274,8 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => {
db.ref("shouldUseNewPrivilegeSystem").withSchema(TableName.Organization),
db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"),
db.ref("googleSsoAuthEnforced").withSchema(TableName.Organization).as("orgGoogleSsoAuthEnforced"),
db.ref("bypassOrgAuthEnabled").withSchema(TableName.Organization).as("bypassOrgAuthEnabled")
db.ref("bypassOrgAuthEnabled").withSchema(TableName.Organization).as("bypassOrgAuthEnabled"),
db.ref("parentOrgId").withSchema(TableName.Organization).as("parentOrgId")
);
const data = sqlNestRelationships({
@@ -283,6 +285,7 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => {
MembershipsSchema.extend({
orgAuthEnforced: z.boolean().optional().nullable(),
shouldUseNewPrivilegeSystem: z.boolean().optional().nullable(),
parentOrgId: z.boolean().optional().nullable(),
orgGoogleSsoAuthEnforced: z.boolean(),
bypassOrgAuthEnabled: z.boolean()
}).parse(el),
@@ -2,7 +2,7 @@ import { MongoAbility } from "@casl/ability";
import { MongoQuery } from "@ucast/mongo2js";
import { Knex } from "knex";
import { ActionProjectType, TMemberships } from "@app/db/schemas";
import { ActionProjectType, OrganizationActionScope, TMemberships } from "@app/db/schemas";
import { ActorAuthMethod, ActorType } from "@app/services/auth/auth-type";
import { OrgPermissionSet } from "./org-permission";
@@ -18,21 +18,6 @@ export type TBuildOrgPermissionDTO = {
role: string;
}[];
export type TGetUserProjectPermissionArg = {
userId: string;
projectId: string;
authMethod: ActorAuthMethod;
actionProjectType: ActionProjectType;
userOrgId?: string;
};
export type TGetIdentityProjectPermissionArg = {
identityId: string;
projectId: string;
identityOrgId?: string;
actionProjectType: ActionProjectType;
};
export type TGetServiceTokenProjectPermissionArg = {
serviceTokenId: string;
projectId: string;
@@ -55,16 +40,11 @@ export type TGetOrgPermissionArg = {
orgId: string;
actorAuthMethod: ActorAuthMethod;
actorOrgId?: string;
scope: OrganizationActionScope;
};
export type TPermissionServiceFactory = {
getOrgPermission: (
type: ActorType,
id: string,
orgId: string,
authMethod: ActorAuthMethod,
actorOrgId: string | undefined
) => Promise<{
getOrgPermission: (arg: TGetOrgPermissionArg) => Promise<{
permission: MongoAbility<OrgPermissionSet, MongoQuery>;
memberships: Array<
TMemberships & {
@@ -7,6 +7,7 @@ import { Knex } from "knex";
import {
AccessScope,
ActionProjectType,
OrganizationActionScope,
OrgMembershipRole,
ProjectMembershipRole,
ServiceTokenScopes
@@ -179,14 +180,15 @@ export const permissionServiceFactory = ({
// return minTtl;
// };
const getOrgPermission: TPermissionServiceFactory["getOrgPermission"] = async (
type,
id,
const getOrgPermission: TPermissionServiceFactory["getOrgPermission"] = async ({
actor,
actorId,
orgId,
authMethod,
actorOrgId
) => {
if (type !== ActorType.USER && type !== ActorType.IDENTITY) {
actorOrgId,
scope,
actorAuthMethod
}) => {
if (actor !== ActorType.USER && actor !== ActorType.IDENTITY) {
throw new BadRequestError({
message: "Invalid actor provided",
name: "Get org permission"
@@ -202,11 +204,19 @@ export const permissionServiceFactory = ({
scope: AccessScope.Organization,
orgId
},
actorId: id,
actorType: type
actorId,
actorType: actor
});
if (!permissionData?.length) throw new ForbiddenRequestError({ name: "You are not member of this organization" });
const parentOrgId = permissionData?.[0]?.parentOrgId;
const isChild = Boolean(parentOrgId);
if (scope === OrganizationActionScope.ParentOrganization && isChild) {
throw new BadRequestError({ message: `Child organization cannot do this operation` });
} else if (scope === OrganizationActionScope.ChildOrganization && !isChild) {
throw new BadRequestError({ message: `Parent organization cannot do this operation` });
}
const permissionFromRoles = permissionData.flatMap((membership) => {
const activeRoles = membership?.roles
.filter(
@@ -227,7 +237,7 @@ export const permissionServiceFactory = ({
permissionData.some((memberships) => memberships.roles.some((el) => role === (el.customRoleSlug || el.role)));
validateOrgSSO(
authMethod,
actorAuthMethod,
permissionData?.[0].orgAuthEnforced,
Boolean(permissionData?.[0].orgGoogleSsoAuthEnforced),
Boolean(permissionData?.[0].bypassOrgAuthEnabled),