mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 04:14:38 +00:00
Merge pull request #3677 from Infisical/secret-scanning-v2-pt-1
feature(secret-scanning-v2): secret scanning architecture and github data source
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
export enum AppConnection {
|
||||
AWS = "aws",
|
||||
GitHub = "github",
|
||||
GitHubRadar = "github-radar",
|
||||
GCP = "gcp",
|
||||
AzureKeyVault = "azure-key-vault",
|
||||
AzureAppConfiguration = "azure-app-configuration",
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./queries";
|
||||
export * from "./types";
|
||||
@@ -0,0 +1,40 @@
|
||||
import { useQuery, UseQueryOptions } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { appConnectionKeys } from "@app/hooks/api/appConnections";
|
||||
|
||||
import {
|
||||
TGitHubRadarConnectionListRepositoriesResponse,
|
||||
TGitHubRadarConnectionRepository
|
||||
} from "./types";
|
||||
|
||||
const githubRadarConnectionKeys = {
|
||||
all: [...appConnectionKeys.all, "github-radar"] as const,
|
||||
listRepositories: (connectionId: string) =>
|
||||
[...githubRadarConnectionKeys.all, "repositories", connectionId] as const
|
||||
};
|
||||
|
||||
export const useGitHubRadarConnectionListRepositories = (
|
||||
connectionId: string,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TGitHubRadarConnectionRepository[],
|
||||
unknown,
|
||||
TGitHubRadarConnectionRepository[],
|
||||
ReturnType<typeof githubRadarConnectionKeys.listRepositories>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: githubRadarConnectionKeys.listRepositories(connectionId),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TGitHubRadarConnectionListRepositoriesResponse>(
|
||||
`/api/v1/app-connections/github-radar/${connectionId}/repositories`
|
||||
);
|
||||
|
||||
return data.repositories;
|
||||
},
|
||||
...options
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
export type TGitHubRadarConnectionOrganization = {
|
||||
login: string;
|
||||
id: number;
|
||||
};
|
||||
|
||||
export type TGitHubRadarConnectionRepository = {
|
||||
id: number;
|
||||
name: string;
|
||||
owner: TGitHubRadarConnectionOrganization;
|
||||
};
|
||||
|
||||
export type TGitHubRadarConnectionListRepositoriesResponse = {
|
||||
repositories: TGitHubRadarConnectionRepository[];
|
||||
};
|
||||
@@ -17,6 +17,11 @@ export type TGitHubConnectionOption = TAppConnectionOptionBase & {
|
||||
appClientSlug?: string;
|
||||
};
|
||||
|
||||
export type TGitHubRadarConnectionOption = TAppConnectionOptionBase & {
|
||||
app: AppConnection.GitHubRadar;
|
||||
appClientSlug?: string;
|
||||
};
|
||||
|
||||
export type TGcpConnectionOption = TAppConnectionOptionBase & {
|
||||
app: AppConnection.GCP;
|
||||
};
|
||||
@@ -121,6 +126,7 @@ export type TAppConnectionOption =
|
||||
export type TAppConnectionOptionMap = {
|
||||
[AppConnection.AWS]: TAwsConnectionOption;
|
||||
[AppConnection.GitHub]: TGitHubConnectionOption;
|
||||
[AppConnection.GitHubRadar]: TGitHubRadarConnectionOption;
|
||||
[AppConnection.GCP]: TGcpConnectionOption;
|
||||
[AppConnection.AzureKeyVault]: TAzureKeyVaultConnectionOption;
|
||||
[AppConnection.AzureAppConfiguration]: TAzureAppConfigurationConnectionOption;
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
import { TRootAppConnection } from "@app/hooks/api/appConnections/types/root-connection";
|
||||
|
||||
export enum GitHubRadarConnectionMethod {
|
||||
App = "github-app"
|
||||
}
|
||||
|
||||
export type TGitHubRadarConnection = TRootAppConnection & { app: AppConnection.GitHubRadar } & {
|
||||
method: GitHubRadarConnectionMethod.App;
|
||||
credentials: {
|
||||
code: string;
|
||||
installationId: string;
|
||||
};
|
||||
};
|
||||
@@ -10,6 +10,7 @@ import { TCamundaConnection } from "./camunda-connection";
|
||||
import { TDatabricksConnection } from "./databricks-connection";
|
||||
import { TGcpConnection } from "./gcp-connection";
|
||||
import { TGitHubConnection } from "./github-connection";
|
||||
import { TGitHubRadarConnection } from "./github-radar-connection";
|
||||
import { THCVaultConnection } from "./hc-vault-connection";
|
||||
import { THumanitecConnection } from "./humanitec-connection";
|
||||
import { TLdapConnection } from "./ldap-connection";
|
||||
@@ -32,6 +33,7 @@ export * from "./camunda-connection";
|
||||
export * from "./databricks-connection";
|
||||
export * from "./gcp-connection";
|
||||
export * from "./github-connection";
|
||||
export * from "./github-radar-connection";
|
||||
export * from "./hc-vault-connection";
|
||||
export * from "./humanitec-connection";
|
||||
export * from "./ldap-connection";
|
||||
@@ -47,6 +49,7 @@ export * from "./windmill-connection";
|
||||
export type TAppConnection =
|
||||
| TAwsConnection
|
||||
| TGitHubConnection
|
||||
| TGitHubRadarConnection
|
||||
| TGcpConnection
|
||||
| TAzureKeyVaultConnection
|
||||
| TAzureAppConfigurationConnection
|
||||
@@ -95,6 +98,7 @@ export type TDeleteAppConnectionDTO = {
|
||||
export type TAppConnectionMap = {
|
||||
[AppConnection.AWS]: TAwsConnection;
|
||||
[AppConnection.GitHub]: TGitHubConnection;
|
||||
[AppConnection.GitHubRadar]: TGitHubRadarConnection;
|
||||
[AppConnection.GCP]: TGcpConnection;
|
||||
[AppConnection.AzureKeyVault]: TAzureKeyVaultConnection;
|
||||
[AppConnection.AzureAppConfiguration]: TAzureAppConfigurationConnection;
|
||||
|
||||
@@ -191,6 +191,20 @@ export const eventToNameMap: { [K in EventType]: string } = {
|
||||
[EventType.GET_IDENTITY_LDAP_AUTH]: "Retrieved LDAP Auth for identity",
|
||||
[EventType.REVOKE_IDENTITY_LDAP_AUTH]: "Revoked LDAP Auth for identity",
|
||||
|
||||
[EventType.SECRET_SCANNING_DATA_SOURCE_LIST]: "List Secret Scanning Data Sources",
|
||||
[EventType.SECRET_SCANNING_DATA_SOURCE_CREATE]: "Create Secret Scanning Data Source",
|
||||
[EventType.SECRET_SCANNING_DATA_SOURCE_UPDATE]: "Update Secret Scanning Data Source",
|
||||
[EventType.SECRET_SCANNING_DATA_SOURCE_DELETE]: "Delete Secret Scanning Data Source",
|
||||
[EventType.SECRET_SCANNING_DATA_SOURCE_GET]: "Get Secret Scanning Data Source",
|
||||
[EventType.SECRET_SCANNING_DATA_SOURCE_TRIGGER_SCAN]: "Trigger Secret Scanning Data Source Scan",
|
||||
[EventType.SECRET_SCANNING_DATA_SOURCE_SCAN]: "Secret Scanning Data Source Scan",
|
||||
[EventType.SECRET_SCANNING_RESOURCE_LIST]: "List Secret Scanning Resources",
|
||||
[EventType.SECRET_SCANNING_SCAN_LIST]: "List Secret Scanning Scans",
|
||||
[EventType.SECRET_SCANNING_FINDING_LIST]: "List Secret Scanning Findings",
|
||||
[EventType.SECRET_SCANNING_FINDING_UPDATE]: "Update Secret Scanning Finding Status",
|
||||
[EventType.SECRET_SCANNING_CONFIG_GET]: "Get Secret Scanning Configuration",
|
||||
[EventType.SECRET_SCANNING_CONFIG_UPDATE]: "Update Secret Scanning Configuration",
|
||||
|
||||
[EventType.CREATE_PKI_SUBSCRIBER]: "Create PKI subscriber",
|
||||
[EventType.UPDATE_PKI_SUBSCRIBER]: "Update PKI subscriber",
|
||||
[EventType.DELETE_PKI_SUBSCRIBER]: "Delete PKI subscriber",
|
||||
|
||||
@@ -185,6 +185,20 @@ export enum EventType {
|
||||
MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_GET = "microsoft-teams-workflow-integration-get",
|
||||
MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_LIST = "microsoft-teams-workflow-integration-list",
|
||||
|
||||
SECRET_SCANNING_DATA_SOURCE_LIST = "secret-scanning-data-source-list",
|
||||
SECRET_SCANNING_DATA_SOURCE_CREATE = "secret-scanning-data-source-create",
|
||||
SECRET_SCANNING_DATA_SOURCE_UPDATE = "secret-scanning-data-source-update",
|
||||
SECRET_SCANNING_DATA_SOURCE_DELETE = "secret-scanning-data-source-delete",
|
||||
SECRET_SCANNING_DATA_SOURCE_GET = "secret-scanning-data-source-get",
|
||||
SECRET_SCANNING_DATA_SOURCE_TRIGGER_SCAN = "secret-scanning-data-source-trigger-scan",
|
||||
SECRET_SCANNING_DATA_SOURCE_SCAN = "secret-scanning-data-source-scan",
|
||||
SECRET_SCANNING_RESOURCE_LIST = "secret-scanning-resource-list",
|
||||
SECRET_SCANNING_SCAN_LIST = "secret-scanning-scan-list",
|
||||
SECRET_SCANNING_FINDING_LIST = "secret-scanning-finding-list",
|
||||
SECRET_SCANNING_FINDING_UPDATE = "secret-scanning-finding-update",
|
||||
SECRET_SCANNING_CONFIG_GET = "secret-scanning-config-get",
|
||||
SECRET_SCANNING_CONFIG_UPDATE = "secret-scanning-config-update",
|
||||
|
||||
CREATE_PKI_SUBSCRIBER = "create-pki-subscriber",
|
||||
UPDATE_PKI_SUBSCRIBER = "update-pki-subscriber",
|
||||
DELETE_PKI_SUBSCRIBER = "delete-pki-subscriber",
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
export enum SecretScanningDataSource {
|
||||
GitHub = "github"
|
||||
}
|
||||
|
||||
export enum SecretScanningScanStatus {
|
||||
Completed = "completed",
|
||||
Failed = "failed",
|
||||
Queued = "queued",
|
||||
Scanning = "scanning"
|
||||
}
|
||||
|
||||
export enum SecretScanningScanType {
|
||||
FullScan = "full-scan",
|
||||
DiffScan = "diff-scan"
|
||||
}
|
||||
|
||||
export enum SecretScanningFindingStatus {
|
||||
Resolved = "resolved",
|
||||
Unresolved = "unresolved",
|
||||
FalsePositive = "false-positive",
|
||||
Ignore = "ignore"
|
||||
}
|
||||
|
||||
export enum SecretScanningResource {
|
||||
Repository = "repository",
|
||||
Project = "project"
|
||||
}
|
||||
|
||||
export enum SecretScanningFindingSeverity {
|
||||
High = "high",
|
||||
Medium = "medium",
|
||||
Low = "low"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./enums";
|
||||
export * from "./mutations";
|
||||
export * from "./queries";
|
||||
export * from "./types";
|
||||
@@ -0,0 +1,160 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { secretScanningV2Keys } from "./queries";
|
||||
import {
|
||||
TCreateSecretScanningDataSourceDTO,
|
||||
TDeleteSecretScanningDataSourceDTO,
|
||||
TGetSecretScanningConfigResponse,
|
||||
TSecretScanningConfig,
|
||||
TSecretScanningDataSourceResponse,
|
||||
TSecretScanningFindingResponse,
|
||||
TTriggerSecretScanningDataSourceDTO,
|
||||
TUpdateSecretScanningDataSourceDTO,
|
||||
TUpdateSecretScanningFinding
|
||||
} from "./types";
|
||||
|
||||
export const useCreateSecretScanningDataSource = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ type, ...params }: TCreateSecretScanningDataSourceDTO) => {
|
||||
const { data } = await apiRequest.post<TSecretScanningDataSourceResponse>(
|
||||
`/api/v2/secret-scanning/data-sources/${type}`,
|
||||
params
|
||||
);
|
||||
|
||||
return data.dataSource;
|
||||
},
|
||||
onSuccess: (_, { projectId }) =>
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.listDataSources(projectId)
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateSecretScanningDataSource = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ type, dataSourceId, ...params }: TUpdateSecretScanningDataSourceDTO) => {
|
||||
const { data } = await apiRequest.patch<TSecretScanningDataSourceResponse>(
|
||||
`/api/v2/secret-scanning/data-sources/${type}/${dataSourceId}`,
|
||||
params
|
||||
);
|
||||
|
||||
return data.dataSource;
|
||||
},
|
||||
onSuccess: (_, { projectId, dataSourceId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.listDataSources(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.dataSourceById(dataSourceId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.listResources(dataSourceId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.listScans(dataSourceId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteSecretScanningDataSource = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ type, dataSourceId }: TDeleteSecretScanningDataSourceDTO) => {
|
||||
const { data } = await apiRequest.delete<TSecretScanningDataSourceResponse>(
|
||||
`/api/v2/secret-scanning/data-sources/${type}/${dataSourceId}`
|
||||
);
|
||||
|
||||
return data.dataSource;
|
||||
},
|
||||
onSuccess: (_, { projectId, dataSourceId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.listDataSources(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.dataSourceById(dataSourceId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.listResources(dataSourceId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.listScans(dataSourceId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useTriggerSecretScanningDataSource = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ type, dataSourceId, resourceId }: TTriggerSecretScanningDataSourceDTO) => {
|
||||
const { data } = await apiRequest.post<TSecretScanningDataSourceResponse>(
|
||||
`/api/v2/secret-scanning/data-sources/${type}/${dataSourceId}${resourceId ? `/resources/${resourceId}` : ""}/scan`
|
||||
);
|
||||
|
||||
return data.dataSource;
|
||||
},
|
||||
onSuccess: (_, { projectId, dataSourceId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.listDataSources(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.dataSourceById(dataSourceId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.listResources(dataSourceId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.listScans(dataSourceId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateSecretScanningFinding = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ findingId, ...params }: TUpdateSecretScanningFinding) => {
|
||||
const { data } = await apiRequest.patch<TSecretScanningFindingResponse>(
|
||||
`/api/v2/secret-scanning/findings/${findingId}`,
|
||||
params
|
||||
);
|
||||
|
||||
return data.finding;
|
||||
},
|
||||
onSuccess: (_, { projectId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.listFindings(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.findingCount(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.dataSource()
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateSecretScanningConfig = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ projectId, ...params }: TSecretScanningConfig) => {
|
||||
const { data } = await apiRequest.patch<TGetSecretScanningConfigResponse>(
|
||||
`/api/v2/secret-scanning/configs?projectId=${projectId}`,
|
||||
params
|
||||
);
|
||||
|
||||
return data.config;
|
||||
},
|
||||
onSuccess: (_, { projectId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: secretScanningV2Keys.configByProjectId(projectId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,248 @@
|
||||
import { useQuery, UseQueryOptions } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import {
|
||||
TGetSecretScanningConfigResponse,
|
||||
TGetSecretScanningDataSource,
|
||||
TGetSecretScanningUnresolvedFindingsResponse,
|
||||
TListSecretScanningDataSourceOptions,
|
||||
TListSecretScanningDataSources,
|
||||
TListSecretScanningFindingsResponse,
|
||||
TListSecretScanningResourcesResponse,
|
||||
TListSecretScanningScansResponse,
|
||||
TSecretScanningConfig,
|
||||
TSecretScanningDataSource,
|
||||
TSecretScanningDataSourceOption,
|
||||
TSecretScanningDataSourceResponse,
|
||||
TSecretScanningDataSourceWithDetails,
|
||||
TSecretScanningFinding,
|
||||
TSecretScanningResourceWithDetails,
|
||||
TSecretScanningScanWithDetails
|
||||
} from "./types";
|
||||
|
||||
export const secretScanningV2Keys = {
|
||||
all: ["secret-scanning-v2"] as const,
|
||||
dataSource: () => [...secretScanningV2Keys.all, "data-source"] as const,
|
||||
dataSourceOptions: () => [...secretScanningV2Keys.dataSource(), "options"] as const,
|
||||
dataSourceById: (dataSourceId: string) => [
|
||||
...secretScanningV2Keys.dataSource(),
|
||||
"byId",
|
||||
dataSourceId
|
||||
],
|
||||
listDataSources: (projectId: string) => [...secretScanningV2Keys.dataSource(), "list", projectId],
|
||||
listResources: (dataSourceId: string) => [
|
||||
...secretScanningV2Keys.dataSource(),
|
||||
"resources",
|
||||
dataSourceId
|
||||
],
|
||||
listScans: (dataSourceId: string) => [
|
||||
...secretScanningV2Keys.dataSource(),
|
||||
"scans",
|
||||
dataSourceId
|
||||
],
|
||||
finding: () => [...secretScanningV2Keys.all, "finding"] as const,
|
||||
findingCount: (projectId: string) =>
|
||||
[...secretScanningV2Keys.finding(), "count", projectId] as const,
|
||||
listFindings: (projectId: string) => [...secretScanningV2Keys.finding(), "list", projectId],
|
||||
configByProjectId: (projectId: string) =>
|
||||
[...secretScanningV2Keys.all, "config", projectId] as const
|
||||
};
|
||||
|
||||
export const useSecretScanningDataSourceOptions = (
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TSecretScanningDataSourceOption[],
|
||||
unknown,
|
||||
TSecretScanningDataSourceOption[],
|
||||
ReturnType<typeof secretScanningV2Keys.dataSourceOptions>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: secretScanningV2Keys.dataSourceOptions(),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TListSecretScanningDataSourceOptions>(
|
||||
"/api/v2/secret-scanning/data-sources/options"
|
||||
);
|
||||
|
||||
return data.dataSourceOptions;
|
||||
},
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
export const useListSecretScanningDataSources = (
|
||||
projectId: string,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TSecretScanningDataSourceWithDetails[],
|
||||
unknown,
|
||||
TSecretScanningDataSourceWithDetails[],
|
||||
ReturnType<typeof secretScanningV2Keys.listDataSources>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: secretScanningV2Keys.listDataSources(projectId),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TListSecretScanningDataSources>(
|
||||
"/api/v2/secret-scanning/data-sources-dashboard",
|
||||
{ params: { projectId } }
|
||||
);
|
||||
|
||||
return data.dataSources;
|
||||
},
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetSecretScanningDataSource = (
|
||||
{ dataSourceId, type }: TGetSecretScanningDataSource,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TSecretScanningDataSource,
|
||||
unknown,
|
||||
TSecretScanningDataSource,
|
||||
ReturnType<typeof secretScanningV2Keys.dataSourceById>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: secretScanningV2Keys.dataSourceById(dataSourceId),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TSecretScanningDataSourceResponse>(
|
||||
`/api/v2/secret-scanning/data-sources/${type}/${dataSourceId}`
|
||||
);
|
||||
|
||||
return data.dataSource;
|
||||
},
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
export const useListSecretScanningResources = (
|
||||
{ dataSourceId, type }: TGetSecretScanningDataSource,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TSecretScanningResourceWithDetails[],
|
||||
unknown,
|
||||
TSecretScanningResourceWithDetails[],
|
||||
ReturnType<typeof secretScanningV2Keys.listResources>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: secretScanningV2Keys.listResources(dataSourceId),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TListSecretScanningResourcesResponse>(
|
||||
`/api/v2/secret-scanning/data-sources/${type}/${dataSourceId}/resources-dashboard`
|
||||
);
|
||||
|
||||
return data.resources;
|
||||
},
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
export const useListSecretScanningScans = (
|
||||
{ dataSourceId, type }: TGetSecretScanningDataSource,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TSecretScanningScanWithDetails[],
|
||||
unknown,
|
||||
TSecretScanningScanWithDetails[],
|
||||
ReturnType<typeof secretScanningV2Keys.listScans>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: secretScanningV2Keys.listScans(dataSourceId),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TListSecretScanningScansResponse>(
|
||||
`/api/v2/secret-scanning/data-sources/${type}/${dataSourceId}/scans-dashboard`
|
||||
);
|
||||
|
||||
return data.scans;
|
||||
},
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetSecretScanningUnresolvedFindingCount = (
|
||||
projectId: string,
|
||||
options?: Omit<
|
||||
UseQueryOptions<number, unknown, number, ReturnType<typeof secretScanningV2Keys.findingCount>>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: secretScanningV2Keys.findingCount(projectId),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TGetSecretScanningUnresolvedFindingsResponse>(
|
||||
"/api/v2/secret-scanning/unresolved-findings-count",
|
||||
{ params: { projectId } }
|
||||
);
|
||||
|
||||
return data.unresolvedFindings;
|
||||
},
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
export const useListSecretScanningFindings = (
|
||||
projectId: string,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TSecretScanningFinding[],
|
||||
unknown,
|
||||
TSecretScanningFinding[],
|
||||
ReturnType<typeof secretScanningV2Keys.listFindings>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: secretScanningV2Keys.listFindings(projectId),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TListSecretScanningFindingsResponse>(
|
||||
"/api/v2/secret-scanning/findings",
|
||||
{ params: { projectId } }
|
||||
);
|
||||
|
||||
return data.findings;
|
||||
},
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetSecretScanningConfig = (
|
||||
projectId: string,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TSecretScanningConfig,
|
||||
unknown,
|
||||
TSecretScanningConfig,
|
||||
ReturnType<typeof secretScanningV2Keys.configByProjectId>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: secretScanningV2Keys.configByProjectId(projectId),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TGetSecretScanningConfigResponse>(
|
||||
"/api/v2/secret-scanning/configs",
|
||||
{ params: { projectId } }
|
||||
);
|
||||
|
||||
return data.config;
|
||||
},
|
||||
...options
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
|
||||
import { SecretScanningDataSource } from "../enums";
|
||||
import { TSecretScanningDataSourceBase } from "./shared";
|
||||
|
||||
export type TGitHubDataSource = TSecretScanningDataSourceBase & {
|
||||
type: SecretScanningDataSource.GitHub;
|
||||
config: {
|
||||
includeRepos: string[];
|
||||
};
|
||||
};
|
||||
|
||||
export type TGitHubDataSourceOption = {
|
||||
name: string;
|
||||
type: SecretScanningDataSource.GitHub;
|
||||
connection: AppConnection.GitHub;
|
||||
};
|
||||
@@ -0,0 +1,166 @@
|
||||
import { DiscriminativePick } from "@app/types";
|
||||
|
||||
import {
|
||||
SecretScanningDataSource,
|
||||
SecretScanningFindingSeverity,
|
||||
SecretScanningFindingStatus,
|
||||
SecretScanningResource,
|
||||
SecretScanningScanStatus,
|
||||
SecretScanningScanType
|
||||
} from "../enums";
|
||||
import { TGitHubDataSource, TGitHubDataSourceOption } from "./github-data-source";
|
||||
|
||||
export type TSecretScanningDataSource = TGitHubDataSource;
|
||||
|
||||
export type TSecretScanningDataSourceWithDetails = TSecretScanningDataSource & {
|
||||
lastScannedAt: string | null;
|
||||
lastScanStatus: SecretScanningScanStatus | null;
|
||||
lastScanStatusMessage: string | null;
|
||||
unresolvedFindings: number | null;
|
||||
};
|
||||
|
||||
export type TListSecretScanningDataSources = {
|
||||
dataSources: TSecretScanningDataSourceWithDetails[];
|
||||
};
|
||||
|
||||
export type TSecretScanningDataSourceOption = TGitHubDataSourceOption;
|
||||
|
||||
export type TListSecretScanningDataSourceOptions = {
|
||||
dataSourceOptions: TSecretScanningDataSourceOption[];
|
||||
};
|
||||
|
||||
export type TSecretScanningDataSourceResponse = { dataSource: TSecretScanningDataSource };
|
||||
|
||||
export type TCreateSecretScanningDataSourceDTO = DiscriminativePick<
|
||||
TSecretScanningDataSource,
|
||||
"name" | "config" | "description" | "connectionId" | "type" | "isAutoScanEnabled" | "projectId"
|
||||
>;
|
||||
|
||||
export type TUpdateSecretScanningDataSourceDTO = Partial<
|
||||
Omit<TCreateSecretScanningDataSourceDTO, "type" | "connectionId" | "projectId">
|
||||
> & {
|
||||
type: SecretScanningDataSource;
|
||||
dataSourceId: string;
|
||||
// required for query invalidation
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export type TDeleteSecretScanningDataSourceDTO = {
|
||||
type: SecretScanningDataSource;
|
||||
dataSourceId: string;
|
||||
// required for query invalidation
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export type TTriggerSecretScanningDataSourceDTO = {
|
||||
type: SecretScanningDataSource;
|
||||
dataSourceId: string;
|
||||
resourceId?: string;
|
||||
// required for query invalidation
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export type TUpdateSecretScanningFinding = {
|
||||
findingId: string;
|
||||
status: SecretScanningFindingStatus;
|
||||
remarks?: string | null;
|
||||
// required for query invalidation
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export type TSecretScanningFindingResponse = {
|
||||
finding: TSecretScanningFinding;
|
||||
};
|
||||
|
||||
export type TGetSecretScanningDataSource = {
|
||||
dataSourceId: string;
|
||||
type: SecretScanningDataSource;
|
||||
};
|
||||
|
||||
export type TSecretScanningResourceWithDetails = {
|
||||
id: string;
|
||||
dataSourceId: string;
|
||||
type: SecretScanningResource;
|
||||
externalId: string;
|
||||
name: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
lastScannedAt: string;
|
||||
lastScanStatus: SecretScanningScanStatus;
|
||||
lastScanStatusMessage: string | null;
|
||||
unresolvedFindings: number;
|
||||
};
|
||||
|
||||
export type TListSecretScanningResourcesResponse = {
|
||||
resources: TSecretScanningResourceWithDetails[];
|
||||
};
|
||||
|
||||
export type TSecretScanningScanWithDetails = {
|
||||
id: string;
|
||||
createdAt: string;
|
||||
resourceId: string;
|
||||
type: SecretScanningScanType;
|
||||
status: SecretScanningScanStatus;
|
||||
statusMessage?: string | null;
|
||||
unresolvedFindings: number;
|
||||
resolvedFindings: number;
|
||||
resourceName: string;
|
||||
};
|
||||
|
||||
export type TListSecretScanningScansResponse = {
|
||||
scans: TSecretScanningScanWithDetails[];
|
||||
};
|
||||
|
||||
export type TGetSecretScanningUnresolvedFindingsResponse = {
|
||||
unresolvedFindings: number;
|
||||
};
|
||||
|
||||
export type TSecretScanningConfig = {
|
||||
projectId: string;
|
||||
content: string | null;
|
||||
};
|
||||
|
||||
export type TGetSecretScanningConfigResponse = {
|
||||
config: TSecretScanningConfig;
|
||||
};
|
||||
|
||||
export type TSecretScanningFinding = {
|
||||
id: string;
|
||||
dataSourceName: string;
|
||||
dataSourceType: SecretScanningDataSource;
|
||||
resourceName: string;
|
||||
resourceType: SecretScanningResource;
|
||||
rule: string;
|
||||
severity: SecretScanningFindingSeverity;
|
||||
status: SecretScanningFindingStatus;
|
||||
remarks?: string;
|
||||
fingerprint: string;
|
||||
// TODO scott: this will need to be type differentiated once we add other scan types
|
||||
details: {
|
||||
description: string;
|
||||
startLine: number;
|
||||
endLine: number;
|
||||
startColumn: number;
|
||||
endColumn: number;
|
||||
file: string;
|
||||
link: string;
|
||||
symlinkFile: string;
|
||||
commit: string;
|
||||
entropy: string;
|
||||
author: string;
|
||||
email: string;
|
||||
date: string;
|
||||
message: string;
|
||||
tags: string[];
|
||||
ruleID: string;
|
||||
fingerprint: string;
|
||||
};
|
||||
projectId: string;
|
||||
scanId: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type TListSecretScanningFindingsResponse = {
|
||||
findings: TSecretScanningFinding[];
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./secret-scanning-data-source-base";
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
|
||||
export type TSecretScanningDataSourceBase = {
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string | null;
|
||||
connectionId?: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
projectId: string;
|
||||
connection?: {
|
||||
app: AppConnection;
|
||||
id: string;
|
||||
name: string;
|
||||
} | null;
|
||||
isAutoScanEnabled: boolean;
|
||||
isDisconnected: boolean;
|
||||
};
|
||||
@@ -50,6 +50,7 @@ export type SubscriptionPlan = {
|
||||
enforceMfa: boolean;
|
||||
projectTemplates: boolean;
|
||||
kmip: boolean;
|
||||
secretScanning: boolean;
|
||||
enterpriseSecretSyncs: boolean;
|
||||
enterpriseAppConnections: boolean;
|
||||
};
|
||||
|
||||
@@ -12,7 +12,8 @@ export enum ProjectType {
|
||||
SecretManager = "secret-manager",
|
||||
CertificateManager = "cert-manager",
|
||||
KMS = "kms",
|
||||
SSH = "ssh"
|
||||
SSH = "ssh",
|
||||
SecretScanning = "secret-scanning"
|
||||
}
|
||||
|
||||
export enum ProjectUserMembershipTemporaryMode {
|
||||
|
||||
@@ -6,16 +6,18 @@ import { useDebounce } from "@app/hooks/useDebounce";
|
||||
export const usePagination = <T extends string>(
|
||||
initialOrderBy: T,
|
||||
{
|
||||
initPerPage = 100
|
||||
initPerPage = 100,
|
||||
initSearch = ""
|
||||
}: {
|
||||
initPerPage?: number;
|
||||
initSearch?: string;
|
||||
} = {}
|
||||
) => {
|
||||
const [page, setPage] = useState(1);
|
||||
const [perPage, setPerPage] = useState(initPerPage);
|
||||
const [orderDirection, setOrderDirection] = useState(OrderByDirection.ASC);
|
||||
const [orderBy, setOrderBy] = useState<T>(initialOrderBy);
|
||||
const [search, setSearch] = useState("");
|
||||
const [search, setSearch] = useState(initSearch);
|
||||
const [debouncedSearch] = useDebounce(search);
|
||||
|
||||
const offset = (page - 1) * perPage;
|
||||
|
||||
Reference in New Issue
Block a user