mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	task: enabled in OSS. (#8856)
Hardcode project and environment names to filter by when OSS
This commit is contained in:
		
							parent
							
								
									a454e14f28
								
							
						
					
					
						commit
						663b169c46
					
				| @ -85,6 +85,7 @@ exports[`should create default config 1`] = ` | |||||||
|   }, |   }, | ||||||
|   "inlineSegmentConstraints": true, |   "inlineSegmentConstraints": true, | ||||||
|   "isEnterprise": false, |   "isEnterprise": false, | ||||||
|  |   "isOss": false, | ||||||
|   "listen": { |   "listen": { | ||||||
|     "host": undefined, |     "host": undefined, | ||||||
|     "port": 4242, |     "port": 4242, | ||||||
|  | |||||||
| @ -620,6 +620,10 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig { | |||||||
|         Boolean(options.enterpriseVersion) && |         Boolean(options.enterpriseVersion) && | ||||||
|         ui.environment?.toLowerCase() !== 'pro'; |         ui.environment?.toLowerCase() !== 'pro'; | ||||||
| 
 | 
 | ||||||
|  |     const isTest = process.env.NODE_ENV === 'test'; | ||||||
|  |     const isOss = isTest | ||||||
|  |         ? options.isOss || false | ||||||
|  |         : !isEnterprise && ui.environment !== 'pro'; | ||||||
|     const metricsRateLimiting = loadMetricsRateLimitingConfig(options); |     const metricsRateLimiting = loadMetricsRateLimitingConfig(options); | ||||||
| 
 | 
 | ||||||
|     const rateLimiting = loadRateLimitingConfig(options); |     const rateLimiting = loadRateLimitingConfig(options); | ||||||
| @ -760,6 +764,7 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig { | |||||||
|         publicFolder: options.publicFolder, |         publicFolder: options.publicFolder, | ||||||
|         disableScheduler: options.disableScheduler, |         disableScheduler: options.disableScheduler, | ||||||
|         isEnterprise: isEnterprise, |         isEnterprise: isEnterprise, | ||||||
|  |         isOss: isOss, | ||||||
|         metricsRateLimiting, |         metricsRateLimiting, | ||||||
|         rateLimiting, |         rateLimiting, | ||||||
|         feedbackUriPath, |         feedbackUriPath, | ||||||
|  | |||||||
| @ -3,13 +3,14 @@ import type { | |||||||
|     FeatureEnvironmentKey, |     FeatureEnvironmentKey, | ||||||
|     IFeatureEnvironmentStore, |     IFeatureEnvironmentStore, | ||||||
| } from '../types/stores/feature-environment-store'; | } from '../types/stores/feature-environment-store'; | ||||||
| import type { Logger, LogProvider } from '../logger'; | import type { Logger } from '../logger'; | ||||||
| import metricsHelper from '../util/metrics-helper'; | import metricsHelper from '../util/metrics-helper'; | ||||||
| import { DB_TIME } from '../metric-events'; | import { DB_TIME } from '../metric-events'; | ||||||
| import type { IFeatureEnvironment, IVariant } from '../types/model'; | import type { IFeatureEnvironment, IVariant } from '../types/model'; | ||||||
| import NotFoundError from '../error/notfound-error'; | import NotFoundError from '../error/notfound-error'; | ||||||
| import { v4 as uuidv4 } from 'uuid'; | import { v4 as uuidv4 } from 'uuid'; | ||||||
| import type { Db } from './db'; | import type { Db } from './db'; | ||||||
|  | import type { IUnleashConfig } from '../types'; | ||||||
| 
 | 
 | ||||||
| const T = { | const T = { | ||||||
|     featureEnvs: 'feature_environments', |     featureEnvs: 'feature_environments', | ||||||
| @ -36,7 +37,12 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore { | |||||||
| 
 | 
 | ||||||
|     private readonly timer: Function; |     private readonly timer: Function; | ||||||
| 
 | 
 | ||||||
|     constructor(db: Db, eventBus: EventEmitter, getLogger: LogProvider) { |     private readonly isOss: boolean; | ||||||
|  |     constructor( | ||||||
|  |         db: Db, | ||||||
|  |         eventBus: EventEmitter, | ||||||
|  |         { getLogger, isOss }: Pick<IUnleashConfig, 'getLogger' | 'isOss'>, | ||||||
|  |     ) { | ||||||
|         this.db = db; |         this.db = db; | ||||||
|         this.logger = getLogger('feature-environment-store.ts'); |         this.logger = getLogger('feature-environment-store.ts'); | ||||||
|         this.timer = (action) => |         this.timer = (action) => | ||||||
| @ -44,6 +50,7 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore { | |||||||
|                 store: 'feature-environments', |                 store: 'feature-environments', | ||||||
|                 action, |                 action, | ||||||
|             }); |             }); | ||||||
|  |         this.isOss = isOss; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async delete({ |     async delete({ | ||||||
| @ -96,11 +103,30 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore { | |||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     addOssFilterIfNeeded(queryBuilder) { | ||||||
|  |         if (this.isOss) { | ||||||
|  |             return queryBuilder | ||||||
|  |                 .join( | ||||||
|  |                     'environments', | ||||||
|  |                     'environments.name', | ||||||
|  |                     '=', | ||||||
|  |                     `${T.featureEnvs}.environment`, | ||||||
|  |                 ) | ||||||
|  |                 .whereIn('environments.name', [ | ||||||
|  |                     'default', | ||||||
|  |                     'development', | ||||||
|  |                     'production', | ||||||
|  |                 ]); | ||||||
|  |         } | ||||||
|  |         return queryBuilder; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     async getAll(query?: Object): Promise<IFeatureEnvironment[]> { |     async getAll(query?: Object): Promise<IFeatureEnvironment[]> { | ||||||
|         let rows = this.db(T.featureEnvs); |         let rows = this.db(T.featureEnvs); | ||||||
|         if (query) { |         if (query) { | ||||||
|             rows = rows.where(query); |             rows = rows.where(query); | ||||||
|         } |         } | ||||||
|  |         this.addOssFilterIfNeeded(rows); | ||||||
|         return (await rows).map((r) => ({ |         return (await rows).map((r) => ({ | ||||||
|             enabled: r.enabled, |             enabled: r.enabled, | ||||||
|             featureName: r.feature_name, |             featureName: r.feature_name, | ||||||
| @ -119,6 +145,7 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore { | |||||||
|         if (environment) { |         if (environment) { | ||||||
|             rows = rows.where({ environment }); |             rows = rows.where({ environment }); | ||||||
|         } |         } | ||||||
|  |         this.addOssFilterIfNeeded(rows); | ||||||
|         return (await rows).map((r) => ({ |         return (await rows).map((r) => ({ | ||||||
|             enabled: r.enabled, |             enabled: r.enabled, | ||||||
|             featureName: r.feature_name, |             featureName: r.feature_name, | ||||||
|  | |||||||
| @ -94,12 +94,7 @@ export const createStores = ( | |||||||
|         settingStore: new SettingStore(db, getLogger), |         settingStore: new SettingStore(db, getLogger), | ||||||
|         userStore: new UserStore(db, getLogger, config.flagResolver), |         userStore: new UserStore(db, getLogger, config.flagResolver), | ||||||
|         accountStore: new AccountStore(db, getLogger), |         accountStore: new AccountStore(db, getLogger), | ||||||
|         projectStore: new ProjectStore( |         projectStore: new ProjectStore(db, eventBus, config), | ||||||
|             db, |  | ||||||
|             eventBus, |  | ||||||
|             getLogger, |  | ||||||
|             config.flagResolver, |  | ||||||
|         ), |  | ||||||
|         tagStore: new TagStore(db, eventBus, getLogger), |         tagStore: new TagStore(db, eventBus, getLogger), | ||||||
|         tagTypeStore: new TagTypeStore(db, eventBus, getLogger), |         tagTypeStore: new TagTypeStore(db, eventBus, getLogger), | ||||||
|         addonStore: new AddonStore(db, eventBus, getLogger), |         addonStore: new AddonStore(db, eventBus, getLogger), | ||||||
| @ -122,15 +117,14 @@ export const createStores = ( | |||||||
|         clientFeatureToggleStore: new FeatureToggleClientStore( |         clientFeatureToggleStore: new FeatureToggleClientStore( | ||||||
|             db, |             db, | ||||||
|             eventBus, |             eventBus, | ||||||
|             getLogger, |             config, | ||||||
|             config.flagResolver, |  | ||||||
|         ), |         ), | ||||||
|         environmentStore: new EnvironmentStore(db, eventBus, getLogger), |         environmentStore: new EnvironmentStore(db, eventBus, config), | ||||||
|         featureTagStore: new FeatureTagStore(db, eventBus, getLogger), |         featureTagStore: new FeatureTagStore(db, eventBus, getLogger), | ||||||
|         featureEnvironmentStore: new FeatureEnvironmentStore( |         featureEnvironmentStore: new FeatureEnvironmentStore( | ||||||
|             db, |             db, | ||||||
|             eventBus, |             eventBus, | ||||||
|             getLogger, |             config, | ||||||
|         ), |         ), | ||||||
|         userSplashStore: new UserSplashStore(db, eventBus, getLogger), |         userSplashStore: new UserSplashStore(db, eventBus, getLogger), | ||||||
|         roleStore: new RoleStore(db, eventBus, getLogger), |         roleStore: new RoleStore(db, eventBus, getLogger), | ||||||
|  | |||||||
| @ -25,7 +25,7 @@ export const createAccessService = ( | |||||||
|     const groupStore = new GroupStore(db); |     const groupStore = new GroupStore(db); | ||||||
|     const accountStore = new AccountStore(db, getLogger); |     const accountStore = new AccountStore(db, getLogger); | ||||||
|     const roleStore = new RoleStore(db, eventBus, getLogger); |     const roleStore = new RoleStore(db, eventBus, getLogger); | ||||||
|     const environmentStore = new EnvironmentStore(db, eventBus, getLogger); |     const environmentStore = new EnvironmentStore(db, eventBus, config); | ||||||
|     const accessStore = new AccessStore(db, eventBus, getLogger); |     const accessStore = new AccessStore(db, eventBus, getLogger); | ||||||
|     const eventService = createEventsService(db, config); |     const eventService = createEventsService(db, config); | ||||||
|     const groupService = new GroupService( |     const groupService = new GroupService( | ||||||
|  | |||||||
| @ -21,7 +21,7 @@ export const createApiTokenService = ( | |||||||
|         getLogger, |         getLogger, | ||||||
|         config.flagResolver, |         config.flagResolver, | ||||||
|     ); |     ); | ||||||
|     const environmentStore = new EnvironmentStore(db, eventBus, getLogger); |     const environmentStore = new EnvironmentStore(db, eventBus, config); | ||||||
|     const eventService = createEventsService(db, config); |     const eventService = createEventsService(db, config); | ||||||
| 
 | 
 | ||||||
|     return new ApiTokenService( |     return new ApiTokenService( | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| import { Knex } from 'knex'; | import { Knex } from 'knex'; | ||||||
| import metricsHelper from '../../util/metrics-helper'; | import metricsHelper from '../../util/metrics-helper'; | ||||||
| import { DB_TIME } from '../../metric-events'; | import { DB_TIME } from '../../metric-events'; | ||||||
| import type { Logger, LogProvider } from '../../logger'; | import type { Logger } from '../../logger'; | ||||||
| import type { | import type { | ||||||
|     IFeatureToggleClient, |     IFeatureToggleClient, | ||||||
|     IFeatureToggleClientStore, |     IFeatureToggleClientStore, | ||||||
| @ -9,6 +9,7 @@ import type { | |||||||
|     IFlagResolver, |     IFlagResolver, | ||||||
|     IStrategyConfig, |     IStrategyConfig, | ||||||
|     ITag, |     ITag, | ||||||
|  |     IUnleashConfig, | ||||||
|     PartialDeep, |     PartialDeep, | ||||||
| } from '../../types'; | } from '../../types'; | ||||||
| import { | import { | ||||||
| @ -46,11 +47,16 @@ export default class FeatureToggleClientStore | |||||||
| 
 | 
 | ||||||
|     private flagResolver: IFlagResolver; |     private flagResolver: IFlagResolver; | ||||||
| 
 | 
 | ||||||
|  |     private readonly isOss: boolean; | ||||||
|  | 
 | ||||||
|     constructor( |     constructor( | ||||||
|         db: Db, |         db: Db, | ||||||
|         eventBus: EventEmitter, |         eventBus: EventEmitter, | ||||||
|         getLogger: LogProvider, |         { | ||||||
|         flagResolver: IFlagResolver, |             getLogger, | ||||||
|  |             flagResolver, | ||||||
|  |             isOss, | ||||||
|  |         }: Pick<IUnleashConfig, 'getLogger' | 'flagResolver' | 'isOss'>, | ||||||
|     ) { |     ) { | ||||||
|         this.db = db; |         this.db = db; | ||||||
|         this.logger = getLogger('feature-toggle-client-store.ts'); |         this.logger = getLogger('feature-toggle-client-store.ts'); | ||||||
| @ -60,6 +66,7 @@ export default class FeatureToggleClientStore | |||||||
|                 action, |                 action, | ||||||
|             }); |             }); | ||||||
|         this.flagResolver = flagResolver; |         this.flagResolver = flagResolver; | ||||||
|  |         this.isOss = isOss; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private async getAll({ |     private async getAll({ | ||||||
| @ -72,7 +79,6 @@ export default class FeatureToggleClientStore | |||||||
|         const isPlayground = requestType === 'playground'; |         const isPlayground = requestType === 'playground'; | ||||||
|         const environment = featureQuery?.environment || DEFAULT_ENV; |         const environment = featureQuery?.environment || DEFAULT_ENV; | ||||||
|         const stopTimer = this.timer(`getAllBy${requestType}`); |         const stopTimer = this.timer(`getAllBy${requestType}`); | ||||||
| 
 |  | ||||||
|         let selectColumns = [ |         let selectColumns = [ | ||||||
|             'features.name as name', |             'features.name as name', | ||||||
|             'features.description as description', |             'features.description as description', | ||||||
| @ -103,6 +109,10 @@ export default class FeatureToggleClientStore | |||||||
| 
 | 
 | ||||||
|         let query = this.db('features') |         let query = this.db('features') | ||||||
|             .modify(FeatureToggleStore.filterByArchived, archived) |             .modify(FeatureToggleStore.filterByArchived, archived) | ||||||
|  |             .modify( | ||||||
|  |                 FeatureToggleStore.filterByProjectsAccessibleByOss, | ||||||
|  |                 this.isOss, | ||||||
|  |             ) | ||||||
|             .leftJoin( |             .leftJoin( | ||||||
|                 this.db('feature_strategies') |                 this.db('feature_strategies') | ||||||
|                     .select('*') |                     .select('*') | ||||||
|  | |||||||
| @ -10,13 +10,10 @@ export const createClientFeatureToggleService = ( | |||||||
|     db: Db, |     db: Db, | ||||||
|     config: IUnleashConfig, |     config: IUnleashConfig, | ||||||
| ): ClientFeatureToggleService => { | ): ClientFeatureToggleService => { | ||||||
|     const { getLogger, eventBus, flagResolver } = config; |  | ||||||
| 
 |  | ||||||
|     const featureToggleClientStore = new FeatureToggleClientStore( |     const featureToggleClientStore = new FeatureToggleClientStore( | ||||||
|         db, |         db, | ||||||
|         eventBus, |         config.eventBus, | ||||||
|         getLogger, |         config, | ||||||
|         flagResolver, |  | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     const segmentReadModel = new SegmentReadModel(db); |     const segmentReadModel = new SegmentReadModel(db); | ||||||
| @ -26,7 +23,7 @@ export const createClientFeatureToggleService = ( | |||||||
|             clientFeatureToggleStore: featureToggleClientStore, |             clientFeatureToggleStore: featureToggleClientStore, | ||||||
|         }, |         }, | ||||||
|         segmentReadModel, |         segmentReadModel, | ||||||
|         { getLogger, flagResolver }, |         config, | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     return clientFeatureToggleService; |     return clientFeatureToggleService; | ||||||
| @ -35,8 +32,6 @@ export const createClientFeatureToggleService = ( | |||||||
| export const createFakeClientFeatureToggleService = ( | export const createFakeClientFeatureToggleService = ( | ||||||
|     config: IUnleashConfig, |     config: IUnleashConfig, | ||||||
| ): ClientFeatureToggleService => { | ): ClientFeatureToggleService => { | ||||||
|     const { getLogger, flagResolver } = config; |  | ||||||
| 
 |  | ||||||
|     const fakeClientFeatureToggleStore = new FakeClientFeatureToggleStore(); |     const fakeClientFeatureToggleStore = new FakeClientFeatureToggleStore(); | ||||||
| 
 | 
 | ||||||
|     const fakeSegmentReadModel = new FakeSegmentReadModel(); |     const fakeSegmentReadModel = new FakeSegmentReadModel(); | ||||||
| @ -46,7 +41,7 @@ export const createFakeClientFeatureToggleService = ( | |||||||
|             clientFeatureToggleStore: fakeClientFeatureToggleStore, |             clientFeatureToggleStore: fakeClientFeatureToggleStore, | ||||||
|         }, |         }, | ||||||
|         fakeSegmentReadModel, |         fakeSegmentReadModel, | ||||||
|         { getLogger, flagResolver }, |         config, | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     return clientFeatureToggleService; |     return clientFeatureToggleService; | ||||||
|  | |||||||
| @ -150,12 +150,7 @@ export const deferredExportImportTogglesService = ( | |||||||
|         ); |         ); | ||||||
|         const tagStore = new TagStore(db, eventBus, getLogger); |         const tagStore = new TagStore(db, eventBus, getLogger); | ||||||
|         const tagTypeStore = new TagTypeStore(db, eventBus, getLogger); |         const tagTypeStore = new TagTypeStore(db, eventBus, getLogger); | ||||||
|         const projectStore = new ProjectStore( |         const projectStore = new ProjectStore(db, eventBus, config); | ||||||
|             db, |  | ||||||
|             eventBus, |  | ||||||
|             getLogger, |  | ||||||
|             flagResolver, |  | ||||||
|         ); |  | ||||||
|         const featureTagStore = new FeatureTagStore(db, eventBus, getLogger); |         const featureTagStore = new FeatureTagStore(db, eventBus, getLogger); | ||||||
|         const strategyStore = new StrategyStore(db, getLogger); |         const strategyStore = new StrategyStore(db, getLogger); | ||||||
|         const contextFieldStore = new ContextFieldStore( |         const contextFieldStore = new ContextFieldStore( | ||||||
| @ -172,7 +167,7 @@ export const deferredExportImportTogglesService = ( | |||||||
|         const featureEnvironmentStore = new FeatureEnvironmentStore( |         const featureEnvironmentStore = new FeatureEnvironmentStore( | ||||||
|             db, |             db, | ||||||
|             eventBus, |             eventBus, | ||||||
|             getLogger, |             config, | ||||||
|         ); |         ); | ||||||
|         const eventStore = new EventStore(db, getLogger); |         const eventStore = new EventStore(db, getLogger); | ||||||
|         const accessService = createAccessService(db, config); |         const accessService = createAccessService(db, config); | ||||||
|  | |||||||
| @ -19,11 +19,11 @@ export const createFeatureLifecycleService = | |||||||
|         const { eventBus, getLogger } = config; |         const { eventBus, getLogger } = config; | ||||||
|         const eventStore = new EventStore(db, getLogger); |         const eventStore = new EventStore(db, getLogger); | ||||||
|         const featureLifecycleStore = new FeatureLifecycleStore(db); |         const featureLifecycleStore = new FeatureLifecycleStore(db); | ||||||
|         const environmentStore = new EnvironmentStore(db, eventBus, getLogger); |         const environmentStore = new EnvironmentStore(db, eventBus, config); | ||||||
|         const featureEnvironmentStore = new FeatureEnvironmentStore( |         const featureEnvironmentStore = new FeatureEnvironmentStore( | ||||||
|             db, |             db, | ||||||
|             eventBus, |             eventBus, | ||||||
|             getLogger, |             config, | ||||||
|         ); |         ); | ||||||
|         const eventService = createEventsService(db, config); |         const eventService = createEventsService(db, config); | ||||||
|         const featureLifecycleService = new FeatureLifecycleService( |         const featureLifecycleService = new FeatureLifecycleService( | ||||||
|  | |||||||
| @ -80,19 +80,13 @@ export const createFeatureToggleService = ( | |||||||
|     const featureToggleClientStore = new FeatureToggleClientStore( |     const featureToggleClientStore = new FeatureToggleClientStore( | ||||||
|         db, |         db, | ||||||
|         eventBus, |         eventBus, | ||||||
|         getLogger, |         config, | ||||||
|         flagResolver, |  | ||||||
|     ); |  | ||||||
|     const projectStore = new ProjectStore( |  | ||||||
|         db, |  | ||||||
|         eventBus, |  | ||||||
|         getLogger, |  | ||||||
|         flagResolver, |  | ||||||
|     ); |     ); | ||||||
|  |     const projectStore = new ProjectStore(db, eventBus, config); | ||||||
|     const featureEnvironmentStore = new FeatureEnvironmentStore( |     const featureEnvironmentStore = new FeatureEnvironmentStore( | ||||||
|         db, |         db, | ||||||
|         eventBus, |         eventBus, | ||||||
|         getLogger, |         config, | ||||||
|     ); |     ); | ||||||
|     const contextFieldStore = new ContextFieldStore( |     const contextFieldStore = new ContextFieldStore( | ||||||
|         db, |         db, | ||||||
| @ -105,7 +99,7 @@ export const createFeatureToggleService = ( | |||||||
|     const accessStore = new AccessStore(db, eventBus, getLogger); |     const accessStore = new AccessStore(db, eventBus, getLogger); | ||||||
|     const featureTagStore = new FeatureTagStore(db, eventBus, getLogger); |     const featureTagStore = new FeatureTagStore(db, eventBus, getLogger); | ||||||
|     const roleStore = new RoleStore(db, eventBus, getLogger); |     const roleStore = new RoleStore(db, eventBus, getLogger); | ||||||
|     const environmentStore = new EnvironmentStore(db, eventBus, getLogger); |     const environmentStore = new EnvironmentStore(db, eventBus, config); | ||||||
|     const eventService = createEventsService(db, config); |     const eventService = createEventsService(db, config); | ||||||
|     const groupService = new GroupService( |     const groupService = new GroupService( | ||||||
|         { groupStore, accountStore }, |         { groupStore, accountStore }, | ||||||
|  | |||||||
| @ -439,6 +439,16 @@ export default class FeatureToggleStore implements IFeatureToggleStore { | |||||||
|             : queryBuilder.whereNull('archived_at'); |             : 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 { |     rowToFeature(row: FeaturesTable): FeatureToggle { | ||||||
|         if (!row) { |         if (!row) { | ||||||
|             throw new NotFoundError('No feature flag found'); |             throw new NotFoundError('No feature flag found'); | ||||||
|  | |||||||
| @ -58,13 +58,8 @@ export const createInstanceStatsService = (db: Db, config: IUnleashConfig) => { | |||||||
|         flagResolver, |         flagResolver, | ||||||
|     ); |     ); | ||||||
|     const userStore = new UserStore(db, getLogger, flagResolver); |     const userStore = new UserStore(db, getLogger, flagResolver); | ||||||
|     const projectStore = new ProjectStore( |     const projectStore = new ProjectStore(db, eventBus, config); | ||||||
|         db, |     const environmentStore = new EnvironmentStore(db, eventBus, config); | ||||||
|         eventBus, |  | ||||||
|         getLogger, |  | ||||||
|         flagResolver, |  | ||||||
|     ); |  | ||||||
|     const environmentStore = new EnvironmentStore(db, eventBus, getLogger); |  | ||||||
|     const strategyStore = new StrategyStore(db, getLogger); |     const strategyStore = new StrategyStore(db, getLogger); | ||||||
|     const contextFieldStore = new ContextFieldStore( |     const contextFieldStore = new ContextFieldStore( | ||||||
|         db, |         db, | ||||||
|  | |||||||
| @ -21,21 +21,16 @@ export const createEnvironmentService = | |||||||
|         const featureEnvironmentStore = new FeatureEnvironmentStore( |         const featureEnvironmentStore = new FeatureEnvironmentStore( | ||||||
|             db, |             db, | ||||||
|             eventBus, |             eventBus, | ||||||
|             getLogger, |             config, | ||||||
|         ); |  | ||||||
|         const projectStore = new ProjectStore( |  | ||||||
|             db, |  | ||||||
|             eventBus, |  | ||||||
|             getLogger, |  | ||||||
|             flagResolver, |  | ||||||
|         ); |         ); | ||||||
|  |         const projectStore = new ProjectStore(db, eventBus, config); | ||||||
|         const featureStrategiesStore = new FeatureStrategiesStore( |         const featureStrategiesStore = new FeatureStrategiesStore( | ||||||
|             db, |             db, | ||||||
|             eventBus, |             eventBus, | ||||||
|             getLogger, |             getLogger, | ||||||
|             flagResolver, |             flagResolver, | ||||||
|         ); |         ); | ||||||
|         const environmentStore = new EnvironmentStore(db, eventBus, getLogger); |         const environmentStore = new EnvironmentStore(db, eventBus, config); | ||||||
|         const eventService = createEventsService(db, config); |         const eventService = createEventsService(db, config); | ||||||
|         return new EnvironmentService( |         return new EnvironmentService( | ||||||
|             { |             { | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| import type EventEmitter from 'events'; | import type EventEmitter from 'events'; | ||||||
| import type { Db } from '../../db/db'; | import type { Db } from '../../db/db'; | ||||||
| import type { Logger, LogProvider } from '../../logger'; | import type { Logger } from '../../logger'; | ||||||
| import metricsHelper from '../../util/metrics-helper'; | import metricsHelper from '../../util/metrics-helper'; | ||||||
| import { DB_TIME } from '../../metric-events'; | import { DB_TIME } from '../../metric-events'; | ||||||
| import type { | import type { | ||||||
| @ -12,6 +12,7 @@ import NotFoundError from '../../error/notfound-error'; | |||||||
| import type { IEnvironmentStore } from './environment-store-type'; | import type { IEnvironmentStore } from './environment-store-type'; | ||||||
| import { snakeCaseKeys } from '../../util/snakeCase'; | import { snakeCaseKeys } from '../../util/snakeCase'; | ||||||
| import type { CreateFeatureStrategySchema } from '../../openapi'; | import type { CreateFeatureStrategySchema } from '../../openapi'; | ||||||
|  | import type { IUnleashConfig } from '../../types'; | ||||||
| 
 | 
 | ||||||
| interface IEnvironmentsTable { | interface IEnvironmentsTable { | ||||||
|     name: string; |     name: string; | ||||||
| @ -104,11 +105,18 @@ export default class EnvironmentStore implements IEnvironmentStore { | |||||||
| 
 | 
 | ||||||
|     private db: Db; |     private db: Db; | ||||||
| 
 | 
 | ||||||
|  |     private isOss: boolean; | ||||||
|  | 
 | ||||||
|     private timer: (string) => any; |     private timer: (string) => any; | ||||||
| 
 | 
 | ||||||
|     constructor(db: Db, eventBus: EventEmitter, getLogger: LogProvider) { |     constructor( | ||||||
|  |         db: Db, | ||||||
|  |         eventBus: EventEmitter, | ||||||
|  |         { getLogger, isOss }: Pick<IUnleashConfig, 'getLogger' | 'isOss'>, | ||||||
|  |     ) { | ||||||
|         this.db = db; |         this.db = db; | ||||||
|         this.logger = getLogger('db/environment-store.ts'); |         this.logger = getLogger('db/environment-store.ts'); | ||||||
|  |         this.isOss = isOss; | ||||||
|         this.timer = (action) => |         this.timer = (action) => | ||||||
|             metricsHelper.wrapTimer(eventBus, DB_TIME, { |             metricsHelper.wrapTimer(eventBus, DB_TIME, { | ||||||
|                 store: 'environment', |                 store: 'environment', | ||||||
| @ -148,9 +156,15 @@ export default class EnvironmentStore implements IEnvironmentStore { | |||||||
| 
 | 
 | ||||||
|     async get(key: string): Promise<IEnvironment> { |     async get(key: string): Promise<IEnvironment> { | ||||||
|         const stopTimer = this.timer('get'); |         const stopTimer = this.timer('get'); | ||||||
|         const row = await this.db<IEnvironmentsTable>(TABLE) |         let keyQuery = this.db<IEnvironmentsTable>(TABLE).where({ name: key }); | ||||||
|             .where({ name: key }) |         if (this.isOss) { | ||||||
|             .first(); |             keyQuery = keyQuery.whereIn('name', [ | ||||||
|  |                 'default', | ||||||
|  |                 'development', | ||||||
|  |                 'production', | ||||||
|  |             ]); | ||||||
|  |         } | ||||||
|  |         const row = await keyQuery.first(); | ||||||
|         stopTimer(); |         stopTimer(); | ||||||
|         if (row) { |         if (row) { | ||||||
|             return mapRow(row); |             return mapRow(row); | ||||||
| @ -169,6 +183,9 @@ export default class EnvironmentStore implements IEnvironmentStore { | |||||||
|         if (query) { |         if (query) { | ||||||
|             qB = qB.where(query); |             qB = qB.where(query); | ||||||
|         } |         } | ||||||
|  |         if (this.isOss) { | ||||||
|  |             qB = qB.whereIn('name', ['default', 'development', 'production']); | ||||||
|  |         } | ||||||
|         const rows = await qB; |         const rows = await qB; | ||||||
|         stopTimer(); |         stopTimer(); | ||||||
|         return rows.map(mapRow); |         return rows.map(mapRow); | ||||||
| @ -196,6 +213,9 @@ export default class EnvironmentStore implements IEnvironmentStore { | |||||||
|         if (query) { |         if (query) { | ||||||
|             qB = qB.where(query); |             qB = qB.where(query); | ||||||
|         } |         } | ||||||
|  |         if (this.isOss) { | ||||||
|  |             qB = qB.whereIn('name', ['default', 'development', 'production']); | ||||||
|  |         } | ||||||
|         const rows = await qB; |         const rows = await qB; | ||||||
|         stopTimer(); |         stopTimer(); | ||||||
|         return rows.map(mapRowWithCounts); |         return rows.map(mapRowWithCounts); | ||||||
| @ -230,6 +250,13 @@ export default class EnvironmentStore implements IEnvironmentStore { | |||||||
|         if (query) { |         if (query) { | ||||||
|             qB = qB.where(query); |             qB = qB.where(query); | ||||||
|         } |         } | ||||||
|  |         if (this.isOss) { | ||||||
|  |             qB = qB.whereIn('environments.name', [ | ||||||
|  |                 'default', | ||||||
|  |                 'production', | ||||||
|  |                 'development', | ||||||
|  |             ]); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         const rows = await qB; |         const rows = await qB; | ||||||
|         stopTimer(); |         stopTimer(); | ||||||
|  | |||||||
| @ -16,12 +16,7 @@ export const createProjectInsightsService = ( | |||||||
|     config: IUnleashConfig, |     config: IUnleashConfig, | ||||||
| ): ProjectInsightsService => { | ): ProjectInsightsService => { | ||||||
|     const { eventBus, getLogger, flagResolver } = config; |     const { eventBus, getLogger, flagResolver } = config; | ||||||
|     const projectStore = new ProjectStore( |     const projectStore = new ProjectStore(db, eventBus, config); | ||||||
|         db, |  | ||||||
|         eventBus, |  | ||||||
|         getLogger, |  | ||||||
|         flagResolver, |  | ||||||
|     ); |  | ||||||
|     const featureToggleStore = new FeatureToggleStore( |     const featureToggleStore = new FeatureToggleStore( | ||||||
|         db, |         db, | ||||||
|         eventBus, |         eventBus, | ||||||
|  | |||||||
| @ -24,12 +24,7 @@ export const createProjectStatusService = ( | |||||||
|     config: IUnleashConfig, |     config: IUnleashConfig, | ||||||
| ): ProjectStatusService => { | ): ProjectStatusService => { | ||||||
|     const eventStore = new EventStore(db, config.getLogger); |     const eventStore = new EventStore(db, config.getLogger); | ||||||
|     const projectStore = new ProjectStore( |     const projectStore = new ProjectStore(db, config.eventBus, config); | ||||||
|         db, |  | ||||||
|         config.eventBus, |  | ||||||
|         config.getLogger, |  | ||||||
|         config.flagResolver, |  | ||||||
|     ); |  | ||||||
|     const apiTokenStore = new ApiTokenStore( |     const apiTokenStore = new ApiTokenStore( | ||||||
|         db, |         db, | ||||||
|         config.eventBus, |         config.eventBus, | ||||||
|  | |||||||
| @ -63,12 +63,7 @@ export const createProjectService = ( | |||||||
| ): ProjectService => { | ): ProjectService => { | ||||||
|     const { eventBus, getLogger, flagResolver } = config; |     const { eventBus, getLogger, flagResolver } = config; | ||||||
|     const eventStore = new EventStore(db, getLogger); |     const eventStore = new EventStore(db, getLogger); | ||||||
|     const projectStore = new ProjectStore( |     const projectStore = new ProjectStore(db, eventBus, config); | ||||||
|         db, |  | ||||||
|         eventBus, |  | ||||||
|         getLogger, |  | ||||||
|         flagResolver, |  | ||||||
|     ); |  | ||||||
|     const projectOwnersReadModel = new ProjectOwnersReadModel(db); |     const projectOwnersReadModel = new ProjectOwnersReadModel(db); | ||||||
|     const projectFlagCreatorsReadModel = new ProjectFlagCreatorsReadModel(db); |     const projectFlagCreatorsReadModel = new ProjectFlagCreatorsReadModel(db); | ||||||
|     const groupStore = new GroupStore(db); |     const groupStore = new GroupStore(db); | ||||||
| @ -79,11 +74,11 @@ export const createProjectService = ( | |||||||
|         flagResolver, |         flagResolver, | ||||||
|     ); |     ); | ||||||
|     const accountStore = new AccountStore(db, getLogger); |     const accountStore = new AccountStore(db, getLogger); | ||||||
|     const environmentStore = new EnvironmentStore(db, eventBus, getLogger); |     const environmentStore = new EnvironmentStore(db, eventBus, config); | ||||||
|     const featureEnvironmentStore = new FeatureEnvironmentStore( |     const featureEnvironmentStore = new FeatureEnvironmentStore( | ||||||
|         db, |         db, | ||||||
|         eventBus, |         eventBus, | ||||||
|         getLogger, |         config, | ||||||
|     ); |     ); | ||||||
|     const projectStatsStore = new ProjectStatsStore(db, eventBus, getLogger); |     const projectStatsStore = new ProjectStatsStore(db, eventBus, getLogger); | ||||||
|     const accessService: AccessService = createAccessService(db, config); |     const accessService: AccessService = createAccessService(db, config); | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| import type { Logger, LogProvider } from '../../logger'; | import type { Logger } from '../../logger'; | ||||||
| 
 | 
 | ||||||
| import NotFoundError from '../../error/notfound-error'; | import NotFoundError from '../../error/notfound-error'; | ||||||
| import type { | import type { | ||||||
| @ -8,6 +8,7 @@ import type { | |||||||
|     IProjectApplication, |     IProjectApplication, | ||||||
|     IProjectApplications, |     IProjectApplications, | ||||||
|     IProjectUpdate, |     IProjectUpdate, | ||||||
|  |     IUnleashConfig, | ||||||
|     ProjectMode, |     ProjectMode, | ||||||
| } from '../../types'; | } from '../../types'; | ||||||
| import type { | import type { | ||||||
| @ -72,11 +73,16 @@ class ProjectStore implements IProjectStore { | |||||||
| 
 | 
 | ||||||
|     private timer: Function; |     private timer: Function; | ||||||
| 
 | 
 | ||||||
|  |     private isOss: boolean; | ||||||
|  | 
 | ||||||
|     constructor( |     constructor( | ||||||
|         db: Db, |         db: Db, | ||||||
|         eventBus: EventEmitter, |         eventBus: EventEmitter, | ||||||
|         getLogger: LogProvider, |         { | ||||||
|         flagResolver: IFlagResolver, |             getLogger, | ||||||
|  |             flagResolver, | ||||||
|  |             isOss, | ||||||
|  |         }: Pick<IUnleashConfig, 'getLogger' | 'flagResolver' | 'isOss'>, | ||||||
|     ) { |     ) { | ||||||
|         this.db = db; |         this.db = db; | ||||||
|         this.logger = getLogger('project-store.ts'); |         this.logger = getLogger('project-store.ts'); | ||||||
| @ -86,6 +92,7 @@ class ProjectStore implements IProjectStore { | |||||||
|                 action, |                 action, | ||||||
|             }); |             }); | ||||||
|         this.flagResolver = flagResolver; |         this.flagResolver = flagResolver; | ||||||
|  |         this.isOss = isOss; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
 |     // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
 | ||||||
| @ -122,6 +129,9 @@ class ProjectStore implements IProjectStore { | |||||||
|             .orderBy('name', 'asc'); |             .orderBy('name', 'asc'); | ||||||
| 
 | 
 | ||||||
|         projects = projects.where(`${TABLE}.archived_at`, null); |         projects = projects.where(`${TABLE}.archived_at`, null); | ||||||
|  |         if (this.isOss) { | ||||||
|  |             projects = projects.where('id', 'default'); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         const rows = await projects; |         const rows = await projects; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -143,6 +143,7 @@ export interface IUnleashOptions { | |||||||
|     metricsRateLimiting?: Partial<IMetricsRateLimiting>; |     metricsRateLimiting?: Partial<IMetricsRateLimiting>; | ||||||
|     dailyMetricsStorageDays?: number; |     dailyMetricsStorageDays?: number; | ||||||
|     rateLimiting?: Partial<IRateLimiting>; |     rateLimiting?: Partial<IRateLimiting>; | ||||||
|  |     isOss?: boolean; | ||||||
|     resourceLimits?: Partial< |     resourceLimits?: Partial< | ||||||
|         Pick< |         Pick< | ||||||
|             ResourceLimitsSchema, |             ResourceLimitsSchema, | ||||||
| @ -273,6 +274,7 @@ export interface IUnleashConfig { | |||||||
|     publicFolder?: string; |     publicFolder?: string; | ||||||
|     disableScheduler?: boolean; |     disableScheduler?: boolean; | ||||||
|     isEnterprise: boolean; |     isEnterprise: boolean; | ||||||
|  |     isOss: boolean; | ||||||
|     rateLimiting: IRateLimiting; |     rateLimiting: IRateLimiting; | ||||||
|     feedbackUriPath?: string; |     feedbackUriPath?: string; | ||||||
|     openAIAPIKey?: string; |     openAIAPIKey?: string; | ||||||
|  | |||||||
							
								
								
									
										68
									
								
								src/test/e2e/api/admin/environment-oss.e2e.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/test/e2e/api/admin/environment-oss.e2e.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,68 @@ | |||||||
|  | import { | ||||||
|  |     type IUnleashTest, | ||||||
|  |     setupAppWithCustomConfig, | ||||||
|  | } from '../../helpers/test-helper'; | ||||||
|  | import dbInit, { type ITestDb } from '../../helpers/database-init'; | ||||||
|  | import getLogger from '../../../fixtures/no-logger'; | ||||||
|  | 
 | ||||||
|  | let app: IUnleashTest; | ||||||
|  | let db: ITestDb; | ||||||
|  | 
 | ||||||
|  | beforeAll(async () => { | ||||||
|  |     db = await dbInit('environment_api_is_oss_serial', getLogger, { | ||||||
|  |         isOss: true, | ||||||
|  |     }); | ||||||
|  |     app = await setupAppWithCustomConfig( | ||||||
|  |         db.stores, | ||||||
|  |         { | ||||||
|  |             experimental: { | ||||||
|  |                 flags: { | ||||||
|  |                     strictSchemaValidation: true, | ||||||
|  |                 }, | ||||||
|  |             }, | ||||||
|  |             isOss: true, | ||||||
|  |         }, | ||||||
|  |         db.rawDatabase, | ||||||
|  |     ); | ||||||
|  |     await db.stores.environmentStore.create({ | ||||||
|  |         name: 'development', | ||||||
|  |         type: 'development', | ||||||
|  |         enabled: true, | ||||||
|  |     }); | ||||||
|  |     await db.stores.environmentStore.create({ | ||||||
|  |         name: 'production', | ||||||
|  |         type: 'production', | ||||||
|  |         enabled: true, | ||||||
|  |     }); | ||||||
|  |     await db.stores.environmentStore.create({ | ||||||
|  |         name: 'customenvironment', | ||||||
|  |         type: 'production', | ||||||
|  |         enabled: true, | ||||||
|  |     }); | ||||||
|  |     await db.stores.environmentStore.create({ | ||||||
|  |         name: 'customenvironment2', | ||||||
|  |         type: 'production', | ||||||
|  |         enabled: true, | ||||||
|  |     }); | ||||||
|  |     await db.stores.environmentStore.create({ | ||||||
|  |         name: 'customenvironment3', | ||||||
|  |         type: 'production', | ||||||
|  |         enabled: true, | ||||||
|  |     }); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | afterAll(async () => { | ||||||
|  |     await app.destroy(); | ||||||
|  |     await db.destroy(); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | test('querying environments in OSS only returns environments that are included in oss', async () => { | ||||||
|  |     await app.request | ||||||
|  |         .get('/api/admin/environments') | ||||||
|  |         .expect(200) | ||||||
|  |         .expect((res) => { | ||||||
|  |             expect(res.body.environments).toHaveLength(3); | ||||||
|  |             const names = res.body.environments.map((env) => env.name); | ||||||
|  |             expect(names).toEqual(['default', 'development', 'production']); | ||||||
|  |         }); | ||||||
|  | }); | ||||||
							
								
								
									
										82
									
								
								src/test/e2e/api/client/feature-oss.e2e.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/test/e2e/api/client/feature-oss.e2e.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,82 @@ | |||||||
|  | import getLogger from '../../../fixtures/no-logger'; | ||||||
|  | import { | ||||||
|  |     type IUnleashTest, | ||||||
|  |     setupAppWithCustomConfig, | ||||||
|  | } from '../../helpers/test-helper'; | ||||||
|  | import dbInit from '../../helpers/database-init'; | ||||||
|  | import type { ITestDb } from '../../helpers/database-init'; | ||||||
|  | import type { IAuditUser, IUser } from '../../../../lib/types'; | ||||||
|  | 
 | ||||||
|  | let app: IUnleashTest; | ||||||
|  | let db: ITestDb; | ||||||
|  | let testUser: IUser; | ||||||
|  | const auditUser = { | ||||||
|  |     username: 'audituser', | ||||||
|  |     id: -42, | ||||||
|  |     ip: 'localhost', | ||||||
|  | } as IAuditUser; | ||||||
|  | 
 | ||||||
|  | let userIndex = 0; | ||||||
|  | const createUser = async (role?: number) => { | ||||||
|  |     const name = `User ${userIndex}`; | ||||||
|  |     const email = `user-${userIndex}@getunleash.io`; | ||||||
|  |     userIndex++; | ||||||
|  | 
 | ||||||
|  |     const { userStore } = db.stores; | ||||||
|  |     return userStore.insert({ name, email }); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | beforeAll(async () => { | ||||||
|  |     db = await dbInit('feature_api_client_is_oss', getLogger, { isOss: true }); | ||||||
|  |     app = await setupAppWithCustomConfig( | ||||||
|  |         db.stores, | ||||||
|  |         { | ||||||
|  |             experimental: { | ||||||
|  |                 flags: { | ||||||
|  |                     strictSchemaValidation: true, | ||||||
|  |                 }, | ||||||
|  |             }, | ||||||
|  |             isOss: true, | ||||||
|  |         }, | ||||||
|  |         db.rawDatabase, | ||||||
|  |     ); | ||||||
|  |     testUser = await createUser(); | ||||||
|  |     await app.services.projectService.createProject( | ||||||
|  |         { id: 'secondproject', name: 'Second project not returned when oss' }, | ||||||
|  |         testUser, | ||||||
|  |         auditUser, | ||||||
|  |     ); | ||||||
|  |     await app.services.featureToggleService.createFeatureToggle( | ||||||
|  |         'secondproject', | ||||||
|  |         { | ||||||
|  |             name: 'my.feature.toggle', | ||||||
|  |         }, | ||||||
|  |         auditUser, | ||||||
|  |         true, | ||||||
|  |     ); | ||||||
|  |     await app.services.featureToggleService.createFeatureToggle( | ||||||
|  |         'default', | ||||||
|  |         { | ||||||
|  |             name: 'my.default.toggle', | ||||||
|  |         }, | ||||||
|  |         auditUser, | ||||||
|  |         true, | ||||||
|  |     ); | ||||||
|  | }); | ||||||
|  | afterAll(async () => { | ||||||
|  |     await app.destroy(); | ||||||
|  |     await db.destroy(); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | describe('OSS downgrade', () => { | ||||||
|  |     test('features created in projects other than default is not visible in client endpoint', async () => { | ||||||
|  |         return app.request | ||||||
|  |             .get('/api/client/features') | ||||||
|  |             .expect('Content-Type', /json/) | ||||||
|  |             .expect(200) | ||||||
|  |             .expect((res) => { | ||||||
|  |                 expect(res.body.features).toHaveLength(1); | ||||||
|  |                 expect(res.body.features[0].name).toBe('my.default.toggle'); | ||||||
|  |             }); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user