Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: only display oss included projects/environments when install is oss #8896

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/lib/__snapshots__/create-config.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ exports[`should create default config 1`] = `
},
"inlineSegmentConstraints": true,
"isEnterprise": false,
"isOss": false,
"listen": {
"host": undefined,
"port": 4242,
Expand Down
35 changes: 34 additions & 1 deletion src/lib/create-config.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createConfig } from './create-config';
import { createConfig, resolveIsOss } from './create-config';
import { ApiTokenType } from './types/models/api-token';

test('should create default config', async () => {
Expand Down Expand Up @@ -498,3 +498,36 @@ test('Config with enterpriseVersion set and not pro environment should set isEnt
});
expect(config.isEnterprise).toBe(true);
});

describe('isOSS', () => {
test('Config with pro environment should set isOss to false regardless of pro casing', async () => {
const isOss = resolveIsOss(false, false, 'Pro');
expect(isOss).toBe(false);
const lowerCase = resolveIsOss(false, false, 'pro');
expect(lowerCase).toBe(false);
const strangeCase = resolveIsOss(false, false, 'PrO');
expect(strangeCase).toBe(false);
});
test('Config with enterpriseVersion set should set isOss to false', async () => {
const isOss = resolveIsOss(true, false, 'Enterprise');
expect(isOss).toBe(false);
});
test('Config with no enterprise version and any other environment than pro should have isOss as true', async () => {
const isOss = resolveIsOss(false, false, 'my oss environment');
expect(isOss).toBe(true);
});
test('Config with enterprise false and isOss option set to false should return false in test mode', async () => {
const isOss = resolveIsOss(false, false, 'my environment', true);
expect(isOss).toBe(false);
});
test('Config with isOss option set to true should return true when test environment is active', async () => {
let isOss = resolveIsOss(false, true, 'Pro', true);
expect(isOss).toBe(true);

isOss = resolveIsOss(true, true, 'Pro', true);
expect(isOss).toBe(true);

isOss = resolveIsOss(false, true, 'some environment', true);
expect(isOss).toBe(true);
});
});
20 changes: 20 additions & 0 deletions src/lib/create-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,17 @@ const parseFrontendApiOrigins = (options: IUnleashOptions): string[] => {
return frontendApiOrigins;
};

export function resolveIsOss(
isEnterprise: boolean,
isOssOption?: boolean,
uiEnvironment?: string,
testEnvironmentActive: boolean = false,
): boolean {
return testEnvironmentActive
? (isOssOption ?? false)
: !isEnterprise && uiEnvironment?.toLowerCase() !== 'pro';
}

export function createConfig(options: IUnleashOptions): IUnleashConfig {
let extraDbOptions = {};

Expand Down Expand Up @@ -620,6 +631,13 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {
Boolean(options.enterpriseVersion) &&
ui.environment?.toLowerCase() !== 'pro';

const isTest = process.env.NODE_ENV === 'test';
const isOss = resolveIsOss(
isEnterprise,
options.isOss,
ui.environment,
isTest,
);
const metricsRateLimiting = loadMetricsRateLimitingConfig(options);

const rateLimiting = loadRateLimitingConfig(options);
Expand Down Expand Up @@ -760,6 +778,7 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {
publicFolder: options.publicFolder,
disableScheduler: options.disableScheduler,
isEnterprise: isEnterprise,
isOss: isOss,
metricsRateLimiting,
rateLimiting,
feedbackUriPath,
Expand All @@ -771,5 +790,6 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {

module.exports = {
createConfig,
resolveIsOss,
authTypeFromString,
};
31 changes: 29 additions & 2 deletions src/lib/db/feature-environment-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -36,14 +37,20 @@ 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, isOss }: Pick<IUnleashConfig, 'getLogger' | 'isOss'>,
) {
this.db = db;
this.logger = getLogger('feature-environment-store.ts');
this.timer = (action) =>
metricsHelper.wrapTimer(eventBus, DB_TIME, {
store: 'feature-environments',
action,
});
this.isOss = isOss;
}

async delete({
Expand Down Expand Up @@ -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[]> {
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,
Expand All @@ -119,6 +145,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,
Expand Down
14 changes: 4 additions & 10 deletions src/lib/db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -122,15 +117,14 @@ export const createStores = (
clientFeatureToggleStore: new FeatureToggleClientStore(
db,
eventBus,
getLogger,
config.flagResolver,
config,
),
environmentStore: new EnvironmentStore(db, eventBus, getLogger),
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),
Expand Down
2 changes: 1 addition & 1 deletion src/lib/features/access/createAccessService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const createAccessService = (
const groupStore = new GroupStore(db);
const accountStore = new AccountStore(db, 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 eventService = createEventsService(db, config);
const groupService = new GroupService(
Expand Down
2 changes: 1 addition & 1 deletion src/lib/features/api-tokens/createApiTokenService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const createApiTokenService = (
getLogger,
config.flagResolver,
);
const environmentStore = new EnvironmentStore(db, eventBus, getLogger);
const environmentStore = new EnvironmentStore(db, eventBus, config);
const eventService = createEventsService(db, config);

return new ApiTokenService(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
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,
IFeatureToggleQuery,
IFlagResolver,
IStrategyConfig,
ITag,
IUnleashConfig,
PartialDeep,
} from '../../types';
import {
Expand Down Expand Up @@ -46,11 +47,16 @@ export default class FeatureToggleClientStore

private flagResolver: IFlagResolver;

private readonly isOss: boolean;

constructor(
db: Db,
eventBus: EventEmitter,
getLogger: LogProvider,
flagResolver: IFlagResolver,
{
getLogger,
flagResolver,
isOss,
}: Pick<IUnleashConfig, 'getLogger' | 'flagResolver' | 'isOss'>,
) {
this.db = db;
this.logger = getLogger('feature-toggle-client-store.ts');
Expand All @@ -60,6 +66,7 @@ export default class FeatureToggleClientStore
action,
});
this.flagResolver = flagResolver;
this.isOss = isOss;
}

private async getAll({
Expand All @@ -72,7 +79,6 @@ export default class FeatureToggleClientStore
const isPlayground = requestType === 'playground';
const environment = featureQuery?.environment || DEFAULT_ENV;
const stopTimer = this.timer(`getAllBy${requestType}`);

let selectColumns = [
'features.name as name',
'features.description as description',
Expand Down Expand Up @@ -103,6 +109,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('*')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -26,7 +23,7 @@ export const createClientFeatureToggleService = (
clientFeatureToggleStore: featureToggleClientStore,
},
segmentReadModel,
{ getLogger, flagResolver },
config,
);

return clientFeatureToggleService;
Expand All @@ -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();
Expand All @@ -46,7 +41,7 @@ export const createFakeClientFeatureToggleService = (
clientFeatureToggleStore: fakeClientFeatureToggleStore,
},
fakeSegmentReadModel,
{ getLogger, flagResolver },
config,
);

return clientFeatureToggleService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions src/lib/features/feature-lifecycle/createFeatureLifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ export const createFeatureLifecycleService =
const { eventBus, getLogger } = config;
const eventStore = new EventStore(db, getLogger);
const featureLifecycleStore = new FeatureLifecycleStore(db);
const environmentStore = new EnvironmentStore(db, eventBus, getLogger);
const environmentStore = new EnvironmentStore(db, eventBus, config);
const featureEnvironmentStore = new FeatureEnvironmentStore(
db,
eventBus,
getLogger,
config,
);
const eventService = createEventsService(db, config);
const featureLifecycleService = new FeatureLifecycleService(
Expand Down
Loading
Loading