Revert "Permission phase 2"

This commit is contained in:
Maidul Islam
2024-10-17 17:37:41 -04:00
committed by GitHub
parent 3d938ea62f
commit 8b9244b079
100 changed files with 1568 additions and 3353 deletions
@@ -71,10 +71,7 @@ import { SecretType, TSecretFolder } from "@app/hooks/api/types";
import { ProjectVersion } from "@app/hooks/api/workspace/types";
import { useDynamicSecretOverview, useFolderOverview, useSecretOverview } from "@app/hooks/utils";
import { SecretOverviewDynamicSecretRow } from "@app/views/SecretOverviewPage/components/SecretOverviewDynamicSecretRow";
import {
SecretNoAccessOverviewTableRow,
SecretOverviewTableRow
} from "@app/views/SecretOverviewPage/components/SecretOverviewTableRow";
import { SecretOverviewTableRow } from "@app/views/SecretOverviewPage/components/SecretOverviewTableRow";
import { SecretTableResourceCount } from "@app/views/SecretOverviewPage/components/SecretTableResourceCount";
import { FolderForm } from "../SecretMainPage/components/ActionBar/FolderForm";
@@ -242,10 +239,7 @@ export const SecretOverviewPage = () => {
totalFolderCount,
totalSecretCount,
totalDynamicSecretCount,
totalCount = 0,
totalUniqueFoldersInPage,
totalUniqueSecretsInPage,
totalUniqueDynamicSecretsInPage
totalCount = 0
} = overview ?? {};
useEffect(() => {
@@ -309,7 +303,7 @@ export const SecretOverviewPage = () => {
if (
permission.can(
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.SecretFolders, { environment: env.slug, secretPath })
subject(ProjectPermissionSub.Secrets, { environment: env.slug, secretPath })
)
) {
const folder = getFolderByNameAndEnv(oldFolderName, env.slug);
@@ -512,13 +506,20 @@ export const SecretOverviewPage = () => {
const pathSegment = secretPath.split("/").filter(Boolean);
const parentPath = `/${pathSegment.slice(0, -1).join("/")}`;
const folderName = pathSegment.at(-1);
const canCreateFolder = permission.can(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.SecretFolders, {
environment: slug,
secretPath: parentPath
})
);
const canCreateFolder = permission.rules.some((rule) =>
(rule.subject as ProjectPermissionSub[]).includes(ProjectPermissionSub.SecretFolders)
)
? permission.can(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.SecretFolders, {
environment: slug,
secretPath: parentPath
})
)
: permission.can(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment: slug, secretPath: parentPath })
);
if (folderName && parentPath && canCreateFolder) {
await createFolder({
projectId: workspaceId,
@@ -770,7 +771,7 @@ export const SecretOverviewPage = () => {
<div className="flex flex-col space-y-1 p-1.5">
<ProjectPermissionCan
I={ProjectPermissionActions.Create}
a={ProjectPermissionSub.SecretFolders}
a={subject(ProjectPermissionSub.Secrets, { secretPath })}
>
{(isAllowed) => (
<Button
@@ -974,16 +975,6 @@ export const SecretOverviewPage = () => {
expandableColWidth={expandableTableWidth}
/>
))}
<SecretNoAccessOverviewTableRow
environments={visibleEnvs}
count={Math.max(
(page * perPage > totalCount ? totalCount % perPage : perPage) -
(totalUniqueFoldersInPage || 0) -
(totalUniqueDynamicSecretsInPage || 0) -
(totalUniqueSecretsInPage || 0),
0
)}
/>
</>
)}
</TBody>
@@ -93,14 +93,23 @@ export const CreateSecretForm = ({
const pathSegment = secretPath.split("/").filter(Boolean);
const parentPath = `/${pathSegment.slice(0, -1).join("/")}`;
const folderName = pathSegment.at(-1);
const canCreateFolder = permission.can(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.SecretFolders, {
environment: env.slug,
secretPath: parentPath
})
);
const canCreateFolder = permission.rules.some((rule) =>
(rule.subject as ProjectPermissionSub[]).includes(ProjectPermissionSub.SecretFolders)
)
? permission.can(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.SecretFolders, {
environment: env.slug,
secretPath: parentPath
})
)
: permission.can(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, {
environment: env.slug,
secretPath: parentPath
})
);
if (folderName && parentPath && canCreateFolder) {
await createFolder({
projectId: workspaceId,
@@ -241,9 +250,7 @@ export const CreateSecretForm = ({
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, {
environment: environmentSlug.slug,
secretPath,
secretName: "*",
secretTags: ["*"]
secretPath
})
)
)
@@ -1,4 +1,4 @@
import { useCallback, useState } from "react";
import { useCallback,useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { subject } from "@casl/ability";
import { faCheck, faCopy, faTrash, faXmark } from "@fortawesome/free-solid-svg-icons";
@@ -7,7 +7,7 @@ import { twMerge } from "tailwind-merge";
import { createNotification } from "@app/components/notifications";
import { ProjectPermissionCan } from "@app/components/permissions";
import { DeleteActionModal, IconButton, Tooltip } from "@app/components/v2";
import { DeleteActionModal,IconButton, Tooltip } from "@app/components/v2";
import { InfisicalSecretInput } from "@app/components/v2/InfisicalSecretInput";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
import { useToggle } from "@app/hooks";
@@ -63,8 +63,8 @@ export const SecretEditRow = ({
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const toggleModal = useCallback(() => {
setIsModalOpen((prev) => !prev);
}, []);
setIsModalOpen((prev) => !prev)
}, [])
const handleFormReset = () => {
reset();
@@ -114,6 +114,7 @@ export const SecretEditRow = ({
return (
<div className="group flex w-full cursor-text items-center space-x-2">
<DeleteActionModal
isOpen={isModalOpen}
onClose={toggleModal}
@@ -150,13 +151,8 @@ export const SecretEditRow = ({
{isDirty ? (
<>
<ProjectPermissionCan
I={isCreatable ? ProjectPermissionActions.Create : ProjectPermissionActions.Edit}
a={subject(ProjectPermissionSub.Secrets, {
environment,
secretPath,
secretName,
secretTags: ["*"]
})}
I={ProjectPermissionActions.Create}
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
>
{(isAllowed) => (
<div>
@@ -205,12 +201,7 @@ export const SecretEditRow = ({
</div>
<ProjectPermissionCan
I={ProjectPermissionActions.Delete}
a={subject(ProjectPermissionSub.Secrets, {
environment,
secretPath,
secretName,
secretTags: ["*"]
})}
a={ProjectPermissionSub.Secrets}
>
{(isAllowed) => (
<div className="opacity-0 group-hover:opacity-100">
@@ -1,51 +0,0 @@
import { faCircle } from "@fortawesome/free-regular-svg-icons";
import { faLock } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Td, Tooltip, Tr } from "@app/components/v2";
type Props = {
environments: { name: string; slug: string }[];
count: number;
};
export const SecretNoAccessOverviewTableRow = ({ environments = [], count }: Props) => {
return (
<>
{Array.from(Array(count)).map((_, j) => (
<Tr key={`no-access-secret-overview-${j + 1}`} isHoverable isSelectable className="group">
<Td className="sticky left-0 z-10 bg-mineshaft-800 bg-clip-padding py-0 px-0 group-hover:bg-mineshaft-700">
<div className="h-full w-full border-r border-mineshaft-600 py-2.5 px-5">
<Tooltip
asChild
content="You do not have permission to view this secret"
className="max-w-sm"
>
<div className="flex items-center space-x-5">
<div className="text-bunker-300">
<FontAwesomeIcon className="block" icon={faLock} />
</div>
<div className="blur-sm">NO ACCESS</div>
</div>
</Tooltip>
</div>
</Td>
{environments.map(({ slug }, i) => {
return (
<Td
key={`sec-overview-${slug}-${i + 1}-value`}
className="py-0 px-0 group-hover:bg-mineshaft-700"
>
<div className="h-full w-full border-r border-mineshaft-600 py-[0.85rem] px-5">
<div className="flex justify-center">
<FontAwesomeIcon icon={faCircle} />
</div>
</div>
</Td>
);
})}
</Tr>
))}
</>
);
};
@@ -18,7 +18,7 @@ import {
} from "@app/context";
import { useToggle } from "@app/hooks";
import { useUpdateSecretV3 } from "@app/hooks/api";
import { SecretType, SecretV3RawSanitized } from "@app/hooks/api/types";
import { SecretType,SecretV3RawSanitized } from "@app/hooks/api/types";
import { SecretActionType } from "@app/views/SecretMainPage/components/SecretListView/SecretListView.utils";
type Props = {
@@ -42,16 +42,15 @@ function SecretRenameRow({ environments, getSecretByKey, secretKey, secretPath }
const isReadOnly = environments.some((env) => {
const environment = env.slug;
const secretDetails = getSecretByKey(environment, secretKey);
const secretPermissionSubject = subject(ProjectPermissionSub.Secrets, {
environment,
secretPath,
secretName: secretKey,
secretTags: (secretDetails?.tags || []).map((i) => i.slug)
});
const isSecretInEnvReadOnly =
permission.can(ProjectPermissionActions.Read, secretPermissionSubject) &&
permission.cannot(ProjectPermissionActions.Edit, secretPermissionSubject);
permission.can(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
) &&
permission.cannot(
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
);
if (isSecretInEnvReadOnly) {
return true;
}
@@ -1,2 +1 @@
export { SecretNoAccessOverviewTableRow } from "./SecretNoAccessOverviewTableRow";
export { SecretOverviewTableRow } from "./SecretOverviewTableRow";
@@ -49,9 +49,9 @@ export const SelectionPanel = ({
"bulkDeleteEntries"
] as const);
const selectedFolderCount = Object.keys(selectedEntries.folder).length;
const selectedKeysCount = Object.keys(selectedEntries.secret).length;
const selectedCount = selectedFolderCount + selectedKeysCount;
const selectedFolderCount = Object.keys(selectedEntries.folder).length
const selectedKeysCount = Object.keys(selectedEntries.secret).length
const selectedCount = selectedFolderCount + selectedKeysCount
const { currentWorkspace } = useWorkspace();
const workspaceId = currentWorkspace?.id || "";
@@ -65,12 +65,7 @@ export const SelectionPanel = ({
const shouldShowDelete = userAvailableEnvs.some((env) =>
permission.can(
ProjectPermissionActions.Delete,
subject(ProjectPermissionSub.Secrets, {
environment: env.slug,
secretPath,
secretName: "*",
secretTags: ["*"]
})
subject(ProjectPermissionSub.Secrets, { environment: env.slug, secretPath })
)
);
@@ -82,50 +77,41 @@ export const SelectionPanel = ({
return "Do you want to delete the selected secrets across environments?";
}
return "Do you want to delete the selected folders across environments?";
};
}
const handleBulkDelete = async () => {
let processedEntries = 0;
const promises = userAvailableEnvs.map(async (env) => {
// additional check: ensure that bulk delete is only executed on envs that user has access to
if (
permission.can(
permission.cannot(
ProjectPermissionActions.Delete,
subject(ProjectPermissionSub.SecretFolders, { environment: env.slug, secretPath })
subject(ProjectPermissionSub.Secrets, { environment: env.slug, secretPath })
)
) {
await Promise.all(
Object.keys(selectedEntries.folder).map(async (folderName) => {
const folder = getFolderByNameAndEnv(folderName, env.slug);
if (folder) {
processedEntries += 1;
await deleteFolder({
folderId: folder?.id,
path: secretPath,
environment: env.slug,
projectId: workspaceId
});
}
})
);
return;
}
await Promise.all(
Object.keys(selectedEntries.folder).map(async (folderName) => {
const folder = getFolderByNameAndEnv(folderName, env.slug);
if (folder) {
processedEntries += 1;
await deleteFolder({
folderId: folder?.id,
path: secretPath,
environment: env.slug,
projectId: workspaceId
});
}
})
);
const secretsToDelete = Object.keys(selectedEntries.secret).reduce(
(accum: TDeleteSecretBatchDTO["secrets"], secretName) => {
const entry = getSecretByKey(env.slug, secretName);
const canDeleteSecret = permission.can(
ProjectPermissionActions.Delete,
subject(ProjectPermissionSub.Secrets, {
environment: env.slug,
secretPath,
secretName,
secretTags: (entry?.tags || []).map((i) => i.slug)
})
);
if (entry && canDeleteSecret) {
if (entry) {
return [
...accum,
{