diff --git a/src/lib/__snapshots__/create-config.test.ts.snap b/src/lib/__snapshots__/create-config.test.ts.snap index fdab0f3ef4..1715571204 100644 --- a/src/lib/__snapshots__/create-config.test.ts.snap +++ b/src/lib/__snapshots__/create-config.test.ts.snap @@ -72,6 +72,7 @@ exports[`should create default config 1`] = ` "batchMetrics": false, "embedProxy": true, "embedProxyFrontend": true, + "featuresExportImport": false, "maintenance": false, "maintenanceMode": false, "messageBanner": false, @@ -89,6 +90,7 @@ exports[`should create default config 1`] = ` "batchMetrics": false, "embedProxy": true, "embedProxyFrontend": true, + "featuresExportImport": false, "maintenance": false, "maintenanceMode": false, "messageBanner": false, diff --git a/src/lib/routes/admin-api/export-import.ts b/src/lib/routes/admin-api/export-import.ts index d2b36b38f1..cfc088b93e 100644 --- a/src/lib/routes/admin-api/export-import.ts +++ b/src/lib/routes/admin-api/export-import.ts @@ -8,6 +8,7 @@ import { OpenApiService } from '../../services/openapi-service'; import ExportImportService, { IExportQuery, } from 'lib/services/export-import-service'; +import { InvalidOperationError } from '../../error'; class ExportImportController extends Controller { private logger: Logger; @@ -50,10 +51,19 @@ class ExportImportController extends Controller { req: Request, res: Response, ): Promise { + this.verifyExportImportEnabled(); const query = req.body; const data = await this.exportImportService.export(query); res.json(data); } + + private verifyExportImportEnabled() { + if (!this.config.flagResolver.isEnabled('featuresExportImport')) { + throw new InvalidOperationError( + 'Feature export/import is not enabled', + ); + } + } } export default ExportImportController; diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index 13115ed768..ae6bedd284 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -50,6 +50,10 @@ const flags = { process.env.UNLEASH_EXPERIMENTAL_SERVICE_ACCOUNTS, false, ), + featuresExportImport: parseEnvVarBoolean( + process.env.UNLEASH_EXPERIMENTAL_FEATURES_EXPORT_IMPORT, + false, + ), }; export const defaultExperimentalOptions: IExperimentalOptions = { diff --git a/src/server-dev.ts b/src/server-dev.ts index 304a585ac7..e9539b421c 100644 --- a/src/server-dev.ts +++ b/src/server-dev.ts @@ -41,6 +41,7 @@ process.nextTick(async () => { responseTimeWithAppName: true, variantsPerEnvironment: true, maintenance: false, + featuresExportImport: true, }, }, authentication: { diff --git a/src/test/e2e/api/admin/export-import.e2e.test.ts b/src/test/e2e/api/admin/export-import.e2e.test.ts index 3ae2715929..dcff784ca3 100644 --- a/src/test/e2e/api/admin/export-import.e2e.test.ts +++ b/src/test/e2e/api/admin/export-import.e2e.test.ts @@ -1,4 +1,7 @@ -import { IUnleashTest, setupApp } from '../../helpers/test-helper'; +import { + IUnleashTest, + setupAppWithCustomConfig, +} from '../../helpers/test-helper'; import dbInit, { ITestDb } from '../../helpers/database-init'; import getLogger from '../../../fixtures/no-logger'; import { IEventStore } from 'lib/types/stores/event-store'; @@ -31,7 +34,13 @@ const createToggle = async ( beforeAll(async () => { db = await dbInit('export_import_api_serial', getLogger); - app = await setupApp(db.stores); + app = await setupAppWithCustomConfig(db.stores, { + experimental: { + flags: { + featuresExportImport: true, + }, + }, + }); eventStore = db.stores.eventStore; });