mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-16 05:13:43 +00:00
Revert "Permission phase 2"
This commit is contained in:
@@ -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>
|
||||
|
||||
+18
-11
@@ -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
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
+8
-17
@@ -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">
|
||||
|
||||
-51
@@ -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>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
+9
-10
@@ -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";
|
||||
|
||||
+24
-38
@@ -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,
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user