feature: gitlab secret scanning

This commit is contained in:
Scott Wilson
2025-07-28 15:03:23 -07:00
parent 7d1bc86702
commit f2b0e4ae37
68 changed files with 1711 additions and 94 deletions
@@ -5,6 +5,7 @@ import {
import { BitbucketDataSourceConfigDisplay } from "./BitbucketDataSourceConfigDisplay";
import { GitHubDataSourceConfigDisplay } from "./GitHubDataSourceConfigDisplay";
import { GitLabDataSourceConfigDisplay } from "./GitLabDataSourceConfigDisplay";
type Props = {
dataSource: TSecretScanningDataSource;
@@ -16,6 +17,8 @@ export const DataSourceConfigDisplay = ({ dataSource }: Props) => {
return <GitHubDataSourceConfigDisplay dataSource={dataSource} />;
case SecretScanningDataSource.Bitbucket:
return <BitbucketDataSourceConfigDisplay dataSource={dataSource} />;
case SecretScanningDataSource.GitLab:
return <GitLabDataSourceConfigDisplay dataSource={dataSource} />;
default:
throw new Error(
`Unhandled dataSource type ${(dataSource as TSecretScanningDataSource).type}`
@@ -0,0 +1,41 @@
import { GenericFieldLabel } from "@app/components/v2";
import {
GitLabDataSourceScope,
TGitLabDataSource
} from "@app/hooks/api/secretScanningV2/types/gitlab-data-source";
type Props = {
dataSource: TGitLabDataSource;
};
export const GitLabDataSourceConfigDisplay = ({ dataSource }: Props) => {
const { config } = dataSource;
if (config.scope === GitLabDataSourceScope.Project) {
const { projectName, projectId } = config;
return (
<>
<GenericFieldLabel label="Scope" className="capitalize">
{config.scope}
</GenericFieldLabel>
<GenericFieldLabel label="Project">{projectName || projectId}</GenericFieldLabel>
</>
);
}
// group-scope
const { includeProjects, groupId, groupName } = config;
return (
<>
<GenericFieldLabel label="Scope" className="capitalize">
{config.scope}
</GenericFieldLabel>
<GenericFieldLabel label="Group">{groupName || groupId}</GenericFieldLabel>
<GenericFieldLabel label="Scan Projects">
{includeProjects.includes("*") ? "All" : includeProjects.join(", ")}
</GenericFieldLabel>
</>
);
};
@@ -35,12 +35,14 @@ import {
import { RESOURCE_DESCRIPTION_HELPER } from "@app/helpers/secretScanningV2";
import { useToggle } from "@app/hooks";
import {
SecretScanningDataSource,
SecretScanningFindingStatus,
SecretScanningScanStatus,
TSecretScanningDataSource,
TSecretScanningResourceWithDetails,
useTriggerSecretScanningDataSource
} from "@app/hooks/api/secretScanningV2";
import { GitLabDataSourceScope } from "@app/hooks/api/secretScanningV2/types/gitlab-data-source";
type Props = {
resource: TSecretScanningResourceWithDetails;
@@ -51,12 +53,30 @@ export const SecretScanningResourceRow = ({ resource, dataSource }: Props) => {
const { id, name, lastScannedAt, lastScanStatus, unresolvedFindings, lastScanStatusMessage } =
resource;
const {
config: { includeRepos }
} = dataSource;
let isActive: boolean;
switch (dataSource.type) {
case SecretScanningDataSource.Bitbucket:
case SecretScanningDataSource.GitHub:
isActive =
dataSource.config.includeRepos.includes("*") ||
dataSource.config.includeRepos.includes(name);
break;
case SecretScanningDataSource.GitLab: {
if (dataSource.config.scope === GitLabDataSourceScope.Project) {
isActive = true; // always active
} else {
isActive =
dataSource.config.includeProjects.includes("*") ||
dataSource.config.includeProjects.includes(name);
}
break;
}
default:
throw new Error("Unhandled Data Source Type: Active Status");
}
// scott: will need to be differentiated by type once other data sources are available
const isActive = includeRepos.includes("*") || includeRepos.includes(name);
const triggerDataSourceScan = useTriggerSecretScanningDataSource();
@@ -38,10 +38,12 @@ import { RESOURCE_DESCRIPTION_HELPER } from "@app/helpers/secretScanningV2";
import { usePagination, useResetPageHelper } from "@app/hooks";
import { OrderByDirection } from "@app/hooks/api/generic/types";
import {
SecretScanningDataSource,
SecretScanningScanStatus,
TSecretScanningDataSource,
useListSecretScanningResources
} from "@app/hooks/api/secretScanningV2";
import { GitLabDataSourceScope } from "@app/hooks/api/secretScanningV2/types/gitlab-data-source";
import { SecretScanningResourceRow } from "./SecretScanningResourceRow";
@@ -104,12 +106,29 @@ export const SecretScanningResourcesTable = ({ dataSource }: Props) => {
resources
.filter((resource) => {
const { name } = resource;
const {
config: { includeRepos }
} = dataSource;
// scott: will need to be differentiated by type once other data sources are available
const isActive = includeRepos.includes("*") || includeRepos.includes(name);
let isActive: boolean;
switch (dataSource.type) {
case SecretScanningDataSource.Bitbucket:
case SecretScanningDataSource.GitHub:
isActive =
dataSource.config.includeRepos.includes("*") ||
dataSource.config.includeRepos.includes(name);
break;
case SecretScanningDataSource.GitLab: {
if (dataSource.config.scope === GitLabDataSourceScope.Project) {
isActive = true; // always active
} else {
isActive =
dataSource.config.includeProjects.includes("*") ||
dataSource.config.includeProjects.includes(name);
}
break;
}
default:
throw new Error("Unhandled Data Source Type: Active Filter");
}
if (filters.status.length === 1) {
if (filters.status.includes(ResourceStatus.Active) && !isActive) {