feat: changed dynamic secret mapping to new one, made optional secretname and tag in permission

This commit is contained in:
=
2024-10-17 23:15:57 +05:30
parent 154ea9e55d
commit 2383c93139
16 changed files with 122 additions and 124 deletions

View File

@@ -80,7 +80,7 @@ export const dynamicSecretServiceFactory = ({
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionDynamicSecretActions.Create,
ProjectPermissionDynamicSecretActions.CreateRootCredential,
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
);
@@ -149,7 +149,7 @@ export const dynamicSecretServiceFactory = ({
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionDynamicSecretActions.Edit,
ProjectPermissionDynamicSecretActions.EditRootCredential,
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
);
@@ -228,7 +228,7 @@ export const dynamicSecretServiceFactory = ({
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionDynamicSecretActions.Delete,
ProjectPermissionDynamicSecretActions.DeleteRootCredential,
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
);
@@ -285,11 +285,11 @@ export const dynamicSecretServiceFactory = ({
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionDynamicSecretActions.Read,
ProjectPermissionDynamicSecretActions.ReadRootCredential,
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionDynamicSecretActions.Edit,
ProjectPermissionDynamicSecretActions.EditRootCredential,
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
);
@@ -335,7 +335,7 @@ export const dynamicSecretServiceFactory = ({
// verify user has access to each env in request
environmentSlugs.forEach((environmentSlug) =>
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionDynamicSecretActions.Read,
ProjectPermissionDynamicSecretActions.ReadRootCredential,
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
)
);
@@ -371,7 +371,7 @@ export const dynamicSecretServiceFactory = ({
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionDynamicSecretActions.Read,
ProjectPermissionDynamicSecretActions.ReadRootCredential,
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
);
@@ -417,7 +417,7 @@ export const dynamicSecretServiceFactory = ({
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionDynamicSecretActions.Read,
ProjectPermissionDynamicSecretActions.ReadRootCredential,
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
);
@@ -459,7 +459,7 @@ export const dynamicSecretServiceFactory = ({
// verify user has access to each env in request
environmentSlugs.forEach((environmentSlug) =>
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionDynamicSecretActions.Read,
ProjectPermissionDynamicSecretActions.ReadRootCredential,
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
)
);

View File

@@ -23,10 +23,10 @@ export enum ProjectPermissionCmekActions {
}
export enum ProjectPermissionDynamicSecretActions {
Read = "read",
Create = "create",
Edit = "edit",
Delete = "delete",
ReadRootCredential = "read-root-credential",
CreateRootCredential = "create-root-credential",
EditRootCredential = "edit-root-credential",
DeleteRootCredential = "delete-root-credential",
Lease = "lease"
}
@@ -63,8 +63,8 @@ export enum ProjectPermissionSub {
export type SecretSubjectFields = {
environment: string;
secretPath: string;
secretName: string;
secretTags: string[];
secretName?: string;
secretTags?: string[];
};
export type SecretFolderSubjectFields = {
@@ -461,10 +461,10 @@ const buildAdminPermissionRules = () => {
can(
[
ProjectPermissionDynamicSecretActions.Read,
ProjectPermissionDynamicSecretActions.Edit,
ProjectPermissionDynamicSecretActions.Create,
ProjectPermissionDynamicSecretActions.Delete,
ProjectPermissionDynamicSecretActions.ReadRootCredential,
ProjectPermissionDynamicSecretActions.EditRootCredential,
ProjectPermissionDynamicSecretActions.CreateRootCredential,
ProjectPermissionDynamicSecretActions.DeleteRootCredential,
ProjectPermissionDynamicSecretActions.Lease
],
ProjectPermissionSub.DynamicSecrets
@@ -512,10 +512,10 @@ const buildMemberPermissionRules = () => {
);
can(
[
ProjectPermissionDynamicSecretActions.Read,
ProjectPermissionDynamicSecretActions.Edit,
ProjectPermissionDynamicSecretActions.Create,
ProjectPermissionDynamicSecretActions.Delete,
ProjectPermissionDynamicSecretActions.ReadRootCredential,
ProjectPermissionDynamicSecretActions.EditRootCredential,
ProjectPermissionDynamicSecretActions.CreateRootCredential,
ProjectPermissionDynamicSecretActions.DeleteRootCredential,
ProjectPermissionDynamicSecretActions.Lease
],
ProjectPermissionSub.DynamicSecrets
@@ -653,7 +653,7 @@ const buildViewerPermissionRules = () => {
can(ProjectPermissionActions.Read, ProjectPermissionSub.Secrets);
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretFolders);
can(ProjectPermissionDynamicSecretActions.Read, ProjectPermissionSub.DynamicSecrets);
can(ProjectPermissionDynamicSecretActions.ReadRootCredential, ProjectPermissionSub.DynamicSecrets);
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretImports);
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval);
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
@@ -773,13 +773,30 @@ export const backfillPermissionV1SchemaToV2Schema = (data: z.infer<typeof Projec
subject: ProjectPermissionSub.SecretFolders
}));
const dynamicSecretPolicies = secretSubjects.map(({ subject, ...el }) => ({
...el,
action: el.action.includes(ProjectPermissionActions.Edit)
? [...el.action, ProjectPermissionDynamicSecretActions.Lease]
: el.action,
subject: ProjectPermissionSub.DynamicSecrets
}));
const dynamicSecretPolicies = secretSubjects.map(({ subject, ...el }) => {
const action = el.action.map((e) => {
switch (e) {
case ProjectPermissionActions.Edit:
return ProjectPermissionDynamicSecretActions.EditRootCredential;
case ProjectPermissionActions.Create:
return ProjectPermissionDynamicSecretActions.CreateRootCredential;
case ProjectPermissionActions.Delete:
return ProjectPermissionDynamicSecretActions.DeleteRootCredential;
case ProjectPermissionActions.Read:
return ProjectPermissionDynamicSecretActions.ReadRootCredential;
default:
return ProjectPermissionDynamicSecretActions.ReadRootCredential;
}
});
return {
...el,
action: el.action.includes(ProjectPermissionActions.Edit)
? [...action, ProjectPermissionDynamicSecretActions.Lease]
: action,
subject: ProjectPermissionSub.DynamicSecrets
};
});
return formattedData.concat(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment

View File

@@ -1,4 +1,4 @@
import { ForbiddenError, subject } from "@casl/ability";
import { ForbiddenError } from "@casl/ability";
import picomatch from "picomatch";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
@@ -344,17 +344,8 @@ export const secretApprovalPolicyServiceFactory = ({
environment,
secretPath
}: TGetBoardSapDTO) => {
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
projectId,
actorAuthMethod,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { secretPath, environment, secretName: "", secretTags: [] })
);
await permissionService.getProjectPermission(actor, actorId, projectId, actorAuthMethod, actorOrgId);
return getSecretApprovalPolicy(projectId, environment, secretPath);
};

View File

@@ -853,7 +853,7 @@ export const secretApprovalRequestServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath, secretName: "", secretTags: [] })
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
);
await projectDAL.checkProjectUpgradeStatus(projectId);

View File

@@ -97,7 +97,7 @@ export const secretRotationServiceFactory = ({
if (!folder) throw new NotFoundError({ message: "Secret path not found" });
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath, secretName: "", secretTags: [] })
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
);
const project = await projectDAL.findById(projectId);

View File

@@ -95,7 +95,7 @@ export const secretSnapshotServiceFactory = ({
// We need to check if the user has access to the secrets in the folder. If we don't do this, a user could theoretically access snapshot secret values even if they don't have read access to the secrets in the folder.
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path, secretName: "", secretTags: [] })
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
@@ -127,7 +127,7 @@ export const secretSnapshotServiceFactory = ({
// We need to check if the user has access to the secrets in the folder. If we don't do this, a user could theoretically access snapshot secret values even if they don't have read access to the secrets in the folder.
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path, secretName: "", secretTags: [] })
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
@@ -214,9 +214,7 @@ export const secretSnapshotServiceFactory = ({
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, {
environment: snapshotDetails.environment.slug,
secretPath: fullFolderPath,
secretName: "",
secretTags: []
secretPath: fullFolderPath
})
);

View File

@@ -91,9 +91,7 @@ export const integrationServiceFactory = ({
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, {
environment: sourceEnvironment,
secretPath,
secretName: "",
secretTags: []
secretPath
})
);
@@ -169,9 +167,7 @@ export const integrationServiceFactory = ({
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, {
environment: newEnvironment,
secretPath: newSecretPath,
secretName: "",
secretTags: []
secretPath: newSecretPath
})
);
}

View File

@@ -92,9 +92,7 @@ export const secretImportServiceFactory = ({
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, {
environment: data.environment,
secretPath: data.path,
secretName: "",
secretTags: []
secretPath: data.path
})
);
if (isReplication) {
@@ -371,9 +369,7 @@ export const secretImportServiceFactory = ({
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, {
environment: secretImportDoc.importEnv.slug,
secretPath: secretImportDoc.importPath,
secretName: "",
secretTags: []
secretPath: secretImportDoc.importPath
})
);
@@ -548,9 +544,7 @@ export const secretImportServiceFactory = ({
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, {
environment: el.importEnv.slug,
secretPath: el.importPath,
secretName: "",
secretTags: []
secretPath: el.importPath
})
)
);
@@ -620,9 +614,7 @@ export const secretImportServiceFactory = ({
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, {
environment: el.importEnv.slug,
secretPath: el.importPath,
secretName: "",
secretTags: []
secretPath: el.importPath
})
)
);

View File

@@ -185,9 +185,7 @@ export const recursivelyGetSecretPaths = ({
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, {
environment,
secretPath: folder.path,
secretName: "",
secretTags: []
secretPath: folder.path
})
) && folder.path.startsWith(currentPath === "/" ? "" : currentPath)
);

View File

@@ -187,7 +187,7 @@ export const secretServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path, secretName: "", secretTags: [] })
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
await projectDAL.checkProjectUpgradeStatus(projectId);
@@ -296,7 +296,7 @@ export const secretServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path, secretName: "", secretTags: [] })
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
await projectDAL.checkProjectUpgradeStatus(projectId);
@@ -433,7 +433,7 @@ export const secretServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path, secretName: "", secretTags: [] })
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
await projectDAL.checkProjectUpgradeStatus(projectId);
@@ -538,7 +538,7 @@ export const secretServiceFactory = ({
} else {
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path, secretName: "", secretTags: [] })
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
@@ -565,9 +565,7 @@ export const secretServiceFactory = ({
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, {
environment: importEnv.slug,
secretPath: importPath,
secretName: "",
secretTags: []
secretPath: importPath
})
)
);
@@ -621,7 +619,7 @@ export const secretServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path, secretName: "", secretTags: [] })
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
if (!folder)
@@ -673,9 +671,7 @@ export const secretServiceFactory = ({
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, {
environment: importEnv.slug,
secretPath: importPath,
secretName: "",
secretTags: []
secretPath: importPath
})
)
);
@@ -722,7 +718,7 @@ export const secretServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path, secretName: "", secretTags: [] })
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
await projectDAL.checkProjectUpgradeStatus(projectId);
@@ -807,7 +803,7 @@ export const secretServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path, secretName: "", secretTags: [] })
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
await projectDAL.checkProjectUpgradeStatus(projectId);
@@ -913,7 +909,7 @@ export const secretServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path, secretName: "", secretTags: [] })
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
await projectDAL.checkProjectUpgradeStatus(projectId);
@@ -2122,7 +2118,7 @@ export const secretServiceFactory = ({
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath, secretName: "", secretTags: [] })
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
);
await projectDAL.checkProjectUpgradeStatus(project.id);
@@ -2224,7 +2220,7 @@ export const secretServiceFactory = ({
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath, secretName: "", secretTags: [] })
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
);
await projectDAL.checkProjectUpgradeStatus(project.id);
@@ -2413,9 +2409,7 @@ export const secretServiceFactory = ({
ProjectPermissionActions.Delete,
subject(ProjectPermissionSub.Secrets, {
environment: sourceEnvironment,
secretPath: sourceSecretPath,
secretName: "",
secretTags: []
secretPath: sourceSecretPath
})
);
@@ -2423,9 +2417,7 @@ export const secretServiceFactory = ({
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, {
environment: destinationEnvironment,
secretPath: destinationSecretPath,
secretName: "",
secretTags: []
secretPath: destinationSecretPath
})
);
@@ -2433,9 +2425,7 @@ export const secretServiceFactory = ({
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, {
environment: destinationEnvironment,
secretPath: destinationSecretPath,
secretName: "",
secretTags: []
secretPath: destinationSecretPath
})
);

View File

@@ -66,7 +66,7 @@ export const serviceTokenServiceFactory = ({
scopes.forEach(({ environment, secretPath }) => {
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment, secretPath, secretName: "", secretTags: [] })
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
);
});

View File

@@ -8,10 +8,10 @@ export enum ProjectPermissionActions {
}
export enum ProjectPermissionDynamicSecretActions {
Read = "read",
Create = "create",
Edit = "edit",
Delete = "delete",
ReadRootCredential = "read-root-credential",
CreateRootCredential = "create-root-credential",
EditRootCredential = "edit-root-credential",
DeleteRootCredential = "delete-root-credential",
Lease = "lease"
}

View File

@@ -30,11 +30,11 @@ const CmekPolicyActionSchema = z.object({
});
const DynamicSecretPolicyActionSchema = z.object({
read: z.boolean().optional(),
edit: z.boolean().optional(),
delete: z.boolean().optional(),
create: z.boolean().optional(),
lease: z.boolean().optional()
[ProjectPermissionDynamicSecretActions.ReadRootCredential]: z.boolean().optional(),
[ProjectPermissionDynamicSecretActions.EditRootCredential]: z.boolean().optional(),
[ProjectPermissionDynamicSecretActions.DeleteRootCredential]: z.boolean().optional(),
[ProjectPermissionDynamicSecretActions.CreateRootCredential]: z.boolean().optional(),
[ProjectPermissionDynamicSecretActions.Lease]: z.boolean().optional()
});
const SecretRollbackPolicyActionSchema = z.object({
@@ -213,21 +213,25 @@ export const rolePermission2Form = (permissions: TProjectPermission[] = []) => {
if (!formVal[subject]) formVal[subject] = [];
if (subject === ProjectPermissionSub.DynamicSecrets) {
const canRead = action.includes(ProjectPermissionDynamicSecretActions.Read);
const canEdit = action.includes(ProjectPermissionDynamicSecretActions.Edit);
const canDelete = action.includes(ProjectPermissionDynamicSecretActions.Delete);
const canCreate = action.includes(ProjectPermissionDynamicSecretActions.Create);
const canRead = action.includes(ProjectPermissionDynamicSecretActions.ReadRootCredential);
const canEdit = action.includes(ProjectPermissionDynamicSecretActions.EditRootCredential);
const canDelete = action.includes(
ProjectPermissionDynamicSecretActions.DeleteRootCredential
);
const canCreate = action.includes(
ProjectPermissionDynamicSecretActions.CreateRootCredential
);
const canLease = action.includes(ProjectPermissionDynamicSecretActions.Lease);
// from above statement we are sure it won't be undefined
formVal[subject]!.push({
read: canRead,
create: canCreate,
edit: canEdit,
delete: canDelete,
[ProjectPermissionDynamicSecretActions.ReadRootCredential]: canRead,
[ProjectPermissionDynamicSecretActions.CreateRootCredential]: canCreate,
[ProjectPermissionDynamicSecretActions.EditRootCredential]: canEdit,
[ProjectPermissionDynamicSecretActions.EditRootCredential]: canDelete,
conditions: conditions ? convertCaslConditionToFormOperator(conditions) : [],
inverted,
lease: canLease
[ProjectPermissionDynamicSecretActions.Lease]: canLease
});
} else {
// for other subjects
@@ -387,11 +391,23 @@ export const PROJECT_PERMISSION_OBJECT: TProjectPermissionObject = {
[ProjectPermissionSub.DynamicSecrets]: {
title: "Dynamic Secrets",
actions: [
{ label: "Read", value: "read" },
{ label: "Create", value: "create" },
{ label: "Modify", value: "edit" },
{ label: "Remove", value: "delete" },
{ label: "Manage Leases", value: "lease" }
{
label: "Read root credentials",
value: ProjectPermissionDynamicSecretActions.ReadRootCredential
},
{
label: "Create root credentials",
value: ProjectPermissionDynamicSecretActions.CreateRootCredential
},
{
label: "Modify root credentials",
value: ProjectPermissionDynamicSecretActions.EditRootCredential
},
{
label: "Remove root credentials",
value: ProjectPermissionDynamicSecretActions.DeleteRootCredential
},
{ label: "Manage Leases", value: ProjectPermissionDynamicSecretActions.Lease }
]
},
[ProjectPermissionSub.Cmek]: {

View File

@@ -94,7 +94,7 @@ export const SecretMainPage = () => {
);
const canReadDynamicSecret = permission.can(
ProjectPermissionDynamicSecretActions.Read,
ProjectPermissionDynamicSecretActions.ReadRootCredential,
subject(ProjectPermissionSub.DynamicSecrets, { environment, secretPath })
);

View File

@@ -487,7 +487,7 @@ export const ActionBar = ({
)}
</ProjectPermissionCan>
<ProjectPermissionCan
I={ProjectPermissionDynamicSecretActions.Create}
I={ProjectPermissionDynamicSecretActions.CreateRootCredential}
a={subject(ProjectPermissionSub.DynamicSecrets, {
environment,
secretPath,

View File

@@ -175,7 +175,7 @@ export const DynamicSecretListView = ({
</div>
<div className="flex items-center space-x-4 border-l border-mineshaft-600 px-3 py-3">
<ProjectPermissionCan
I={ProjectPermissionDynamicSecretActions.Edit}
I={ProjectPermissionDynamicSecretActions.EditRootCredential}
a={subject(ProjectPermissionSub.DynamicSecrets, { environment, secretPath })}
renderTooltip
allowedLabel="Edit"
@@ -197,7 +197,7 @@ export const DynamicSecretListView = ({
)}
</ProjectPermissionCan>
<ProjectPermissionCan
I={ProjectPermissionDynamicSecretActions.Delete}
I={ProjectPermissionDynamicSecretActions.DeleteRootCredential}
a={subject(ProjectPermissionSub.DynamicSecrets, { environment, secretPath })}
renderTooltip
allowedLabel="Delete"