1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-09 00:18:00 +01:00

Permission guards in existing endpoints interacting with feature toggle configuration (#2418)

This PR adds permission guards for operations.

1. Toggling feature flag
2. Adding a strategy
3. Updating a strategy
4. Deleting a strategy
This commit is contained in:
sjaanus 2022-11-14 14:05:26 +01:00 committed by GitHub
parent 3624cdc21f
commit 131ebb931a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 1 deletions

View File

@ -27,6 +27,7 @@ const T = {
ROLE_PERMISSION: 'role_permission',
PERMISSIONS: 'permissions',
PERMISSION_TYPES: 'permission_types',
CHANGE_REQUEST_SETTINGS: 'change_request_settings',
};
interface IPermissionRow {
@ -448,4 +449,17 @@ export class AccessStore implements IAccessStore {
[destinationEnvironment, sourceEnvironment],
);
}
async isChangeRequestsEnabled(
project: string,
environment: string,
): Promise<boolean> {
const result = await this.db.raw(
`SELECT EXISTS(SELECT 1 FROM ${T.CHANGE_REQUEST_SETTINGS}
WHERE environment = ? and project = ?) AS present`,
[environment, project],
);
const { present } = result.rows[0];
return present;
}
}

View File

@ -542,4 +542,11 @@ export class AccessService {
await this.validateRoleIsUnique(role.name, existingId);
return cleanedRole;
}
async isChangeRequestsEnabled(
project: string,
environment: string,
): Promise<boolean> {
return this.store.isChangeRequestsEnabled(project, environment);
}
}

View File

@ -314,6 +314,11 @@ class FeatureToggleService {
const { featureName, projectId, environment } = context;
await this.validateFeatureContext(context);
if (await this.changeRequestsEnabled(projectId, environment)) {
throw new Error(
`Strategies can only be created through change requests for ${environment} environment`,
);
}
if (strategyConfig.constraints?.length > 0) {
strategyConfig.constraints = await this.validateConstraints(
strategyConfig.constraints,
@ -382,6 +387,12 @@ class FeatureToggleService {
const existingStrategy = await this.featureStrategiesStore.get(id);
this.validateFeatureStrategyContext(existingStrategy, context);
if (await this.changeRequestsEnabled(projectId, environment)) {
throw new Error(
`Strategies can only be updated through change requests for ${environment} environment`,
);
}
if (existingStrategy.id === id) {
if (updates.constraints?.length > 0) {
updates.constraints = await this.validateConstraints(
@ -430,6 +441,12 @@ class FeatureToggleService {
): Promise<Saved<IStrategyConfig>> {
const { projectId, environment, featureName } = context;
if (await this.changeRequestsEnabled(projectId, environment)) {
throw new Error(
`Strategies can only be updated through change requests for ${environment} environment`,
);
}
const existingStrategy = await this.featureStrategiesStore.get(id);
this.validateFeatureStrategyContext(existingStrategy, context);
@ -482,6 +499,12 @@ class FeatureToggleService {
const { featureName, projectId, environment } = context;
this.validateFeatureStrategyContext(existingStrategy, context);
if (await this.changeRequestsEnabled(projectId, environment)) {
throw new Error(
`Strategies can only deleted updated through change requests for ${environment} environment`,
);
}
await this.featureStrategiesStore.delete(id);
const tags = await this.tagStore.getAllTagsForFeature(featureName);
@ -903,6 +926,12 @@ class FeatureToggleService {
createdBy: string,
user?: User,
): Promise<FeatureToggle> {
if (await this.changeRequestsEnabled(project, environment)) {
throw new Error(
`Features can only be updated through change requests for ${environment} environment`,
);
}
const hasEnvironment =
await this.featureEnvironmentStore.featureHasEnvironment(
environment,
@ -928,7 +957,11 @@ class FeatureToggleService {
if (canAddStrategies) {
await this.createStrategy(
getDefaultStrategy(featureName),
{ environment, projectId: project, featureName },
{
environment,
projectId: project,
featureName,
},
createdBy,
);
} else {
@ -961,6 +994,7 @@ class FeatureToggleService {
}
return feature;
}
throw new NotFoundError(
`Could not find environment ${environment} for feature: ${featureName}`,
);
@ -1186,6 +1220,13 @@ class FeatureToggleService {
});
return variableVariants.concat(fixedVariants);
}
changeRequestsEnabled(
project: string,
environment: string,
): Promise<boolean> {
return this.accessService.isChangeRequestsEnabled(project, environment);
}
}
export default FeatureToggleService;

View File

@ -132,4 +132,9 @@ export interface IAccessStore extends Store<IRole, number> {
sourceEnvironment: string,
destinationEnvironment: string,
): Promise<void>;
isChangeRequestsEnabled(
project: string,
environment: string,
): Promise<boolean>;
}

View File

@ -11,6 +11,13 @@ import {
import { IPermission } from 'lib/types/model';
class AccessStoreMock implements IAccessStore {
isChangeRequestsEnabled(
project: string,
environment: string,
): Promise<boolean> {
throw new Error('Method not implemented.');
}
addAccessToProject(
users: IAccessInfo[],
groups: IAccessInfo[],