Skip to content

Commit

Permalink
fix: load all issues and not just the first 100 (#204)
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanbuck-snyk authored Sep 11, 2024
1 parent 97fa2c3 commit f3a000e
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 87 deletions.
44 changes: 29 additions & 15 deletions src/api/SnykApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { Entity } from "@backstage/catalog-model";
import { mockedDepGraphs } from "../utils/mockedDepGraphs";
import { mockedProjectDetails } from "../utils/mockedProjectDetails";
import { IssuesCount } from "../types/types";
import { Issue } from "../types/unifiedIssuesTypes";
import { Issue, UnifiedIssues } from "../types/unifiedIssuesTypes";
const pkg = require('../../package.json');
const DEFAULT_PROXY_PATH_BASE = "";

Expand All @@ -42,7 +42,7 @@ export const snykApiRef: ApiRef<SnykApi> = createApiRef<SnykApi>({
});

export interface SnykApi {
listAllAggregatedIssues(orgName: string, projectId: string): Promise<any>;
listAllAggregatedIssues(orgName: string, projectId: string): Promise<UnifiedIssues>;

getProjectDetails(orgName: string, projectId: string): Promise<any>;

Expand Down Expand Up @@ -232,26 +232,40 @@ export class SnykApiClient implements SnykApi {
};
};

async listAllAggregatedIssues(orgId: string, projectId: string) {
async listAllAggregatedIssues(orgId: string, projectId: string): Promise<UnifiedIssues> {
if (this.isMocked()) {
await new Promise((resolve) => setTimeout(resolve, 500));
return mockedIssues[projectId];
}

const backendBaseUrl = await this.getApiUrl();
const v3Headers = this.headers;
const fetchPage = async (url: string): Promise<any[]> => {
const backendBaseUrl = await this.getApiUrl();
const v3Headers = this.headers;
v3Headers["Content-Type"] = "application/vnd.api+json";

const response = await this.fetch(`${backendBaseUrl}${url}`, "GET");

if (response.status >= 400 && response.status < 600) {
throw new Error(`Error ${response.status} - Failed fetching Vuln Issues snyk data`);
}

const json = await response.json();

const currentIssues = json?.data || [];

if (json?.links?.next) {
const nextPageIssues = await fetchPage(json.links.next);
return [...currentIssues, ...nextPageIssues];
}

return currentIssues;
};

const version = this.getSnykIssuesApiVersion();
v3Headers["Content-Type"] = "application/vnd.api+json";
const apiUrl = `${backendBaseUrl}/rest/orgs/${orgId}/issues?version=${version}&scan_item.id=${projectId}&scan_item.type=project&limit=100`;
const response = await this.fetch(`${apiUrl}`, "GET");
const initialApiUrl = `/rest/orgs/${orgId}/issues?version=${version}&scan_item.id=${projectId}&scan_item.type=project&limit=100`;

if (response.status >= 400 && response.status < 600) {
throw new Error(
`Error ${response.status} - Failed fetching Vuln Issues snyk data`
);
}
return response.json();
}
return await fetchPage(initialApiUrl);
}

async getProjectDetails(orgName: string, projectId: string) {
if (this.isMocked()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export const SnykOverviewComponent = ({ entity }: { entity: Entity }) => {
);

const currentProjectIssuesCount = snykApi.getIssuesCount(
vulnsIssues.data
vulnsIssues
);
aggregatedIssuesCount.critical += currentProjectIssuesCount.critical;
aggregatedIssuesCount.high += currentProjectIssuesCount.high;
Expand Down
6 changes: 3 additions & 3 deletions src/components/SnykEntityComponent/SnykTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ export const generateSnykTabForProject = (
orgId,
projectId
);
const genericIssues: Array<Issue> = allIssues.data.filter((issue) =>
const genericIssues: Array<Issue> = allIssues.filter((issue) =>
genericIssuesTypeArray.includes(issue.attributes.type)
);
const licenseIssues: Array<Issue> = allIssues.data.filter(
const licenseIssues: Array<Issue> = allIssues.filter(
(issue) => issue.attributes.type === "license"
);
const ignoredIssues: Array<Issue> = allIssues.data.filter(
const ignoredIssues: Array<Issue> = allIssues.filter(
(issue) =>
issue.attributes.ignored === true &&
issue.attributes.status != IssueAttributesStatusEnum.Resolved
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,13 @@ export const IssuesTable: FC<DenseTableProps> = ({ issues, pageUrl }) => {
return (
<Table
title="Security vulnerabilities"
options={{ search: false, paging: false }}
options={{
search: false,
paging: true,
pageSize: 20,
paginationPosition: 'both',
pageSizeOptions: [20, 50, 100]
}}
columns={columns}
data={data}
/>
Expand Down
68 changes: 1 addition & 67 deletions src/types/unifiedIssuesTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -709,70 +709,4 @@ export interface Issue {
type: IssueType;
}

export interface JsonApi {
/**
* Version of the JSON API specification this server supports.
* @type {string}
* @memberof JsonApi
*/
version: string;
}
export interface LinkProperty {}
/**
*
* @export
* @interface PaginatedLinks
*/
export interface PaginatedLinks {
/**
*
* @type {LinkProperty}
* @memberof PaginatedLinks
*/
first?: LinkProperty;
/**
*
* @type {LinkProperty}
* @memberof PaginatedLinks
*/
last?: LinkProperty;
/**
*
* @type {LinkProperty}
* @memberof PaginatedLinks
*/
next?: LinkProperty;
/**
*
* @type {LinkProperty}
* @memberof PaginatedLinks
*/
prev?: LinkProperty;
/**
*
* @type {LinkProperty}
* @memberof PaginatedLinks
*/
self?: LinkProperty;
}

export interface UnifiedIssues {
/**
*
* @type {Array<Issue>}
* @memberof InlineResponse2003
*/
data: Array<Issue>;
/**
*
* @type {JsonApi}
* @memberof InlineResponse2003
*/
jsonapi: JsonApi;
/**
*
* @type {PaginatedLinks}
* @memberof InlineResponse2003
*/
links?: PaginatedLinks;
}
export type UnifiedIssues = Array<Issue>;

0 comments on commit f3a000e

Please sign in to comment.