mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-09 00:18:00 +01:00
chore: move enterprise check further left, prevent OSS from seeing CR usage (#5431)
This PR checks that the unleash instance is an enterprise instance before fetching change request data. This is to prevent Change Request usage from preventing OSS users from deleting segments (when they don't have access to change requests). This PR also does a little bit of refactoring (which we can remove if you want)
This commit is contained in:
parent
c0369b739e
commit
1a754325de
@ -354,31 +354,6 @@ export class SegmentsController extends Controller {
|
|||||||
user.id,
|
user.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.flagResolver.isEnabled('detectSegmentUsageInChangeRequests')) {
|
|
||||||
const mapStrategies = (strategy) => ({
|
|
||||||
id: strategy.id,
|
|
||||||
projectId: strategy.projectId,
|
|
||||||
featureName: strategy.featureName,
|
|
||||||
strategyName: strategy.strategyName,
|
|
||||||
environment: strategy.environment,
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapChangeRequestStrategies = (strategy) => ({
|
|
||||||
...(strategy.id ? { id: strategy.id } : {}),
|
|
||||||
projectId: strategy.projectId,
|
|
||||||
featureName: strategy.featureName,
|
|
||||||
strategyName: strategy.strategyName,
|
|
||||||
environment: strategy.environment,
|
|
||||||
changeRequest: strategy.changeRequest,
|
|
||||||
});
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
strategies: strategies.strategies.map(mapStrategies),
|
|
||||||
changeRequestStrategies: strategies.changeRequestStrategies.map(
|
|
||||||
mapChangeRequestStrategies,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const segmentStrategies = strategies.strategies.map((strategy) => ({
|
const segmentStrategies = strategies.strategies.map((strategy) => ({
|
||||||
id: strategy.id,
|
id: strategy.id,
|
||||||
projectId: strategy.projectId,
|
projectId: strategy.projectId,
|
||||||
@ -387,6 +362,22 @@ export class SegmentsController extends Controller {
|
|||||||
environment: strategy.environment,
|
environment: strategy.environment,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if (this.flagResolver.isEnabled('detectSegmentUsageInChangeRequests')) {
|
||||||
|
const changeRequestStrategies =
|
||||||
|
strategies.changeRequestStrategies.map((strategy) => ({
|
||||||
|
...('id' in strategy ? { id: strategy.id } : {}),
|
||||||
|
projectId: strategy.projectId,
|
||||||
|
featureName: strategy.featureName,
|
||||||
|
strategyName: strategy.strategyName,
|
||||||
|
environment: strategy.environment,
|
||||||
|
changeRequest: strategy.changeRequest,
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
strategies: segmentStrategies,
|
||||||
|
changeRequestStrategies,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
res.json({ strategies: segmentStrategies });
|
res.json({ strategies: segmentStrategies });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,6 +119,10 @@ export class SegmentService implements ISegmentService {
|
|||||||
const strategies =
|
const strategies =
|
||||||
await this.featureStrategiesStore.getStrategiesBySegment(id);
|
await this.featureStrategiesStore.getStrategiesBySegment(id);
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.flagResolver.isEnabled('detectSegmentUsageInChangeRequests') &&
|
||||||
|
this.config.isEnterprise
|
||||||
|
) {
|
||||||
const changeRequestStrategies =
|
const changeRequestStrategies =
|
||||||
await this.changeRequestSegmentUsageReadModel.getStrategiesUsedInActiveChangeRequests(
|
await this.changeRequestSegmentUsageReadModel.getStrategiesUsedInActiveChangeRequests(
|
||||||
id,
|
id,
|
||||||
@ -127,6 +131,9 @@ export class SegmentService implements ISegmentService {
|
|||||||
return { strategies, changeRequestStrategies };
|
return { strategies, changeRequestStrategies };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return { strategies, changeRequestStrategies: [] };
|
||||||
|
}
|
||||||
|
|
||||||
async isInUse(id: number): Promise<boolean> {
|
async isInUse(id: number): Promise<boolean> {
|
||||||
const { strategies, changeRequestStrategies } =
|
const { strategies, changeRequestStrategies } =
|
||||||
await this.getAllStrategies(id);
|
await this.getAllStrategies(id);
|
||||||
|
@ -435,7 +435,43 @@ describe('detect strategy usage in change requests', () => {
|
|||||||
const CR_ID = 54321;
|
const CR_ID = 54321;
|
||||||
let user;
|
let user;
|
||||||
|
|
||||||
|
// Change request data is only counted for enterprise
|
||||||
|
// instances, so we'll instantiate our own version of the app
|
||||||
|
// for that.
|
||||||
|
let enterpriseApp;
|
||||||
|
|
||||||
|
// likewise, we want to fetch from the right app to make sure
|
||||||
|
// we get the right data
|
||||||
|
const enterpriseFetchSegments = () =>
|
||||||
|
enterpriseApp.request
|
||||||
|
.get(SEGMENTS_BASE_PATH)
|
||||||
|
.expect(200)
|
||||||
|
.then((res) => res.body.segments);
|
||||||
|
|
||||||
|
const enterpriseFetchSegmentStrategies = (
|
||||||
|
segmentId: number,
|
||||||
|
): Promise<StrategiesUsingSegment> =>
|
||||||
|
enterpriseApp.request
|
||||||
|
.get(`${SEGMENTS_BASE_PATH}/${segmentId}/strategies`)
|
||||||
|
.expect(200)
|
||||||
|
.then((res) => res.body);
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
|
enterpriseApp = await setupAppWithCustomConfig(
|
||||||
|
db.stores,
|
||||||
|
{
|
||||||
|
enterpriseVersion: '5.3.0',
|
||||||
|
ui: { environment: 'Enterprise' },
|
||||||
|
isEnterprise: true,
|
||||||
|
experimental: {
|
||||||
|
flags: {
|
||||||
|
detectSegmentUsageInChangeRequests: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
db.rawDatabase,
|
||||||
|
);
|
||||||
|
|
||||||
user = await db.stores.userStore.insert({
|
user = await db.stores.userStore.insert({
|
||||||
username: 'test',
|
username: 'test',
|
||||||
});
|
});
|
||||||
@ -463,8 +499,8 @@ describe('detect strategy usage in change requests', () => {
|
|||||||
test('should not delete segments used by strategies in CRs', async () => {
|
test('should not delete segments used by strategies in CRs', async () => {
|
||||||
await createSegment({ name: 'a', constraints: [] });
|
await createSegment({ name: 'a', constraints: [] });
|
||||||
const toggle = mockFeatureToggle();
|
const toggle = mockFeatureToggle();
|
||||||
await createFeatureToggle(app, toggle);
|
await createFeatureToggle(enterpriseApp, toggle);
|
||||||
const [segment] = await fetchSegments();
|
const [segment] = await enterpriseFetchSegments();
|
||||||
|
|
||||||
await db.rawDatabase.table('change_request_events').insert({
|
await db.rawDatabase.table('change_request_events').insert({
|
||||||
feature: toggle.name,
|
feature: toggle.name,
|
||||||
@ -487,20 +523,25 @@ describe('detect strategy usage in change requests', () => {
|
|||||||
created_by: user.id,
|
created_by: user.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect((await fetchSegments()).length).toEqual(1);
|
expect((await enterpriseFetchSegments()).length).toEqual(1);
|
||||||
|
|
||||||
await app.request
|
await enterpriseApp.request
|
||||||
.delete(`${SEGMENTS_BASE_PATH}/${segment.id}`)
|
.delete(`${SEGMENTS_BASE_PATH}/${segment.id}`)
|
||||||
.expect(409);
|
.expect(409);
|
||||||
|
|
||||||
expect((await fetchSegments()).length).toEqual(1);
|
expect((await enterpriseFetchSegments()).length).toEqual(1);
|
||||||
|
|
||||||
|
// check that it can be deleted in OSS
|
||||||
|
await app.request
|
||||||
|
.delete(`${SEGMENTS_BASE_PATH}/${segment.id}`)
|
||||||
|
.expect(204);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should show segment usage in addStrategy events', async () => {
|
test('Should show segment usage in addStrategy events', async () => {
|
||||||
await createSegment({ name: 'a', constraints: [] });
|
await createSegment({ name: 'a', constraints: [] });
|
||||||
const toggle = mockFeatureToggle();
|
const toggle = mockFeatureToggle();
|
||||||
await createFeatureToggle(app, toggle);
|
await createFeatureToggle(enterpriseApp, toggle);
|
||||||
const [segment] = await fetchSegments();
|
const [segment] = await enterpriseFetchSegments();
|
||||||
|
|
||||||
await db.rawDatabase.table('change_request_events').insert({
|
await db.rawDatabase.table('change_request_events').insert({
|
||||||
feature: toggle.name,
|
feature: toggle.name,
|
||||||
@ -524,7 +565,7 @@ describe('detect strategy usage in change requests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { strategies, changeRequestStrategies } =
|
const { strategies, changeRequestStrategies } =
|
||||||
await fetchSegmentStrategies(segment.id);
|
await enterpriseFetchSegmentStrategies(segment.id);
|
||||||
|
|
||||||
expect(changeRequestStrategies).toMatchObject([
|
expect(changeRequestStrategies).toMatchObject([
|
||||||
{
|
{
|
||||||
@ -536,16 +577,21 @@ describe('detect strategy usage in change requests', () => {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
expect(strategies).toStrictEqual([]);
|
expect(strategies).toStrictEqual([]);
|
||||||
|
|
||||||
|
// check that OSS gets no CR strategies
|
||||||
|
const ossResult = await fetchSegmentStrategies(segment.id);
|
||||||
|
expect(ossResult.strategies).toStrictEqual([]);
|
||||||
|
expect(ossResult.changeRequestStrategies ?? []).toStrictEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should show segment usage in updateStrategy events', async () => {
|
test('Should show segment usage in updateStrategy events', async () => {
|
||||||
await createSegment({ name: 'a', constraints: [] });
|
await createSegment({ name: 'a', constraints: [] });
|
||||||
const toggle = mockFeatureToggle();
|
const toggle = mockFeatureToggle();
|
||||||
await createFeatureToggle(app, toggle);
|
await createFeatureToggle(enterpriseApp, toggle);
|
||||||
const [segment] = await fetchSegments();
|
const [segment] = await enterpriseFetchSegments();
|
||||||
|
|
||||||
await addStrategyToFeatureEnv(
|
await addStrategyToFeatureEnv(
|
||||||
app,
|
enterpriseApp,
|
||||||
{ ...toggle.strategies[0] },
|
{ ...toggle.strategies[0] },
|
||||||
'default',
|
'default',
|
||||||
toggle.name,
|
toggle.name,
|
||||||
@ -578,7 +624,7 @@ describe('detect strategy usage in change requests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { strategies, changeRequestStrategies } =
|
const { strategies, changeRequestStrategies } =
|
||||||
await fetchSegmentStrategies(segment.id);
|
await enterpriseFetchSegmentStrategies(segment.id);
|
||||||
|
|
||||||
expect(changeRequestStrategies).toMatchObject([
|
expect(changeRequestStrategies).toMatchObject([
|
||||||
{
|
{
|
||||||
@ -587,16 +633,21 @@ describe('detect strategy usage in change requests', () => {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
expect(strategies).toStrictEqual([]);
|
expect(strategies).toStrictEqual([]);
|
||||||
|
|
||||||
|
// check that OSS gets no CR strategies
|
||||||
|
const ossResult = await fetchSegmentStrategies(segment.id);
|
||||||
|
expect(ossResult.strategies).toStrictEqual([]);
|
||||||
|
expect(ossResult.changeRequestStrategies ?? []).toStrictEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('If a segment is used in an existing strategy and in a CR for the same strategy, the strategy should be listed both places', async () => {
|
test('If a segment is used in an existing strategy and in a CR for the same strategy, the strategy should be listed both places', async () => {
|
||||||
await createSegment({ name: 'a', constraints: [] });
|
await createSegment({ name: 'a', constraints: [] });
|
||||||
const toggle = mockFeatureToggle();
|
const toggle = mockFeatureToggle();
|
||||||
await createFeatureToggle(app, toggle);
|
await createFeatureToggle(enterpriseApp, toggle);
|
||||||
const [segment] = await fetchSegments();
|
const [segment] = await enterpriseFetchSegments();
|
||||||
|
|
||||||
await addStrategyToFeatureEnv(
|
await addStrategyToFeatureEnv(
|
||||||
app,
|
enterpriseApp,
|
||||||
{ ...toggle.strategies[0] },
|
{ ...toggle.strategies[0] },
|
||||||
'default',
|
'default',
|
||||||
toggle.name,
|
toggle.name,
|
||||||
@ -630,39 +681,19 @@ describe('detect strategy usage in change requests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { strategies, changeRequestStrategies } =
|
const { strategies, changeRequestStrategies } =
|
||||||
await fetchSegmentStrategies(segment.id);
|
await enterpriseFetchSegmentStrategies(segment.id);
|
||||||
|
|
||||||
expect(strategies).toMatchObject([{ id: strategyId }]);
|
expect(strategies).toMatchObject([{ id: strategyId }]);
|
||||||
|
|
||||||
expect(changeRequestStrategies).toMatchObject([{ id: strategyId }]);
|
expect(changeRequestStrategies).toMatchObject([{ id: strategyId }]);
|
||||||
|
|
||||||
|
// check that OSS gets no CR strategies
|
||||||
|
const ossResult = await fetchSegmentStrategies(segment.id);
|
||||||
|
expect(ossResult.strategies).toMatchObject([{ id: strategyId }]);
|
||||||
|
expect(ossResult.changeRequestStrategies ?? []).toStrictEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should show usage in features and projects in CRs', async () => {
|
test('Should show usage in features and projects in CRs', async () => {
|
||||||
// Change request data is only counted for enterprise
|
|
||||||
// instances, so we'll instantiate our own version of the app
|
|
||||||
// for that.
|
|
||||||
const enterpriseApp = await setupAppWithCustomConfig(
|
|
||||||
db.stores,
|
|
||||||
{
|
|
||||||
enterpriseVersion: '5.3.0',
|
|
||||||
ui: { environment: 'Enterprise' },
|
|
||||||
experimental: {
|
|
||||||
flags: {
|
|
||||||
detectSegmentUsageInChangeRequests: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
db.rawDatabase,
|
|
||||||
);
|
|
||||||
|
|
||||||
// likewise, we want to fetch from the right app to make sure
|
|
||||||
// we get the right data
|
|
||||||
const enterpriseFetchSegments = () =>
|
|
||||||
enterpriseApp.request
|
|
||||||
.get(SEGMENTS_BASE_PATH)
|
|
||||||
.expect(200)
|
|
||||||
.then((res) => res.body.segments);
|
|
||||||
|
|
||||||
// because they use the same db, we can use the regular app
|
// because they use the same db, we can use the regular app
|
||||||
// (through `createSegment` and `createFeatureToggle`) to
|
// (through `createSegment` and `createFeatureToggle`) to
|
||||||
// create the segment and the flag
|
// create the segment and the flag
|
||||||
@ -698,5 +729,11 @@ describe('detect strategy usage in change requests', () => {
|
|||||||
expect(segments).toMatchObject([
|
expect(segments).toMatchObject([
|
||||||
{ usedInFeatures: 1, usedInProjects: 1 },
|
{ usedInFeatures: 1, usedInProjects: 1 },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// check that OSS gets no CR usage
|
||||||
|
const ossSegments = await fetchSegments();
|
||||||
|
expect(ossSegments).toMatchObject([
|
||||||
|
{ usedInFeatures: 0, usedInProjects: 0 },
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user