Compare commits

...
Author SHA1 Message Date
Charles Bochet e22881739f fix: invalidate rolesPermissions cache when object/field permissions change
After migrating object/field permissions to syncable entities, changes to
flatObjectPermissionMaps, flatFieldPermissionMaps, or flatPermissionFlagMaps
no longer triggered rolesPermissions cache invalidation. This caused stale
permission data to be served, leading to flaky permission-on-relations tests
where newly-created object permission overrides were not reflected.

Made-with: Cursor
2026-03-27 16:04:24 +01:00
Charles Bochet 1f1046e187 fix: resolve availabilityObjectMetadataUniversalIdentifier in backfill command
The migration runner resolves availabilityObjectMetadataId from
availabilityObjectMetadataUniversalIdentifier, overwriting the original
value. The backfill was hardcoding the universal identifier to null,
causing RECORD_SELECTION items to lose their object metadata reference.

Made-with: Cursor
2026-03-27 15:43:33 +01:00
2 changed files with 21 additions and 5 deletions
@@ -255,8 +255,11 @@ export class BackfillCommandMenuItemsCommand extends ActiveOrSuspendedWorkspaces
const trigger = workflowVersion.trigger as WorkflowManualTrigger;
const { availabilityType, availabilityObjectMetadataId } =
await this.resolveManualTriggerAvailability(trigger, workspaceId);
const {
availabilityType,
availabilityObjectMetadataId,
availabilityObjectMetadataUniversalIdentifier,
} = await this.resolveManualTriggerAvailability(trigger, workspaceId);
const id = uuidv4();
const now = new Date().toISOString();
@@ -276,7 +279,7 @@ export class BackfillCommandMenuItemsCommand extends ActiveOrSuspendedWorkspaces
hotKeys: null,
availabilityType,
availabilityObjectMetadataId: availabilityObjectMetadataId ?? null,
availabilityObjectMetadataUniversalIdentifier: null,
availabilityObjectMetadataUniversalIdentifier,
conditionalAvailabilityExpression: null,
workspaceId,
applicationId: workspaceCustomFlatApplication.id,
@@ -340,6 +343,7 @@ export class BackfillCommandMenuItemsCommand extends ActiveOrSuspendedWorkspaces
): Promise<{
availabilityType: CommandMenuItemAvailabilityType;
availabilityObjectMetadataId: string | undefined;
availabilityObjectMetadataUniversalIdentifier: string | null;
}> {
const availability = trigger.settings.availability;
@@ -347,10 +351,11 @@ export class BackfillCommandMenuItemsCommand extends ActiveOrSuspendedWorkspaces
return {
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
availabilityObjectMetadataId: undefined,
availabilityObjectMetadataUniversalIdentifier: null,
};
}
const { objectIdByNameSingular } =
const { objectIdByNameSingular, flatObjectMetadataMaps } =
await this.workflowCommonWorkspaceService.getFlatEntityMaps(workspaceId);
const objectId = objectIdByNameSingular[availability.objectNameSingular];
@@ -363,12 +368,17 @@ export class BackfillCommandMenuItemsCommand extends ActiveOrSuspendedWorkspaces
return {
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
availabilityObjectMetadataId: undefined,
availabilityObjectMetadataUniversalIdentifier: null,
};
}
const objectUniversalIdentifier =
flatObjectMetadataMaps.universalIdentifierById[objectId] ?? null;
return {
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
availabilityObjectMetadataId: objectId,
availabilityObjectMetadataUniversalIdentifier: objectUniversalIdentifier,
};
}
}
@@ -85,9 +85,15 @@ export class WorkspaceMigrationRunnerService {
flatMapsKeysSet.has('flatRoleMaps') ||
flatMapsKeysSet.has('flatRoleTargetMaps');
const shouldInvalidateRolesPermissionsCache =
flatMapsKeysSet.has('flatObjectPermissionMaps') ||
flatMapsKeysSet.has('flatFieldPermissionMaps') ||
flatMapsKeysSet.has('flatPermissionFlagMaps');
if (
shouldIncrementMetadataGraphqlSchemaVersion ||
shouldInvalidateRoleMapCache
shouldInvalidateRoleMapCache ||
shouldInvalidateRolesPermissionsCache
) {
asyncOperations.push(
this.workspaceCacheService.invalidateAndRecompute(workspaceId, [