Fix RLS entitlement check + fix role page with RLS on object without object-permission not being displayed (#17326)

This commit is contained in:
Weiko
2026-01-22 11:48:24 +01:00
committed by GitHub
parent f10515fc2d
commit 670ff1583e
7 changed files with 48 additions and 26 deletions
@@ -163,6 +163,19 @@ export const useGetObjectPermissionDerivedStates = ({
((isThereAnyFieldPermissionThatRevokeRead && canRestrictFieldRead) ||
(isThereAnyFieldPermissionThatRevokeUpdate && canRestrictFieldUpdate));
const rowLevelPermissionPredicatesForThisObject =
settingsDraftRole.rowLevelPermissionPredicates?.filter(
(predicateToFilter) =>
predicateToFilter.objectMetadataId === objectMetadataItemId,
) ?? [];
const isThereAnyRowLevelPermissionPredicateForThisObject =
rowLevelPermissionPredicatesForThisObject.length > 0;
const objectHasNoOverrideButRowLevelPermissionShouldBeTakenIntoAccount =
objectHasNoOverrideOnObjectPermission &&
isThereAnyRowLevelPermissionPredicateForThisObject;
const objectHasOverrideOnObjectPermissions =
!objectHasNoOverrideOnObjectPermission;
@@ -182,6 +195,7 @@ export const useGetObjectPermissionDerivedStates = ({
objectHasNoOverrideOnObjectPermission,
thereAreFieldPermissionsButTheyShouldntBeTakenIntoAccountBecauseObjectPermissionsDontAllowIt,
objectHasNoOverrideButFieldPermissionsShouldBeTakenIntoAccount,
objectHasNoOverrideButRowLevelPermissionShouldBeTakenIntoAccount,
objectPermissionHasOnlyNullPermissions,
objectHasOverrideOnObjectPermissions,
};
@@ -17,10 +17,12 @@ export const useFilterObjectMetadataItemsWithPermissionOverride = ({
const {
objectHasOverrideOnObjectPermissions,
objectHasNoOverrideButFieldPermissionsShouldBeTakenIntoAccount,
objectHasNoOverrideButRowLevelPermissionShouldBeTakenIntoAccount,
} = getObjectPermissionDerivedStates(objectMetadataItem.id);
const hasOverride =
objectHasNoOverrideButFieldPermissionsShouldBeTakenIntoAccount ||
objectHasNoOverrideButRowLevelPermissionShouldBeTakenIntoAccount ||
objectHasOverrideOnObjectPermissions;
return hasOverride;
@@ -34,8 +34,7 @@ export const SettingsRolePermissionsObjectLevelObjectForm = ({
const fromAgentId = searchParams.get('fromAgent');
const currentWorkspace = useRecoilValue(currentWorkspaceState);
const hasValidEnterpriseKey =
currentWorkspace?.hasValidEnterpriseKey === true;
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
);
@@ -63,8 +62,7 @@ export const SettingsRolePermissionsObjectLevelObjectForm = ({
const isRowLevelPermissionPredicatesEnabled =
featureFlagsMap[
FeatureFlagKey.IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED
] &&
(hasValidEnterpriseKey || isRLSBillingEntitlementEnabled);
] && isRLSBillingEntitlementEnabled;
const objectMetadataItem = objectMetadata.objectMetadataItem;
@@ -23,11 +23,12 @@ import {
BillingException,
BillingExceptionCode,
} from 'src/engine/core-modules/billing/billing.exception';
import { BillingEntitlementDTO } from 'src/engine/core-modules/billing/dtos/billing-entitlement.dto';
import { BillingCustomerEntity } from 'src/engine/core-modules/billing/entities/billing-customer.entity';
import { BillingEntitlementEntity } from 'src/engine/core-modules/billing/entities/billing-entitlement.entity';
import { BillingSubscriptionItemEntity } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity';
import { BillingSubscriptionEntity } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
import { type BillingEntitlementKey } from 'src/engine/core-modules/billing/enums/billing-entitlement-key.enum';
import { BillingEntitlementKey } from 'src/engine/core-modules/billing/enums/billing-entitlement-key.enum';
import { BillingProductKey } from 'src/engine/core-modules/billing/enums/billing-product-key.enum';
import { SubscriptionStatus } from 'src/engine/core-modules/billing/enums/billing-subscription-status.enum';
import { BillingPlanService } from 'src/engine/core-modules/billing/services/billing-plan.service';
@@ -177,18 +178,31 @@ export class BillingSubscriptionService {
async getWorkspaceEntitlements(
workspaceId: string,
): Promise<BillingEntitlementEntity[]> {
): Promise<BillingEntitlementDTO[]> {
const isBillingEnabled = this.twentyConfigService.get('IS_BILLING_ENABLED');
if (!isBillingEnabled) {
return [];
}
const hasValidEnterpriseKey = isDefined(
this.twentyConfigService.get('ENTERPRISE_KEY'),
);
const entitlements = await this.billingEntitlementRepository.find({
where: { workspaceId },
});
return entitlements;
const entitlementsByKey = entitlements.reduce(
(acc, entitlement) => {
acc[entitlement.key] = entitlement;
return acc;
},
{} as Record<BillingEntitlementKey, BillingEntitlementEntity>,
);
return Object.values(BillingEntitlementKey).map((key) => ({
key,
value:
hasValidEnterpriseKey &&
(!isBillingEnabled || (entitlementsByKey[key]?.value ?? false)),
}));
}
async getWorkspaceEntitlementByKey(
@@ -18,8 +18,8 @@ import assert from 'assert';
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
import { PermissionFlagType } from 'twenty-shared/constants';
import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
import { FileFolder } from 'twenty-shared/types';
import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
import type { FileUpload } from 'graphql-upload/processRequest.mjs';
@@ -360,8 +360,9 @@ export class RowLevelPermissionPredicateGroupService {
private async hasRowLevelPermissionFeature(
workspaceId: string,
): Promise<boolean> {
const isBillingEnabled = this.configService.get('IS_BILLING_ENABLED');
const entrepriseKey = this.configService.get('ENTERPRISE_KEY');
const hasValidEnterpriseKey = isDefined(
this.configService.get('ENTERPRISE_KEY'),
);
const isRowLevelPermissionEnabled =
await this.billingService.hasEntitlement(
@@ -369,11 +370,7 @@ export class RowLevelPermissionPredicateGroupService {
BillingEntitlementKey.RLS,
);
if (isDefined(entrepriseKey)) {
return true;
}
return isBillingEnabled && isRowLevelPermissionEnabled;
return hasValidEnterpriseKey && isRowLevelPermissionEnabled;
}
private async hasRowLevelPermissionFeatureOrThrow(workspaceId: string) {
@@ -718,8 +718,9 @@ export class RowLevelPermissionPredicateService {
private async hasRowLevelPermissionFeature(
workspaceId: string,
): Promise<boolean> {
const isBillingEnabled = this.configService.get('IS_BILLING_ENABLED');
const entrepriseKey = this.configService.get('ENTERPRISE_KEY');
const hasValidEnterpriseKey = isDefined(
this.configService.get('ENTERPRISE_KEY'),
);
const isRowLevelPermissionEnabled =
await this.billingService.hasEntitlement(
@@ -727,11 +728,7 @@ export class RowLevelPermissionPredicateService {
BillingEntitlementKey.RLS,
);
if (isDefined(entrepriseKey)) {
return true;
}
return isBillingEnabled && isRowLevelPermissionEnabled;
return hasValidEnterpriseKey && isRowLevelPermissionEnabled;
}
private async hasRowLevelPermissionFeatureOrThrow(workspaceId: string) {