diff --git a/src/lib/db/feature-environment-store.ts b/src/lib/db/feature-environment-store.ts index 6b3cb7392539..824fedc0411b 100644 --- a/src/lib/db/feature-environment-store.ts +++ b/src/lib/db/feature-environment-store.ts @@ -3,13 +3,14 @@ import type { FeatureEnvironmentKey, IFeatureEnvironmentStore, } from '../types/stores/feature-environment-store'; -import type { Logger, LogProvider } from '../logger'; +import type { Logger } from '../logger'; import metricsHelper from '../util/metrics-helper'; import { DB_TIME } from '../metric-events'; import type { IFeatureEnvironment, IVariant } from '../types/model'; import NotFoundError from '../error/notfound-error'; import { v4 as uuidv4 } from 'uuid'; import type { Db } from './db'; +import type { IUnleashConfig } from '../types'; const T = { featureEnvs: 'feature_environments', @@ -36,7 +37,16 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore { private readonly timer: Function; - constructor(db: Db, eventBus: EventEmitter, getLogger: LogProvider) { + private readonly isOss: boolean; + constructor( + db: Db, + eventBus: EventEmitter, + { + getLogger, + ui, + isEnterprise, + }: Pick, + ) { this.db = db; this.logger = getLogger('feature-environment-store.ts'); this.timer = (action) => @@ -44,6 +54,8 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore { store: 'feature-environments', action, }); + const isTest = process.env.NODE_ENV === 'test'; + this.isOss = !isEnterprise && ui.environment !== 'pro' && !isTest; } async delete({ @@ -96,11 +108,26 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore { ); } + addOssFilterIfNeeded(queryBuilder) { + if (this.isOss) { + return queryBuilder + .join( + 'environments', + 'environments.name', + '=', + `${T.featureEnvs}.environment`, + ) + .where('environments.enabled_in_oss', true); + } + return queryBuilder; + } + async getAll(query?: Object): Promise { let rows = this.db(T.featureEnvs); if (query) { rows = rows.where(query); } + this.addOssFilterIfNeeded(rows); return (await rows).map((r) => ({ enabled: r.enabled, featureName: r.feature_name, @@ -119,6 +146,7 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore { if (environment) { rows = rows.where({ environment }); } + this.addOssFilterIfNeeded(rows); return (await rows).map((r) => ({ enabled: r.enabled, featureName: r.feature_name, diff --git a/src/lib/db/index.ts b/src/lib/db/index.ts index 2716ff052077..3722d91d46fd 100644 --- a/src/lib/db/index.ts +++ b/src/lib/db/index.ts @@ -94,12 +94,7 @@ export const createStores = ( settingStore: new SettingStore(db, getLogger), userStore: new UserStore(db, getLogger, config.flagResolver), accountStore: new AccountStore(db, getLogger), - projectStore: new ProjectStore( - db, - eventBus, - getLogger, - config.flagResolver, - ), + projectStore: new ProjectStore(db, eventBus, config), tagStore: new TagStore(db, eventBus, getLogger), tagTypeStore: new TagTypeStore(db, eventBus, getLogger), addonStore: new AddonStore(db, eventBus, getLogger), @@ -122,15 +117,14 @@ export const createStores = ( clientFeatureToggleStore: new FeatureToggleClientStore( db, eventBus, - getLogger, - config.flagResolver, + config, ), environmentStore: new EnvironmentStore(db, eventBus, config), featureTagStore: new FeatureTagStore(db, eventBus, getLogger), featureEnvironmentStore: new FeatureEnvironmentStore( db, eventBus, - getLogger, + config, ), userSplashStore: new UserSplashStore(db, eventBus, getLogger), roleStore: new RoleStore(db, eventBus, getLogger), diff --git a/src/lib/features/client-feature-toggles/client-feature-toggle-service.ts b/src/lib/features/client-feature-toggles/client-feature-toggle-service.ts index c4a7f0e5bd0b..7e90ef21a3ea 100644 --- a/src/lib/features/client-feature-toggles/client-feature-toggle-service.ts +++ b/src/lib/features/client-feature-toggles/client-feature-toggle-service.ts @@ -27,6 +27,7 @@ export class ClientFeatureToggleService { this.logger = getLogger('services/client-feature-toggle-service.ts'); this.segmentReadModel = segmentReadModel; this.clientFeatureToggleStore = clientFeatureToggleStore; + const isTest = process.env.NODE_ENV === 'test'; } async getActiveSegmentsForClient() { diff --git a/src/lib/features/client-feature-toggles/client-feature-toggle-store.ts b/src/lib/features/client-feature-toggles/client-feature-toggle-store.ts index ed4b738a734b..c200c7bbbe69 100644 --- a/src/lib/features/client-feature-toggles/client-feature-toggle-store.ts +++ b/src/lib/features/client-feature-toggles/client-feature-toggle-store.ts @@ -1,7 +1,7 @@ import { Knex } from 'knex'; import metricsHelper from '../../util/metrics-helper'; import { DB_TIME } from '../../metric-events'; -import type { Logger, LogProvider } from '../../logger'; +import type { Logger } from '../../logger'; import type { IFeatureToggleClient, IFeatureToggleClientStore, @@ -9,6 +9,7 @@ import type { IFlagResolver, IStrategyConfig, ITag, + IUnleashConfig, PartialDeep, } from '../../types'; import { @@ -46,11 +47,20 @@ export default class FeatureToggleClientStore private flagResolver: IFlagResolver; + private readonly isOss: boolean; + constructor( db: Db, eventBus: EventEmitter, - getLogger: LogProvider, - flagResolver: IFlagResolver, + { + getLogger, + flagResolver, + ui, + isEnterprise, + }: Pick< + IUnleashConfig, + 'getLogger' | 'flagResolver' | 'ui' | 'isEnterprise' + >, ) { this.db = db; this.logger = getLogger('feature-toggle-client-store.ts'); @@ -60,6 +70,8 @@ export default class FeatureToggleClientStore action, }); this.flagResolver = flagResolver; + const isTest = process.env.NODE_ENV === 'test'; + this.isOss = !isEnterprise && ui.environment !== 'pro' && !isTest; } private async getAll({ @@ -72,7 +84,7 @@ export default class FeatureToggleClientStore const isPlayground = requestType === 'playground'; const environment = featureQuery?.environment || DEFAULT_ENV; const stopTimer = this.timer(`getAllBy${requestType}`); - + this.logger.info(`Getting all features and we're OSS: ${this.isOss}`); let selectColumns = [ 'features.name as name', 'features.description as description', @@ -103,6 +115,10 @@ export default class FeatureToggleClientStore let query = this.db('features') .modify(FeatureToggleStore.filterByArchived, archived) + .modify( + FeatureToggleStore.filterByProjectsAccessibleByOss, + this.isOss, + ) .leftJoin( this.db('feature_strategies') .select('*') diff --git a/src/lib/features/client-feature-toggles/createClientFeatureToggleService.ts b/src/lib/features/client-feature-toggles/createClientFeatureToggleService.ts index be72bf8026f1..8d4a8c239fa2 100644 --- a/src/lib/features/client-feature-toggles/createClientFeatureToggleService.ts +++ b/src/lib/features/client-feature-toggles/createClientFeatureToggleService.ts @@ -10,13 +10,10 @@ export const createClientFeatureToggleService = ( db: Db, config: IUnleashConfig, ): ClientFeatureToggleService => { - const { getLogger, eventBus, flagResolver } = config; - const featureToggleClientStore = new FeatureToggleClientStore( db, - eventBus, - getLogger, - flagResolver, + config.eventBus, + config, ); const segmentReadModel = new SegmentReadModel(db); @@ -26,7 +23,7 @@ export const createClientFeatureToggleService = ( clientFeatureToggleStore: featureToggleClientStore, }, segmentReadModel, - { getLogger, flagResolver }, + config, ); return clientFeatureToggleService; @@ -35,8 +32,6 @@ export const createClientFeatureToggleService = ( export const createFakeClientFeatureToggleService = ( config: IUnleashConfig, ): ClientFeatureToggleService => { - const { getLogger, flagResolver } = config; - const fakeClientFeatureToggleStore = new FakeClientFeatureToggleStore(); const fakeSegmentReadModel = new FakeSegmentReadModel(); @@ -46,7 +41,7 @@ export const createFakeClientFeatureToggleService = ( clientFeatureToggleStore: fakeClientFeatureToggleStore, }, fakeSegmentReadModel, - { getLogger, flagResolver }, + config, ); return clientFeatureToggleService; diff --git a/src/lib/features/export-import-toggles/createExportImportService.ts b/src/lib/features/export-import-toggles/createExportImportService.ts index b36b6e0fabf3..69bebf187066 100644 --- a/src/lib/features/export-import-toggles/createExportImportService.ts +++ b/src/lib/features/export-import-toggles/createExportImportService.ts @@ -150,12 +150,7 @@ export const deferredExportImportTogglesService = ( ); const tagStore = new TagStore(db, eventBus, getLogger); const tagTypeStore = new TagTypeStore(db, eventBus, getLogger); - const projectStore = new ProjectStore( - db, - eventBus, - getLogger, - flagResolver, - ); + const projectStore = new ProjectStore(db, eventBus, config); const featureTagStore = new FeatureTagStore(db, eventBus, getLogger); const strategyStore = new StrategyStore(db, getLogger); const contextFieldStore = new ContextFieldStore( @@ -172,7 +167,7 @@ export const deferredExportImportTogglesService = ( const featureEnvironmentStore = new FeatureEnvironmentStore( db, eventBus, - getLogger, + config, ); const eventStore = new EventStore(db, getLogger); const accessService = createAccessService(db, config); diff --git a/src/lib/features/feature-lifecycle/createFeatureLifecycle.ts b/src/lib/features/feature-lifecycle/createFeatureLifecycle.ts index 296d22125012..ed907e9f894b 100644 --- a/src/lib/features/feature-lifecycle/createFeatureLifecycle.ts +++ b/src/lib/features/feature-lifecycle/createFeatureLifecycle.ts @@ -23,7 +23,7 @@ export const createFeatureLifecycleService = const featureEnvironmentStore = new FeatureEnvironmentStore( db, eventBus, - getLogger, + config, ); const eventService = createEventsService(db, config); const featureLifecycleService = new FeatureLifecycleService( diff --git a/src/lib/features/feature-toggle/createFeatureToggleService.ts b/src/lib/features/feature-toggle/createFeatureToggleService.ts index b5f5d8fcf1eb..b12eb3adfc17 100644 --- a/src/lib/features/feature-toggle/createFeatureToggleService.ts +++ b/src/lib/features/feature-toggle/createFeatureToggleService.ts @@ -80,19 +80,13 @@ export const createFeatureToggleService = ( const featureToggleClientStore = new FeatureToggleClientStore( db, eventBus, - getLogger, - flagResolver, - ); - const projectStore = new ProjectStore( - db, - eventBus, - getLogger, - flagResolver, + config, ); + const projectStore = new ProjectStore(db, eventBus, config); const featureEnvironmentStore = new FeatureEnvironmentStore( db, eventBus, - getLogger, + config, ); const contextFieldStore = new ContextFieldStore( db, diff --git a/src/lib/features/feature-toggle/feature-toggle-store.ts b/src/lib/features/feature-toggle/feature-toggle-store.ts index fe412fb9986a..861d1af92c5e 100644 --- a/src/lib/features/feature-toggle/feature-toggle-store.ts +++ b/src/lib/features/feature-toggle/feature-toggle-store.ts @@ -439,6 +439,16 @@ export default class FeatureToggleStore implements IFeatureToggleStore { : queryBuilder.whereNull('archived_at'); }; + static filterByProjectsAccessibleByOss: Knex.QueryCallbackWithArgs = ( + queryBuilder: Knex.QueryBuilder, + isOss: boolean, + ) => { + if (isOss) { + return queryBuilder.andWhere('project', '=', 'default'); + } + return queryBuilder; + }; + rowToFeature(row: FeaturesTable): FeatureToggle { if (!row) { throw new NotFoundError('No feature flag found'); diff --git a/src/lib/features/instance-stats/createInstanceStatsService.ts b/src/lib/features/instance-stats/createInstanceStatsService.ts index 3aa6f6ae14e0..fb03d5ec8a1a 100644 --- a/src/lib/features/instance-stats/createInstanceStatsService.ts +++ b/src/lib/features/instance-stats/createInstanceStatsService.ts @@ -58,12 +58,7 @@ export const createInstanceStatsService = (db: Db, config: IUnleashConfig) => { flagResolver, ); const userStore = new UserStore(db, getLogger, flagResolver); - const projectStore = new ProjectStore( - db, - eventBus, - getLogger, - flagResolver, - ); + const projectStore = new ProjectStore(db, eventBus, config); const environmentStore = new EnvironmentStore(db, eventBus, config); const strategyStore = new StrategyStore(db, getLogger); const contextFieldStore = new ContextFieldStore( diff --git a/src/lib/features/project-environments/createEnvironmentService.ts b/src/lib/features/project-environments/createEnvironmentService.ts index 10246f7f5f2c..9a1dfbd6c626 100644 --- a/src/lib/features/project-environments/createEnvironmentService.ts +++ b/src/lib/features/project-environments/createEnvironmentService.ts @@ -21,14 +21,9 @@ export const createEnvironmentService = const featureEnvironmentStore = new FeatureEnvironmentStore( db, eventBus, - getLogger, - ); - const projectStore = new ProjectStore( - db, - eventBus, - getLogger, - flagResolver, + config, ); + const projectStore = new ProjectStore(db, eventBus, config); const featureStrategiesStore = new FeatureStrategiesStore( db, eventBus, diff --git a/src/lib/features/project-insights/createProjectInsightsService.ts b/src/lib/features/project-insights/createProjectInsightsService.ts index 68b46ac3941f..f15c1d61ad07 100644 --- a/src/lib/features/project-insights/createProjectInsightsService.ts +++ b/src/lib/features/project-insights/createProjectInsightsService.ts @@ -16,12 +16,7 @@ export const createProjectInsightsService = ( config: IUnleashConfig, ): ProjectInsightsService => { const { eventBus, getLogger, flagResolver } = config; - const projectStore = new ProjectStore( - db, - eventBus, - getLogger, - flagResolver, - ); + const projectStore = new ProjectStore(db, eventBus, config); const featureToggleStore = new FeatureToggleStore( db, eventBus, diff --git a/src/lib/features/project-status/createProjectStatusService.ts b/src/lib/features/project-status/createProjectStatusService.ts index c8694775403d..165c641ce8cd 100644 --- a/src/lib/features/project-status/createProjectStatusService.ts +++ b/src/lib/features/project-status/createProjectStatusService.ts @@ -24,12 +24,7 @@ export const createProjectStatusService = ( config: IUnleashConfig, ): ProjectStatusService => { const eventStore = new EventStore(db, config.getLogger); - const projectStore = new ProjectStore( - db, - config.eventBus, - config.getLogger, - config.flagResolver, - ); + const projectStore = new ProjectStore(db, config.eventBus, config); const apiTokenStore = new ApiTokenStore( db, config.eventBus, diff --git a/src/lib/features/project/createProjectService.ts b/src/lib/features/project/createProjectService.ts index 234cd0ef385c..a753ca34224f 100644 --- a/src/lib/features/project/createProjectService.ts +++ b/src/lib/features/project/createProjectService.ts @@ -63,12 +63,7 @@ export const createProjectService = ( ): ProjectService => { const { eventBus, getLogger, flagResolver } = config; const eventStore = new EventStore(db, getLogger); - const projectStore = new ProjectStore( - db, - eventBus, - getLogger, - flagResolver, - ); + const projectStore = new ProjectStore(db, eventBus, config); const projectOwnersReadModel = new ProjectOwnersReadModel(db); const projectFlagCreatorsReadModel = new ProjectFlagCreatorsReadModel(db); const groupStore = new GroupStore(db); @@ -83,7 +78,7 @@ export const createProjectService = ( const featureEnvironmentStore = new FeatureEnvironmentStore( db, eventBus, - getLogger, + config, ); const projectStatsStore = new ProjectStatsStore(db, eventBus, getLogger); const accessService: AccessService = createAccessService(db, config); diff --git a/src/lib/features/project/project-store.ts b/src/lib/features/project/project-store.ts index 5df93193c63e..7ba21274f903 100644 --- a/src/lib/features/project/project-store.ts +++ b/src/lib/features/project/project-store.ts @@ -1,4 +1,4 @@ -import type { Logger, LogProvider } from '../../logger'; +import type { Logger } from '../../logger'; import NotFoundError from '../../error/notfound-error'; import type { @@ -8,6 +8,7 @@ import type { IProjectApplication, IProjectApplications, IProjectUpdate, + IUnleashConfig, ProjectMode, } from '../../types'; import type { @@ -72,11 +73,20 @@ class ProjectStore implements IProjectStore { private timer: Function; + private isOss: boolean; + constructor( db: Db, eventBus: EventEmitter, - getLogger: LogProvider, - flagResolver: IFlagResolver, + { + getLogger, + flagResolver, + ui, + isEnterprise, + }: Pick< + IUnleashConfig, + 'getLogger' | 'flagResolver' | 'ui' | 'isEnterprise' + >, ) { this.db = db; this.logger = getLogger('project-store.ts'); @@ -86,6 +96,8 @@ class ProjectStore implements IProjectStore { action, }); this.flagResolver = flagResolver; + const isTest = process.env.NODE_ENV === 'test'; + this.isOss = !isEnterprise && ui.environment !== 'pro' && !isTest; } // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types @@ -122,6 +134,9 @@ class ProjectStore implements IProjectStore { .orderBy('name', 'asc'); projects = projects.where(`${TABLE}.archived_at`, null); + if (this.isOss) { + projects = projects.where('id', 'default'); + } const rows = await projects;