← Files Codex Security CloudARCHIVED FILE

.internal/defense-factory-ui/src/scans.tsx

33.3 KB · Oct 4, 2026 · 12:24 UTC

↓ Download file

import type { components } from "@oai/aardvark-client/components";
import { useMutation, useQuery } from "@tanstack/react-query";
import { useState, type ReactNode } from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { useLocation, useParams, useSearchParams } from "react-router";

import { useCloud } from "./app-context";
import { securityClient } from "./client";
import { ContinuousScanDetail } from "./continuous-scans";
import { ScanLaunch } from "./scan-launch";
import { repositoryLabel } from "./ui";
import {
  WorkbenchButton as Button,
  WorkbenchSearchInput,
} from "./workbench/controls";
import {
  ScanCancelConfirmation,
  ScanDetailPresentation,
  ScanFindingsUnavailable,
} from "./workbench/scan-detail-presentation";
import { ScanFindings } from "./workbench/scan-findings";
import { ScanWorkflowOutput } from "./workbench/scan-workflow-output";
import { ScansFilterMenu } from "./workbench/scans-filters";
import { scanMessages } from "./workbench/scans-messages";
import {
  filterAndSortWorkbenchScans,
  type ScanSortField,
  type ScanStatusFilter,
  type ScanTypeFilter,
  type WorkbenchScan,
} from "./workbench/scans-model";
import { WorkbenchScansTable } from "./workbench/scans-table";
import { WorkbenchState, WorkbenchToolbar } from "./workbench/layout";
import { workbenchStyles } from "./workbench/styles";

const running = new Set([
  "queued",
  "preparing",
  "running",
  "validating_output",
  "cancel_requested",
]);

type ScanConfiguration =
  components["schemas"]["AardvarkScanConfigurationListItem"];
type WorkflowRepository =
  components["schemas"]["WorkflowRunRepositoryMetadataItem"];

type RepositoryScope = {
  configuration?: ScanConfiguration;
  repoConnectorId: string | null;
  repoId: string;
  repoUrl?: string;
};

const PAGINATION_PARAMETERS = [
  "cursor",
  "commit_cursor",
  "workflow_exhausted",
  "commit_exhausted",
] as const;

function clearPagination(parameters: URLSearchParams) {
  for (const parameter of PAGINATION_PARAMETERS) parameters.delete(parameter);
}

function paginationKey(parameters: URLSearchParams) {
  return PAGINATION_PARAMETERS.map(
    (parameter) => `${parameter}:${parameters.get(parameter) ?? ""}`,
  ).join("|");
}

function isContinuousConfiguration(configuration: ScanConfiguration) {
  return (
    configuration.scan_type === "continuous_scan" &&
    !configuration.soft_deleted_at
  );
}

function normalizedRepositoryUrl(repositoryUrl?: string | null) {
  return repositoryUrl?.replace(/\.git$/, "");
}

function configurationMatchesScope(
  configuration: ScanConfiguration,
  repoId?: string,
  repoUrl?: string,
) {
  return (
    isContinuousConfiguration(configuration) &&
    (!repoId || configuration.scan_input.repo_id === repoId) &&
    (!repoUrl ||
      normalizedRepositoryUrl(configuration.scan_input.repo_url) ===
        normalizedRepositoryUrl(repoUrl))
  );
}

function publicRepositoryUrl(repository: WorkflowRepository) {
  return repository.repo_connector_id == null
    ? `https://github.com/${repository.repository_full_name}`
    : undefined;
}

function repositoryIdentityKey(repository: {
  repo_id: string;
  repo_connector_id?: string | null;
}) {
  return `${repository.repo_id}:${repository.repo_connector_id ?? "public"}`;
}

export function Scans() {
  const { id, repositoryId } = useParams();
  const location = useLocation();
  const [search] = useSearchParams();
  const configurationId = search.get("scan_configuration_id");
  const isWorkflowRunId = Boolean(id && /^wfr_[0-9a-f]{64}$/.test(id));
  if (id && !isWorkflowRunId) {
    return (
      <ContinuousScanDetail
        key={id}
        configurationId={configurationId}
        repositoryId={repositoryId}
        scanId={id}
      />
    );
  }
  return location.pathname === "/scans/new" ? (
    <ScanLaunch key={search.get("repo_id") ?? ""} />
  ) : id ? (
    <ScanDetail key={id} id={id} />
  ) : (
    <ScanList />
  );
}

function ScanList() {
  const intl = useIntl();
  const { repositoryId: routeRepositoryId } = useParams();
  const { accountId, identity } = useCloud();
  const [search, setSearch] = useSearchParams();
  const [previousPages, setPreviousPages] = useState<Record<string, string>>(
    {},
  );
  const [text, setText] = useState("");
  const [status, setStatus] = useState<ScanStatusFilter>("all");
  const [scanType, setScanType] = useState<ScanTypeFilter>("all");
  const [sortField, setSortField] = useState<ScanSortField>("started");
  const [sortDescending, setSortDescending] = useState(true);
  const configurationId = search.get("scan_configuration_id");
  const hasRepoIdParameter = search.has("repo_id");
  const hasRepoUrlParameter = search.has("repo");
  const repoIdParameter = search.get("repo_id") ?? undefined;
  const repoUrlParameter = search.get("repo") ?? undefined;
  const requestedRepoId = routeRepositoryId ?? repoIdParameter;
  const requestedRepoUrl = repoUrlParameter;
  const hintsConflict = Boolean(
    (routeRepositoryId &&
      repoIdParameter &&
      routeRepositoryId !== repoIdParameter) ||
      (hasRepoIdParameter && !repoIdParameter?.trim()) ||
      (hasRepoUrlParameter && !repoUrlParameter?.trim()),
  );
  const hasExplicitRepositoryScope = Boolean(
    routeRepositoryId ||
      hasRepoIdParameter ||
      hasRepoUrlParameter ||
      configurationId,
  );
  const selectedScanType =
    !hasExplicitRepositoryScope && scanType === "commit_scan"
      ? "all"
      : scanType;

  const repositories = useQuery({
    queryKey: [
      "scan-filter-repositories",
      accountId,
      identity?.userId ?? "none",
    ],
    queryFn: () =>
      securityClient.request({ operation: "workflow_repositories" }),
    refetchOnMount: "always",
    staleTime: 60_000,
  });
  const configurationById = useQuery({
    queryKey: [
      "scan-configuration-scope",
      accountId,
      identity?.userId ?? "none",
      configurationId,
    ],
    queryFn: () =>
      securityClient.request({
        operation: "monitoring_get",
        parameters: { path: { id: configurationId ?? "" } },
      }),
    enabled: Boolean(configurationId && !hintsConflict),
    refetchOnMount: "always",
    staleTime: 15_000,
  });
  const configurationsForScope = useQuery({
    queryKey: [
      "scan-configurations-for-scope",
      accountId,
      identity?.userId ?? "none",
      requestedRepoId,
      requestedRepoUrl,
    ],
    queryFn: () =>
      securityClient.request({
        operation: "monitoring_list",
        parameters: {
          query: {
            repo_id: requestedRepoId,
            repo_url: requestedRepoId ? undefined : requestedRepoUrl,
            scan_type: "continuous_scan",
            limit: 2,
          },
        },
      }),
    enabled: Boolean(
      !configurationId &&
        !hintsConflict &&
        (requestedRepoId || requestedRepoUrl),
    ),
    refetchOnMount: "always",
    staleTime: 15_000,
  });

  const authorizedRepositories =
    repositories.isFetchedAfterMount && !repositories.error
      ? repositories.data
      : undefined;
  const authorizedConfigurationById =
    configurationById.isFetchedAfterMount && !configurationById.error
      ? configurationById.data
      : undefined;
  const authorizedConfigurationsForScope =
    configurationsForScope.isFetchedAfterMount && !configurationsForScope.error
      ? configurationsForScope.data
      : undefined;
  const matchingConfigurations = (
    authorizedConfigurationsForScope?.items ?? []
  ).filter((configuration) =>
    configurationMatchesScope(configuration, requestedRepoId, requestedRepoUrl),
  );
  const configurationScopeConflicts = Boolean(
    requestedRepoId &&
      requestedRepoUrl &&
      authorizedConfigurationsForScope?.items.some(isContinuousConfiguration) &&
      matchingConfigurations.length === 0,
  );
  const matchingWorkflowRepositories = Array.from(
    new Map(
      (authorizedRepositories?.items ?? [])
        .filter(
          (repository) =>
            (!requestedRepoId || repository.repo_id === requestedRepoId) &&
            (!requestedRepoUrl ||
              normalizedRepositoryUrl(publicRepositoryUrl(repository)) ===
                normalizedRepositoryUrl(requestedRepoUrl) ||
              // Nested repository pages render this child only after their
              // wrapper resolves and normalizes the requested repository URL.
              // That lets connector-scoped repositories use the matching
              // authorized repository identity without inventing a public URL.
              Boolean(routeRepositoryId && repository.repo_connector_id)),
        )
        .map((repository) => [repositoryIdentityKey(repository), repository]),
    ).values(),
  );

  let resolvedScope: RepositoryScope | null = null;
  let scopeIsPending = false;
  let scopeIsUnavailable = hintsConflict;
  if (!scopeIsUnavailable && configurationId) {
    if (configurationById.isPending || !configurationById.isFetchedAfterMount) {
      scopeIsPending = true;
    } else if (
      configurationById.error ||
      !authorizedConfigurationById ||
      (authorizedConfigurationById.id !== configurationId &&
        authorizedConfigurationById.hid !== configurationId) ||
      !configurationMatchesScope(
        authorizedConfigurationById,
        requestedRepoId,
        requestedRepoUrl,
      )
    ) {
      scopeIsUnavailable = true;
    } else {
      resolvedScope = {
        configuration: authorizedConfigurationById,
        repoConnectorId:
          authorizedConfigurationById.scan_input.repo_connector_id ?? null,
        repoId: authorizedConfigurationById.scan_input.repo_id,
        repoUrl: authorizedConfigurationById.scan_input.repo_url,
      };
    }
  } else if (!scopeIsUnavailable && hasExplicitRepositoryScope) {
    if (
      configurationsForScope.isPending ||
      !configurationsForScope.isFetchedAfterMount ||
      repositories.isPending ||
      !repositories.isFetchedAfterMount
    ) {
      scopeIsPending = true;
    } else if (configurationScopeConflicts) {
      // A repository ID with an active configuration for another URL is an
      // explicit identity conflict. Do not fall back to workflow history.
      scopeIsUnavailable = true;
    } else if (
      matchingConfigurations.length > 1 ||
      authorizedConfigurationsForScope?.next_cursor
    ) {
      scopeIsUnavailable = true;
    } else if (matchingConfigurations.length === 1) {
      const configuration = matchingConfigurations[0];
      resolvedScope = {
        configuration,
        repoConnectorId: configuration.scan_input.repo_connector_id ?? null,
        repoId: configuration.scan_input.repo_id,
        repoUrl: configuration.scan_input.repo_url,
      };
    } else if (matchingWorkflowRepositories.length === 1) {
      const repository = matchingWorkflowRepositories[0];
      resolvedScope = {
        repoConnectorId: repository.repo_connector_id ?? null,
        repoId: repository.repo_id,
        repoUrl: publicRepositoryUrl(repository),
      };
    } else {
      scopeIsUnavailable = true;
    }
  }

  const workflowCursor = search.get("cursor") || undefined;
  const commitCursor = search.get("commit_cursor") || undefined;
  const workflowPageIsExhausted = search.get("workflow_exhausted") === "true";
  // Old workflow-only deep links do not have a paired commit cursor. Do not
  // repeat the first commit page alongside a later workflow page.
  const commitPageIsExhausted =
    search.get("commit_exhausted") === "true" ||
    Boolean(
      workflowCursor &&
        !search.has("commit_cursor") &&
        !search.has("commit_exhausted"),
    );
  const canQueryHistory = !hasExplicitRepositoryScope || Boolean(resolvedScope);
  const workflowQuery = useQuery({
    queryKey: [
      "scans",
      accountId,
      identity?.userId ?? "none",
      resolvedScope?.repoId,
      workflowCursor,
    ],
    queryFn: () =>
      securityClient.request({
        operation: "workflow_list",
        parameters: {
          query: {
            repo_id: resolvedScope?.repoId,
            cursor: workflowCursor,
            limit: 50,
            include_ownership: true,
          },
        },
      }),
    enabled: canQueryHistory && !scopeIsPending && !workflowPageIsExhausted,
    refetchOnMount: "always",
    staleTime: 4_000,
    refetchInterval: (query) =>
      query.state.data?.items.some((run) => running.has(run.status))
        ? 4_000
        : false,
  });
  const configuration = resolvedScope?.configuration;
  const configurationRequestId = configuration
    ? configuration.hid || configuration.id
    : undefined;
  const commitQuery = useQuery({
    queryKey: [
      "continuous-scans",
      accountId,
      identity?.userId ?? "none",
      configurationRequestId,
      commitCursor,
      search.get("include_deleted") === "true",
    ],
    queryFn: () =>
      securityClient.request({
        operation: "monitoring_scans",
        parameters: {
          path: { id: configurationRequestId ?? "" },
          query: {
            limit: 25,
            cursor: commitCursor,
            include_deleted: search.get("include_deleted") === "true",
          },
        },
      }),
    enabled: Boolean(
      canQueryHistory &&
        !scopeIsPending &&
        configurationRequestId &&
        !commitPageIsExhausted,
    ),
    refetchOnMount: "always",
    staleTime: 4_000,
    refetchInterval: (query) =>
      query.state.data?.items.some(
        (scan) => scan.status === "created" || scan.status === "in_progress",
      )
        ? 4_000
        : false,
  });
  const environments = useQuery({
    queryKey: ["scan-environments", accountId, identity?.userId ?? "none"],
    queryFn: () => securityClient.request({ operation: "environments_list" }),
    refetchOnMount: "always",
    staleTime: 60_000,
  });
  const environmentLabels = new Map(
    (environments.isFetchedAfterMount && !environments.error
      ? environments.data ?? []
      : []
    ).map((environment) => [environment.id, environment.label]),
  );
  const environmentsAreLoading =
    environments.isPending || !environments.isFetchedAfterMount;
  const workflowPage =
    canQueryHistory &&
    !scopeIsPending &&
    workflowQuery.isEnabled &&
    !workflowPageIsExhausted &&
    workflowQuery.isFetchedAfterMount &&
    !workflowQuery.error
      ? workflowQuery.data
      : undefined;
  const commitPage =
    canQueryHistory &&
    !scopeIsPending &&
    commitQuery.isEnabled &&
    !commitPageIsExhausted &&
    commitQuery.isFetchedAfterMount &&
    !commitQuery.error
      ? commitQuery.data
      : undefined;
  const workflowScans: WorkbenchScan[] = (workflowPage?.items ?? [])
    .filter(
      (workflow) =>
        !resolvedScope ||
        (workflow.repo_id === resolvedScope.repoId &&
          (workflow.repo_connector_id ?? null) ===
            resolvedScope.repoConnectorId),
    )
    .map((workflow) => {
      const scopedConfiguration =
        configuration?.scan_input.repo_id === workflow.repo_id &&
        (configuration.scan_input.repo_connector_id ?? null) ===
          (workflow.repo_connector_id ?? null)
          ? configuration
          : undefined;
      const repositoryUrl =
        workflow.repository_url ??
        scopedConfiguration?.scan_input.repo_url ??
        (workflow.repo_connector_id == null && workflow.repository_full_name
          ? `https://github.com/${workflow.repository_full_name}`
          : "");
      const environmentId =
        workflow.environment_id ??
        scopedConfiguration?.scan_input.environment_id;
      return {
        id: workflow.run_id,
        workflow,
        scanType: "repository_scan",
        repositoryId: workflow.repo_id,
        repositoryName:
          workflow.repository_full_name ??
          (repositoryUrl ? repositoryLabel(repositoryUrl) : workflow.repo_id),
        repositoryUrl,
        environmentLabel: environmentId
          ? environmentLabels.get(environmentId)
          : null,
        isEnvironmentLoading: Boolean(environmentId) && environmentsAreLoading,
      };
    });
  const commitScans: WorkbenchScan[] = (commitPage?.items ?? [])
    .filter(
      (scan) =>
        configuration &&
        (scan.scan_configuration_id === configuration.id ||
          scan.scan_configuration_id === configuration.hid) &&
        scan.scan_input.repo_id === configuration.scan_input.repo_id &&
        normalizedRepositoryUrl(scan.scan_input.repo_url) ===
          normalizedRepositoryUrl(configuration.scan_input.repo_url) &&
        (scan.scan_input.repo_connector_id ?? null) ===
          (configuration.scan_input.repo_connector_id ?? null),
    )
    .map((commitScan) => {
      const environmentId =
        commitScan.scan_input.environment_id ||
        configuration?.scan_input.environment_id;
      const repositoryUrl = commitScan.scan_input.repo_url;
      return {
        id: commitScan.id,
        commitScan,
        scanType: "commit_scan",
        repositoryId: commitScan.scan_input.repo_id,
        repositoryName:
          repositoryLabel(repositoryUrl) || commitScan.scan_input.repo_id,
        repositoryUrl,
        environmentLabel: environmentId
          ? environmentLabels.get(environmentId)
          : null,
        isEnvironmentLoading: Boolean(environmentId) && environmentsAreLoading,
      };
    });
  const scans = [...workflowScans, ...commitScans];
  const filteredScans = filterAndSortWorkbenchScans({
    scans,
    searchQuery: text,
    statusFilter: status,
    scanTypeFilter: selectedScanType,
    sortField,
    sortDescending,
    intl,
  });
  const repositoriesById = new Map<string, Map<string, WorkflowRepository>>();
  for (const repository of authorizedRepositories?.items ?? []) {
    const identities = repositoriesById.get(repository.repo_id) ?? new Map();
    identities.set(repositoryIdentityKey(repository), repository);
    repositoriesById.set(repository.repo_id, identities);
  }
  const repositoryOptions = new Map<
    string,
    { value: string; label: string; url?: string }
  >();
  for (const [repoId, identities] of repositoriesById) {
    if (identities.size !== 1) continue;
    const repository = Array.from(identities.values())[0];
    const selectedConfigurationUrl =
      configuration?.scan_input.repo_id === repoId &&
      (configuration.scan_input.repo_connector_id ?? null) ===
        (repository.repo_connector_id ?? null)
        ? configuration.scan_input.repo_url
        : undefined;
    repositoryOptions.set(repoId, {
      value: repoId,
      label: repository.repository_full_name,
      url: selectedConfigurationUrl ?? publicRepositoryUrl(repository),
    });
  }

  function replaceSearch(parameters: URLSearchParams) {
    const value = parameters.toString();
    setSearch(value ? `?${value}` : "", { replace: true });
  }

  function resetPagination() {
    setPreviousPages({});
    const parameters = new URLSearchParams(search);
    const hadPagination = PAGINATION_PARAMETERS.some((parameter) =>
      parameters.has(parameter),
    );
    if (!hadPagination) return;
    clearPagination(parameters);
    replaceSearch(parameters);
  }

  function selectRepository(nextRepositoryId: string) {
    const parameters = new URLSearchParams(search);
    clearPagination(parameters);
    setPreviousPages({});
    if (nextRepositoryId === "__all_repositories__") {
      if (scanType === "commit_scan") setScanType("all");
      parameters.delete("repo_id");
      parameters.delete("repo");
      parameters.delete("scan_configuration_id");
      replaceSearch(parameters);
      return;
    }
    const repository = repositoryOptions.get(nextRepositoryId);
    parameters.set("repo_id", nextRepositoryId);
    if (repository?.url) parameters.set("repo", repository.url);
    else parameters.delete("repo");
    // Resolve the matching configuration after selection. A configuration
    // from the previous repository is never carried into the new scope.
    parameters.delete("scan_configuration_id");
    replaceSearch(parameters);
  }

  function clearFilters() {
    setText("");
    setStatus("all");
    setScanType("all");
    const parameters = new URLSearchParams(search);
    if (!routeRepositoryId) {
      parameters.delete("repo_id");
      parameters.delete("repo");
      parameters.delete("scan_configuration_id");
    }
    clearPagination(parameters);
    setPreviousPages({});
    replaceSearch(parameters);
  }

  function toggleSort(nextField: ScanSortField) {
    if (sortField === nextField) {
      setSortDescending((value) => !value);
      return;
    }
    setSortField(nextField);
    setSortDescending(nextField === "started");
  }

  const hasClientFilters =
    text.trim() !== "" || status !== "all" || selectedScanType !== "all";
  const configurationLookupError =
    Boolean(configurationId && configurationById.error) ||
    Boolean(!configurationId && configurationsForScope.error);
  const scanHistoryError =
    scopeIsUnavailable ||
    Boolean(workflowQuery.error) ||
    Boolean(commitQuery.error) ||
    configurationLookupError ||
    Boolean(
      hasExplicitRepositoryScope &&
        !resolvedScope?.configuration &&
        repositories.error,
    );
  const isPending =
    scopeIsPending ||
    (workflowQuery.isEnabled &&
      (workflowQuery.isPending || !workflowQuery.isFetchedAfterMount)) ||
    (commitQuery.isEnabled &&
      (commitQuery.isPending || !commitQuery.isFetchedAfterMount));
  const isFetching =
    configurationById.isFetching ||
    configurationsForScope.isFetching ||
    (hasExplicitRepositoryScope && repositories.isFetching) ||
    workflowQuery.isFetching ||
    commitQuery.isFetching;
  const retry = () => {
    if (configurationById.error) void configurationById.refetch();
    if (configurationsForScope.error) void configurationsForScope.refetch();
    if (repositories.error) void repositories.refetch();
    if (workflowQuery.error) void workflowQuery.refetch();
    if (commitQuery.error) void commitQuery.refetch();
  };
  const retryAction =
    configurationLookupError ||
    repositories.error ||
    workflowQuery.error ||
    commitQuery.error ? (
      <Button
        type="button"
        color="outlineSurface"
        loading={isFetching}
        onClick={retry}
      >
        {intl.formatMessage(scanMessages.retryHistory)}
      </Button>
    ) : undefined;

  return (
    <section className={workbenchStyles.collectionPage}>
      <WorkbenchToolbar>
        <WorkbenchSearchInput
          id="scan-search"
          searchQuery={text}
          onSearchQueryChange={(value) => {
            resetPagination();
            setText(value);
          }}
          label={intl.formatMessage(scanMessages.searchScans)}
          placeholder={intl.formatMessage(scanMessages.searchScans)}
        />
        <div className="flex min-w-0 items-center gap-2 max-sm:w-full">
          <ScansFilterMenu
            repositoryFilter={
              routeRepositoryId
                ? undefined
                : {
                    value: resolvedScope?.repoId ?? "__all_repositories__",
                    options: [
                      {
                        value: "__all_repositories__",
                        label: intl.formatMessage(scanMessages.allRepositories),
                      },
                      ...Array.from(repositoryOptions.values())
                        .sort((first, second) =>
                          first.label.localeCompare(second.label),
                        )
                        .map(({ value, label }) => ({ value, label })),
                    ],
                    onChange: selectRepository,
                  }
            }
            scanType={selectedScanType}
            commitScansRequireRepository={!hasExplicitRepositoryScope}
            status={status}
            onScanTypeChange={(value) => {
              resetPagination();
              setScanType(value);
            }}
            onStatusChange={(value) => {
              resetPagination();
              setStatus(value);
            }}
            onClearFilters={clearFilters}
          />
        </div>
      </WorkbenchToolbar>
      {scanHistoryError && scans.length > 0 ? (
        <WorkbenchState variant="inline" action={retryAction}>
          <FormattedMessage
            id="codexSecurity.workbench.scans.error"
            defaultMessage="Scan history could not be loaded."
            description="Sanitized error shown when authorized scan history cannot be retrieved."
          />
        </WorkbenchState>
      ) : null}
      <WorkbenchScansTable
        scans={filteredScans}
        emptyState={
          filteredScans.length > 0
            ? null
            : isPending
            ? "loading"
            : scanHistoryError
            ? "unavailable"
            : hasClientFilters
            ? "filtered"
            : "unfiltered"
        }
        sort={{ field: sortField, descending: sortDescending }}
        onSort={toggleSort}
        retryAction={retryAction}
        pagination={{
          busy: isFetching,
          canGoPrevious: Object.hasOwn(previousPages, paginationKey(search)),
          canGoNext:
            !scanHistoryError &&
            Boolean(workflowPage?.next_cursor || commitPage?.next_cursor),
          onPrevious: () => {
            const previous = previousPages[paginationKey(search)];
            if (previous == null) return;
            setSearch(previous ? `?${previous}` : "", { replace: true });
          },
          onNext: () => {
            const parameters = new URLSearchParams(search);
            const nextWorkflowCursor = workflowPage?.next_cursor;
            const nextCommitCursor = commitPage?.next_cursor;
            if (!nextWorkflowCursor && !nextCommitCursor) return;
            if (workflowQuery.isEnabled) {
              if (nextWorkflowCursor) {
                parameters.set("cursor", nextWorkflowCursor);
                parameters.delete("workflow_exhausted");
              } else {
                parameters.set("workflow_exhausted", "true");
              }
            }
            if (commitQuery.isEnabled) {
              if (nextCommitCursor) {
                parameters.set("commit_cursor", nextCommitCursor);
                parameters.delete("commit_exhausted");
              } else {
                parameters.set("commit_exhausted", "true");
              }
            }
            const nextPageKey = paginationKey(parameters);
            setPreviousPages((pages) => ({
              ...pages,
              [nextPageKey]: search.toString(),
            }));
            replaceSearch(parameters);
          },
        }}
      />
    </section>
  );
}

function ScanDetail({ id }: { id: string }) {
  const { repositoryId: routeRepositoryId } = useParams();
  const { accountId, identity } = useCloud();
  const [confirmCancel, setConfirmCancel] = useState(false);
  const {
    data: run,
    error,
    isPending,
    isFetching,
    isFetchedAfterMount,
    refetch,
  } = useQuery({
    queryKey: ["scan", accountId, identity?.userId ?? "none", id],
    queryFn: () =>
      securityClient.request({
        operation: "workflow_get",
        parameters: {
          path: { run_id: id },
          query: { include_ownership: true },
        },
      }),
    refetchOnMount: "always",
    staleTime: 4_000,
    refetchInterval: (query) =>
      query.state.data && running.has(query.state.data.status) ? 4_000 : false,
  });
  const authorizedRun = isFetchedAfterMount && !error ? run : undefined;
  const repositories = useQuery({
    queryKey: [
      "scan-detail-repositories",
      accountId,
      identity?.userId ?? "none",
    ],
    queryFn: () =>
      securityClient.request({ operation: "workflow_repositories" }),
    refetchOnMount: "always",
    staleTime: 60_000,
  });
  const repositoryRuns = useQuery({
    queryKey: [
      "scan-detail-repository-runs",
      accountId,
      identity?.userId ?? "none",
      authorizedRun?.repo_id,
    ],
    queryFn: () =>
      securityClient.request({
        operation: "workflow_list",
        parameters: {
          query: {
            repo_id: authorizedRun?.repo_id,
            limit: 50,
            include_ownership: true,
          },
        },
      }),
    enabled: Boolean(authorizedRun?.repo_id),
    refetchOnMount: "always",
    staleTime: 15_000,
  });
  const monitoring = useQuery({
    queryKey: [
      "scan-detail-monitoring",
      accountId,
      identity?.userId ?? "none",
      authorizedRun?.repo_id,
    ],
    queryFn: () =>
      securityClient.request({
        operation: "monitoring_list",
        parameters: {
          query: {
            repo_id: authorizedRun?.repo_id,
            scan_type: "continuous_scan",
            limit: 25,
          },
        },
      }),
    enabled: Boolean(authorizedRun?.repo_id),
    refetchOnMount: "always",
    staleTime: 15_000,
  });
  const environments = useQuery({
    queryKey: ["scan-environments", accountId, identity?.userId ?? "none"],
    queryFn: () => securityClient.request({ operation: "environments_list" }),
    refetchOnMount: "always",
    staleTime: 60_000,
  });
  const {
    mutate: cancel,
    error: cancelError,
    isPending: canceling,
    reset: resetCancel,
  } = useMutation({
    mutationFn: () =>
      securityClient.request({
        operation: "workflow_cancel",
        parameters: { path: { run_id: id } },
      }),
    onSuccess: async () => {
      setConfirmCancel(false);
      await refetch();
    },
  });
  if (isPending || !isFetchedAfterMount) {
    return <WorkbenchState loading />;
  }
  if (error || !run) {
    return (
      <ScanDetailUnavailable
        retryAction={
          <Button
            color="outlineSurface"
            loading={isFetching}
            onClick={() => void refetch()}
          >
            <FormattedMessage
              id="codexSecurity.workbench.scans.detail.retry"
              defaultMessage="Retry"
              description="Retries loading the selected authorized scan."
            />
          </Button>
        }
      />
    );
  }
  if (routeRepositoryId && routeRepositoryId !== run.repo_id) {
    return <ScanDetailUnavailable />;
  }

  const repositoryMetadata = (
    repositories.isFetchedAfterMount && !repositories.error
      ? repositories.data?.items
      : undefined
  )?.find(
    (repository) =>
      repository.repo_id === run.repo_id &&
      (repository.repo_connector_id ?? null) ===
        (run.repo_connector_id ?? null),
  );
  const repositoryRun = (
    repositoryRuns.isFetchedAfterMount && !repositoryRuns.error
      ? repositoryRuns.data?.items
      : undefined
  )?.find(
    (candidate) =>
      candidate.run_id === run.run_id &&
      candidate.repo_id === run.repo_id &&
      (candidate.repo_connector_id ?? null) === (run.repo_connector_id ?? null),
  );
  const repositoryConfiguration = (
    monitoring.isFetchedAfterMount && !monitoring.error
      ? monitoring.data?.items
      : undefined
  )?.find(
    (configuration) =>
      configuration.scan_input.repo_id === run.repo_id &&
      (configuration.scan_input.repo_connector_id ?? null) ===
        (run.repo_connector_id ?? null),
  );
  const repositoryUrl =
    repositoryRun?.repository_url ??
    repositoryConfiguration?.scan_input.repo_url ??
    (run.repo_connector_id == null && repositoryMetadata?.repository_full_name
      ? `https://github.com/${repositoryMetadata.repository_full_name}`
      : "");
  const repositoryName =
    repositoryRun?.repository_full_name ??
    repositoryMetadata?.repository_full_name ??
    (repositoryUrl ? repositoryLabel(repositoryUrl) : run.repo_id);
  const environmentLabel =
    environments.isFetchedAfterMount && !environments.error
      ? environments.data?.find(
          (environment) => environment.id === run.environment_id,
        )?.label
      : undefined;
  const scan: WorkbenchScan = {
    id: run.run_id,
    workflow: run,
    scanType: "repository_scan",
    repositoryId: run.repo_id,
    repositoryName,
    repositoryUrl,
    environmentLabel,
    isEnvironmentLoading:
      environments.isPending || !environments.isFetchedAfterMount,
  };
  const findingsPath = routeRepositoryId
    ? `/repositories/${encodeURIComponent(routeRepositoryId)}/findings`
    : "/findings";
  const outputs = run.output_ids?.length ? (
    <div className="space-y-6">
      {run.output_ids.map((outputId) => (
        <div key={outputId} className="min-h-[28rem]">
          <ScanWorkflowOutput runId={id} outputId={outputId} />
        </div>
      ))}
    </div>
  ) : undefined;

  return (
    <ScanDetailPresentation
      scan={scan}
      outputs={outputs}
      findings={
        repositoryUrl ? (
          <ScanFindings
            detailBasePath={findingsPath}
            repositoryId={run.repo_id}
            repositoryUrl={repositoryUrl}
            scanId={run.run_id}
            scanStatus={run.status}
            source="repository_scan"
          />
        ) : (
          <ScanFindingsUnavailable />
        )
      }
      failureMessage={run.failure_message}
      isCanceling={canceling}
      onRequestCancel={() => {
        resetCancel();
        setConfirmCancel(true);
      }}
      cancelConfirmation={
        <ScanCancelConfirmation
          open={confirmCancel}
          canceling={canceling}
          failed={Boolean(cancelError)}
          onOpenChange={(open) => {
            setConfirmCancel(open);
            if (!open) resetCancel();
          }}
          onConfirm={() => cancel()}
        />
      }
    />
  );
}

function ScanDetailUnavailable({ retryAction }: { retryAction?: ReactNode }) {
  return (
    <WorkbenchState action={retryAction}>
      <FormattedMessage
        id="codexSecurity.workbench.scans.detail.unavailable"
        defaultMessage="This scan is unavailable or you do not have access to it."
        description="Privacy-preserving notice when a scan cannot be loaded or accessed."
      />
    </WorkbenchState>
  );
}

SHA-256: b193840bf9333efde648f63d1f2ad48b736abe10016ce290f319b1663d65c31b