diff --git a/backend/src/ee/services/secret-scanning/secret-scanning-service.ts b/backend/src/ee/services/secret-scanning/secret-scanning-service.ts index 9b78da3af..ef511deb8 100644 --- a/backend/src/ee/services/secret-scanning/secret-scanning-service.ts +++ b/backend/src/ee/services/secret-scanning/secret-scanning-service.ts @@ -90,15 +90,17 @@ export const secretScanningServiceFactory = ({ const { data: { repositories } } = await octokit.apps.listReposAccessibleToInstallation(); - await Promise.all( - repositories.map(({ id, full_name }) => - secretScanningQueue.startFullRepoScan({ - organizationId: session.orgId, - installationId, - repository: { id, fullName: full_name } - }) - ) - ); + if (!appCfg.DISABLE_SECRET_SCANNING) { + await Promise.all( + repositories.map(({ id, full_name }) => + secretScanningQueue.startFullRepoScan({ + organizationId: session.orgId, + installationId, + repository: { id, fullName: full_name } + }) + ) + ); + } return { installatedApp }; }; @@ -151,6 +153,7 @@ export const secretScanningServiceFactory = ({ }; const handleRepoPushEvent = async (payload: WebhookEventMap["push"]) => { + const appCfg = getConfig(); const { commits, repository, installation, pusher } = payload; if (!commits || !repository || !installation || !pusher) { return; @@ -161,13 +164,15 @@ export const secretScanningServiceFactory = ({ }); if (!installationLink) return; - await secretScanningQueue.startPushEventScan({ - commits, - pusher: { name: pusher.name, email: pusher.email }, - repository: { fullName: repository.full_name, id: repository.id }, - organizationId: installationLink.orgId, - installationId: String(installation?.id) - }); + if (!appCfg.DISABLE_SECRET_SCANNING) { + await secretScanningQueue.startPushEventScan({ + commits, + pusher: { name: pusher.name, email: pusher.email }, + repository: { fullName: repository.full_name, id: repository.id }, + organizationId: installationLink.orgId, + installationId: String(installation?.id) + }); + } }; const handleRepoDeleteEvent = async (installationId: string, repositoryIds: string[]) => { diff --git a/backend/src/lib/config/env.ts b/backend/src/lib/config/env.ts index f9bbb1b46..6ae8bf02d 100644 --- a/backend/src/lib/config/env.ts +++ b/backend/src/lib/config/env.ts @@ -13,6 +13,10 @@ const zodStrBool = z const envSchema = z .object({ PORT: z.coerce.number().default(4000), + DISABLE_SECRET_SCANNING: z + .enum(["true", "false"]) + .default("false") + .transform((el) => el === "true"), REDIS_URL: zpStr(z.string()), HOST: zpStr(z.string().default("localhost")), DB_CONNECTION_URI: zpStr(z.string().describe("Postgres database connection string")).default( diff --git a/backend/src/server/routes/v1/admin-router.ts b/backend/src/server/routes/v1/admin-router.ts index 4882411d8..572409d9b 100644 --- a/backend/src/server/routes/v1/admin-router.ts +++ b/backend/src/server/routes/v1/admin-router.ts @@ -20,16 +20,23 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => { schema: { response: { 200: z.object({ - config: SuperAdminSchema.omit({ createdAt: true, updatedAt: true }).merge( - z.object({ isMigrationModeOn: z.boolean() }) - ) + config: SuperAdminSchema.omit({ createdAt: true, updatedAt: true }).extend({ + isMigrationModeOn: z.boolean(), + isSecretScanningDisabled: z.boolean() + }) }) } }, handler: async () => { const config = await getServerCfg(); const serverEnvs = getConfig(); - return { config: { ...config, isMigrationModeOn: serverEnvs.MAINTENANCE_MODE } }; + return { + config: { + ...config, + isMigrationModeOn: serverEnvs.MAINTENANCE_MODE, + isSecretScanningDisabled: serverEnvs.DISABLE_SECRET_SCANNING + } + }; } }); diff --git a/frontend/src/components/v2/NoticeBanner/NoticeBanner.tsx b/frontend/src/components/v2/NoticeBanner/NoticeBanner.tsx new file mode 100644 index 000000000..cf32427a3 --- /dev/null +++ b/frontend/src/components/v2/NoticeBanner/NoticeBanner.tsx @@ -0,0 +1,26 @@ +import { ReactNode } from "react"; +import { faWarning, IconDefinition } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { twMerge } from "tailwind-merge"; + +type Props = { + icon?: IconDefinition; + title: string; + children: ReactNode; + className?: string; +}; + +export const NoticeBanner = ({ icon = faWarning, title, children, className }: Props) => ( +
+ +
+
{title}
+
{children}
+
+
+); diff --git a/frontend/src/components/v2/NoticeBanner/index.tsx b/frontend/src/components/v2/NoticeBanner/index.tsx new file mode 100644 index 000000000..0006c75a5 --- /dev/null +++ b/frontend/src/components/v2/NoticeBanner/index.tsx @@ -0,0 +1 @@ +export { NoticeBanner } from "./NoticeBanner"; diff --git a/frontend/src/components/v2/index.tsx b/frontend/src/components/v2/index.tsx index 526580b6c..3a5cef86b 100644 --- a/frontend/src/components/v2/index.tsx +++ b/frontend/src/components/v2/index.tsx @@ -17,6 +17,7 @@ export * from "./IconButton"; export * from "./Input"; export * from "./Menu"; export * from "./Modal"; +export * from "./NoticeBanner"; export * from "./Pagination"; export * from "./Popoverv2"; export * from "./SecretInput"; diff --git a/frontend/src/hooks/api/admin/types.ts b/frontend/src/hooks/api/admin/types.ts index f5aaabc83..6a42e6ed0 100644 --- a/frontend/src/hooks/api/admin/types.ts +++ b/frontend/src/hooks/api/admin/types.ts @@ -5,6 +5,7 @@ export type TServerConfig = { isMigrationModeOn?: boolean; trustSamlEmails: boolean; trustLdapEmails: boolean; + isSecretScanningDisabled: boolean; }; export type TCreateAdminUserDTO = { diff --git a/frontend/src/pages/org/[id]/secret-scanning/index.tsx b/frontend/src/pages/org/[id]/secret-scanning/index.tsx index 97a715e37..fd44f6961 100644 --- a/frontend/src/pages/org/[id]/secret-scanning/index.tsx +++ b/frontend/src/pages/org/[id]/secret-scanning/index.tsx @@ -3,8 +3,8 @@ import Head from "next/head"; import { useRouter } from "next/router"; import { OrgPermissionCan } from "@app/components/permissions"; -import { Button } from "@app/components/v2"; -import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context"; +import { Button, NoticeBanner } from "@app/components/v2"; +import { OrgPermissionActions, OrgPermissionSubjects, useServerConfig } from "@app/context"; import { withPermission } from "@app/hoc"; import { SecretScanningLogsTable } from "@app/views/SecretScanning/components"; @@ -17,6 +17,7 @@ const SecretScanning = withPermission( const router = useRouter(); const queryParams = router.query; const [integrationEnabled, setIntegrationStatus] = useState(false); + const { config } = useServerConfig(); useEffect(() => { const linkInstallation = async () => { @@ -69,6 +70,11 @@ const SecretScanning = withPermission(
Automatically monitor your GitHub activity and prevent secret leaks
+ {config.isSecretScanningDisabled && ( + + We are working on improving the performance of secret scanning due to increased usage. + + )}
@@ -110,7 +116,7 @@ const SecretScanning = withPermission( colorSchema="primary" onClick={generateNewIntegrationSession} className="h-min py-2" - isDisabled={!isAllowed} + isDisabled={!isAllowed || config.isSecretScanningDisabled} > Integrate with GitHub