Remove IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED feature flag (#18520)

## Summary
- Removes the `IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED` feature
flag, consolidating tarball-based app installation under the existing
`IS_APPLICATION_ENABLED` flag
- Removes the runtime feature flag check in `runWorkspaceMigration`
resolver (the `@RequireFeatureFlag(IS_APPLICATION_ENABLED)` decorator
already gates this endpoint)
- Cleans up related integration test setup/teardown and mock feature
flag maps

## Test plan
- [ ] Verify tarball-based app installation still works when
`IS_APPLICATION_ENABLED` is true
- [ ] Verify app installation is blocked when `IS_APPLICATION_ENABLED`
is false
- [ ] Run `failing-install-application.integration-spec.ts` to confirm
it passes without the removed flag


Made with [Cursor](https://cursor.com)
This commit is contained in:
Félix Malfait
2026-03-10 13:13:22 +01:00
committed by GitHub
parent f9f7e2f929
commit 6995420b71
7 changed files with 1 additions and 48 deletions
@@ -1643,7 +1643,6 @@ export type FeatureFlag = {
export enum FeatureFlagKey {
IS_AI_ENABLED = 'IS_AI_ENABLED',
IS_APPLICATION_ENABLED = 'IS_APPLICATION_ENABLED',
IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED = 'IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED',
IS_ATTACHMENT_MIGRATED = 'IS_ATTACHMENT_MIGRATED',
IS_COMMAND_MENU_ITEM_ENABLED = 'IS_COMMAND_MENU_ITEM_ENABLED',
IS_DASHBOARD_V2_ENABLED = 'IS_DASHBOARD_V2_ENABLED',
@@ -1580,7 +1580,6 @@ enum FeatureFlagKey {
IS_JSON_FILTER_ENABLED
IS_AI_ENABLED
IS_APPLICATION_ENABLED
IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED
IS_MARKETPLACE_ENABLED
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED
IS_PUBLIC_DOMAIN_ENABLED
@@ -1295,7 +1295,7 @@ export interface FeatureFlag {
__typename: 'FeatureFlag'
}
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_AI_ENABLED' | 'IS_APPLICATION_ENABLED' | 'IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED' | 'IS_MARKETPLACE_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_DASHBOARD_V2_ENABLED' | 'IS_ATTACHMENT_MIGRATED' | 'IS_NOTE_TARGET_MIGRATED' | 'IS_TASK_TARGET_MIGRATED' | 'IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_NAVIGATION_MENU_ITEM_ENABLED' | 'IS_DATE_TIME_WHOLE_DAY_FILTER_ENABLED' | 'IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED' | 'IS_DRAFT_EMAIL_ENABLED'
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_AI_ENABLED' | 'IS_APPLICATION_ENABLED' | 'IS_MARKETPLACE_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_DASHBOARD_V2_ENABLED' | 'IS_ATTACHMENT_MIGRATED' | 'IS_NOTE_TARGET_MIGRATED' | 'IS_TASK_TARGET_MIGRATED' | 'IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_NAVIGATION_MENU_ITEM_ENABLED' | 'IS_DATE_TIME_WHOLE_DAY_FILTER_ENABLED' | 'IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED' | 'IS_DRAFT_EMAIL_ENABLED'
export interface SSOIdentityProvider {
id: Scalars['UUID']
@@ -8504,7 +8504,6 @@ export const enumFeatureFlagKey = {
IS_JSON_FILTER_ENABLED: 'IS_JSON_FILTER_ENABLED' as const,
IS_AI_ENABLED: 'IS_AI_ENABLED' as const,
IS_APPLICATION_ENABLED: 'IS_APPLICATION_ENABLED' as const,
IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED: 'IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED' as const,
IS_MARKETPLACE_ENABLED: 'IS_MARKETPLACE_ENABLED' as const,
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED: 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' as const,
IS_PUBLIC_DOMAIN_ENABLED: 'IS_PUBLIC_DOMAIN_ENABLED' as const,
@@ -11,10 +11,6 @@ import { FeatureFlagKey } from 'twenty-shared/types';
import { MetadataResolver } from 'src/engine/api/graphql/graphql-config/decorators/metadata-resolver.decorator';
import { ApplicationExceptionFilter } from 'src/engine/core-modules/application/application-exception-filter';
import {
ApplicationException,
ApplicationExceptionCode,
} from 'src/engine/core-modules/application/application.exception';
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
import { ApplicationSyncService } from 'src/engine/core-modules/application/application-manifest/application-sync.service';
import { RunWorkspaceMigrationInput } from 'src/engine/core-modules/application/application-manifest/dtos/run-workspace-migration.input';
@@ -29,7 +25,6 @@ import {
} from 'src/engine/guards/feature-flag.guard';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
import { WorkspaceMigrationGraphqlApiExceptionInterceptor } from 'src/engine/workspace-manager/workspace-migration/interceptors/workspace-migration-graphql-api-exception.interceptor';
import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/services/workspace-migration-runner.service';
@@ -43,7 +38,6 @@ export class ApplicationManifestResolver {
private readonly applicationService: ApplicationService,
private readonly applicationSyncService: ApplicationSyncService,
private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService,
private readonly workspaceCacheService: WorkspaceCacheService,
) {}
@Mutation(() => Boolean)
@@ -53,22 +47,6 @@ export class ApplicationManifestResolver {
@Args() { workspaceMigration: { actions } }: RunWorkspaceMigrationInput,
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
) {
const { featureFlagsMap } = await this.workspaceCacheService.getOrRecompute(
workspaceId,
['featureFlagsMap'],
);
if (
featureFlagsMap[
FeatureFlagKey.IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED
] !== true
) {
throw new ApplicationException(
'Application installation from tarball is not enabled',
ApplicationExceptionCode.FORBIDDEN,
);
}
const { workspaceCustomFlatApplication } =
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
{
@@ -241,7 +241,6 @@ describe('WorkspaceEntityManager', () => {
IS_COMMAND_MENU_ITEM_ENABLED: false,
IS_NAVIGATION_MENU_ITEM_ENABLED: false,
IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED: false,
IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED: false,
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED: false,
IS_MARKETPLACE_ENABLED: false,
IS_DATE_TIME_WHOLE_DAY_FILTER_ENABLED: false,
@@ -4,23 +4,12 @@ import { installApplication } from 'test/integration/metadata/suites/application
import { setupApplicationForSync } from 'test/integration/metadata/suites/application/utils/setup-application-for-sync.util';
import { syncApplication } from 'test/integration/metadata/suites/application/utils/sync-application.util';
import { uninstallApplication } from 'test/integration/metadata/suites/application/utils/uninstall-application.util';
import { updateFeatureFlag } from 'test/integration/metadata/suites/utils/update-feature-flag.util';
import { v4 as uuidv4 } from 'uuid';
import { FeatureFlagKey } from 'twenty-shared/types';
const INVALID_UUID_APP_ID = uuidv4();
const INVALID_UUID_ROLE_ID = uuidv4();
describe('Install application should fail when entity does not exist', () => {
beforeAll(async () => {
await updateFeatureFlag({
featureFlag:
FeatureFlagKey.IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED,
value: true,
expectToFail: false,
});
});
beforeEach(async () => {
await setupApplicationForSync({
applicationUniversalIdentifier: INVALID_UUID_APP_ID,
@@ -30,15 +19,6 @@ describe('Install application should fail when entity does not exist', () => {
});
}, 60000);
afterAll(async () => {
await updateFeatureFlag({
featureFlag:
FeatureFlagKey.IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED,
value: false,
expectToFail: false,
});
});
afterEach(async () => {
try {
await uninstallApplication({
@@ -3,7 +3,6 @@ export enum FeatureFlagKey {
IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED',
IS_AI_ENABLED = 'IS_AI_ENABLED',
IS_APPLICATION_ENABLED = 'IS_APPLICATION_ENABLED',
IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED = 'IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED',
IS_MARKETPLACE_ENABLED = 'IS_MARKETPLACE_ENABLED',
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED',
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',