feature: secret scanning pt2 and address initial feedback

This commit is contained in:
Scott Wilson
2025-05-29 20:40:48 -07:00
parent e6c97510ca
commit 4773336a04
78 changed files with 1038 additions and 346 deletions
@@ -1,7 +1,12 @@
import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next";
import { ProjectPermissionCan } from "@app/components/permissions";
import { PageHeader } from "@app/components/v2";
import {
ProjectPermissionSecretScanningDataSourceActions,
ProjectPermissionSub
} from "@app/context/ProjectPermissionContext/types";
import { SecretScanningDataSourcesSection } from "./components";
@@ -12,17 +17,23 @@ export const SecretScanningDataSourcesPage = () => {
<Helmet>
<title>{t("common.head-title", { title: "Secret Scanning" })}</title>
</Helmet>
<div className="h-full bg-bunker-800">
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
<div className="mx-auto mb-6 w-full max-w-7xl">
<PageHeader
title="Data Sources"
description="Manage your Secret Scanning data sources."
/>
<SecretScanningDataSourcesSection />
<ProjectPermissionCan
renderGuardBanner
I={ProjectPermissionSecretScanningDataSourceActions.Read}
a={ProjectPermissionSub.SecretScanningDataSources}
>
<div className="h-full bg-bunker-800">
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
<div className="mx-auto mb-6 w-full max-w-7xl">
<PageHeader
title="Data Sources"
description="Manage your Secret Scanning data sources."
/>
<SecretScanningDataSourcesSection />
</div>
</div>
</div>
</div>
</ProjectPermissionCan>
</>
);
};
@@ -7,6 +7,7 @@ import {
faEllipsisV,
faExpand,
faInfoCircle,
faPlugCircleXmark,
faSearch,
faToggleOff,
faToggleOn,
@@ -72,7 +73,8 @@ export const SecretScanningDataSourceRow = ({
unresolvedFindings,
lastScannedAt,
lastScanStatus,
lastScanStatusMessage
lastScanStatusMessage,
isDisconnected
} = dataSource;
const sourceDetails = SECRET_SCANNING_DATA_SOURCE_MAP[type];
@@ -199,7 +201,7 @@ export const SecretScanningDataSourceRow = ({
) : (
<span className="text-mineshaft-400">No scans</span>
)}
{!isAutoScanEnabled && (
{!isAutoScanEnabled && !isDisconnected && (
<Tooltip
className="text-xs"
content={`Auto-Scan is disabled. Scans will not be automatically triggered when a ${autoScanDescription.verb} occurs to ${autoScanDescription.pluralNoun} associated with this data source`}
@@ -212,6 +214,22 @@ export const SecretScanningDataSourceRow = ({
</div>
</Tooltip>
)}
{isDisconnected && (
<Tooltip
className="text-xs"
content="The external data source has been removed and can no longer be scanned. Delete this data source and re-initialize the connection."
>
<div className="ml-auto">
<Badge
variant="danger"
className="flex h-5 w-min items-center gap-1.5 whitespace-nowrap"
>
<FontAwesomeIcon icon={faPlugCircleXmark} />
<span>Disconnected</span>
</Badge>
</div>
</Tooltip>
)}
</div>
</Td>
<Td>
@@ -1,10 +1,11 @@
import { faArrowUpRightFromSquare, faBookOpen, faPlus } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
import { ProjectPermissionCan } from "@app/components/permissions";
import { CreateSecretScanningDataSourceModal } from "@app/components/secret-scanning";
import { Button, Spinner } from "@app/components/v2";
import { ProjectPermissionSub, useWorkspace } from "@app/context";
import { ProjectPermissionSub, useSubscription, useWorkspace } from "@app/context";
import { ProjectPermissionSecretScanningDataSourceActions } from "@app/context/ProjectPermissionContext/types";
import { usePopUp } from "@app/hooks";
import { useListSecretScanningDataSources } from "@app/hooks/api/secretScanningV2";
@@ -12,7 +13,12 @@ import { useListSecretScanningDataSources } from "@app/hooks/api/secretScanningV
import { SecretScanningDataSourcesTable } from "./SecretScanningDataSourcesTable";
export const SecretScanningDataSourcesSection = () => {
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["addDataSource"] as const);
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp([
"addDataSource",
"upgradePlan"
] as const);
const { subscription } = useSubscription();
const { currentWorkspace } = useWorkspace();
@@ -63,7 +69,14 @@ export const SecretScanningDataSourcesSection = () => {
colorSchema="secondary"
type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => handlePopUpOpen("addDataSource")}
onClick={() => {
if (!subscription.secretScanning) {
handlePopUpOpen("upgradePlan");
return;
}
handlePopUpOpen("addDataSource");
}}
isDisabled={!isAllowed}
>
Add Data Source
@@ -77,6 +90,11 @@ export const SecretScanningDataSourcesSection = () => {
isOpen={popUp.addDataSource.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("addDataSource", isOpen)}
/>
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can create Data Sources by upgrading to Infisical's Enterprise plan."
/>
</>
);
};
@@ -3,9 +3,9 @@ import {
faArrowDown,
faArrowUp,
faCheckCircle,
faCubesStacked,
faFilter,
faMagnifyingGlass,
faPuzzlePiece,
faSearch
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
@@ -368,7 +368,7 @@ export const SecretScanningDataSourcesTable = ({ dataSources }: Props) => {
? "No data sources match search..."
: "This project has no data sources configured"
}
icon={dataSources.length ? faSearch : faPuzzlePiece}
icon={dataSources.length ? faSearch : faCubesStacked}
/>
)}
</TableContainer>