feat(secrets-ui): add direct reference warning on secrets updates

This commit is contained in:
carlosmonastyrski
2025-04-25 17:38:43 -03:00
parent d5065af7e9
commit 4160009913
14 changed files with 254 additions and 100 deletions
@@ -118,7 +118,7 @@ type Props = {
environment: { name: string; slug: string };
folders: {
name: string;
secrets?: { secretId: string; referencedSecretKey: string }[];
secrets?: { secretId: string; referencedSecretKey: string; referencedSecretId: string }[];
isImported: boolean;
}[];
}[];
@@ -26,7 +26,7 @@ interface CollapsibleSecretImportsProps {
environment: { name: string; slug: string };
folders: {
name: string;
secrets?: { secretId: string; referencedSecretKey: string }[];
secrets?: { secretId: string; referencedSecretKey: string; referencedSecretId: string }[];
isImported: boolean;
}[];
}[];
@@ -38,12 +38,14 @@ interface CollapsibleSecretImportsProps {
}[]
| null;
secretsToDelete: string[];
onlyReferences?: boolean;
}
export const CollapsibleSecretImports: React.FC<CollapsibleSecretImportsProps> = ({
importedBy = [],
usedBySecretSyncs = [],
secretsToDelete
secretsToDelete,
onlyReferences
}) => {
const { currentWorkspace } = useWorkspace();
@@ -88,7 +90,7 @@ export const CollapsibleSecretImports: React.FC<CollapsibleSecretImportsProps> =
importedBy.forEach((env) => {
env.folders.forEach((folder) => {
if (folder.isImported) {
if (folder.isImported && !onlyReferences) {
items.push({
type: ItemType.Folder,
path: folder.name,
@@ -4,6 +4,7 @@ import { ProjectPermissionCan } from "@app/components/permissions";
import {
Button,
Checkbox,
DeleteActionModal,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
@@ -31,7 +32,7 @@ import {
useProjectPermission,
useWorkspace
} from "@app/context";
import { useToggle } from "@app/hooks";
import { usePopUp, useToggle } from "@app/hooks";
import { SecretV3RawSanitized } from "@app/hooks/api/secrets/types";
import { WsTag } from "@app/hooks/api/types";
import { subject } from "@casl/ability";
@@ -56,6 +57,7 @@ import {
SecretActionType,
TFormSchema
} from "./SecretListView.utils";
import { CollapsibleSecretImports } from "./CollapsibleSecretImports";
type Props = {
secret: SecretV3RawSanitized;
@@ -74,6 +76,14 @@ type Props = {
environment: string;
secretPath: string;
handleSecretShare: () => void;
importedBy?: {
environment: { name: string; slug: string };
folders: {
name: string;
secrets?: { secretId: string; referencedSecretKey: string; referencedSecretId: string }[];
isImported: boolean;
}[];
}[];
};
export const SecretItem = memo(
@@ -89,8 +99,12 @@ export const SecretItem = memo(
onToggleSecretSelect,
environment,
secretPath,
handleSecretShare
handleSecretShare,
importedBy
}: Props) => {
const { handlePopUpOpen, handlePopUpToggle, handlePopUpClose, popUp } = usePopUp([
"editSecret"
] as const);
const { currentWorkspace } = useWorkspace();
const { permission } = useProjectPermission();
const { isRotatedSecret } = secret;
@@ -194,9 +208,25 @@ export const SecretItem = memo(
};
const handleFormSubmit = async (data: TFormSchema) => {
if (
importedBy &&
importedBy.some(({ folders }) =>
folders?.some(({ secrets }) =>
secrets?.some(({ referencedSecretId }) => referencedSecretId === secret.id)
)
)
) {
handlePopUpOpen("editSecret", data);
return;
}
await onSaveSecret(secret, { ...secret, ...data }, () => reset());
};
const handleEditSecret = async (data: TFormSchema) => {
await onSaveSecret(secret, { ...secret, ...data }, () => reset());
handlePopUpClose("editSecret");
};
const handleTagSelect = (tag: WsTag) => {
if (selectedTagsGroupById?.[tag.id]) {
const tagPos = selectedTags.findIndex(({ id }) => id === tag.id);
@@ -682,6 +712,26 @@ export const SecretItem = memo(
</AnimatePresence>
</div>
</div>
<DeleteActionModal
isOpen={popUp.editSecret.isOpen}
deleteKey="confirm"
buttonColorSchema="secondary"
buttonText="Save"
subTitle=""
title="Do you want to edit this secret?"
onChange={(isOpen) => handlePopUpToggle("editSecret", isOpen)}
onDeleteApproved={() => handleEditSecret(popUp?.editSecret?.data)}
formContent={
importedBy &&
importedBy.length > 0 && (
<CollapsibleSecretImports
importedBy={importedBy}
secretsToDelete={[secret.key]}
onlyReferences
/>
)
}
/>
</form>
);
}
@@ -34,7 +34,7 @@ type Props = {
environment: { name: string; slug: string };
folders: {
name: string;
secrets?: { secretId: string; referencedSecretKey: string }[];
secrets?: { secretId: string; referencedSecretKey: string; referencedSecretId: string }[];
isImported: boolean;
}[];
}[];
@@ -354,6 +354,7 @@ export const SecretListView = ({
onSaveSecret={handleSaveSecret}
onDeleteSecret={onDeleteSecret}
onDetailViewSecret={onDetailViewSecret}
importedBy={importedBy}
onCreateTag={onCreateTag}
handleSecretShare={() =>
handlePopUpOpen("createSharedSecret", {