Skip to content

Commit

Permalink
Merge pull request #181 from snyk-tech-services/develop
Browse files Browse the repository at this point in the history
release changes
  • Loading branch information
aarlaud authored Feb 14, 2024
2 parents 66b9743 + cb713ae commit 64d9c50
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 111 deletions.
4 changes: 4 additions & 0 deletions config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export interface Config {
* @visibility frontend
*/
apiVersion?: string;
/**
* @visibility frontend
*/
issuesApiVersion?: string;
/**
* @visibility frontend
*/
Expand Down
167 changes: 114 additions & 53 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ import {
createApiRef,
DiscoveryApi,
} from "@backstage/core-plugin-api";
import {TargetData} from "../types/targetsTypes";
import {OrgData} from "../types/orgsTypes";
import {ProjectsData} from "../types/projectsTypes";
import { TargetData } from "../types/targetsTypes";
import { OrgData } from "../types/orgsTypes";
import { ProjectsData } from "../types/projectsTypes";
import {
SNYK_ANNOTATION_TARGETID,
SNYK_ANNOTATION_TARGETNAME,
Expand All @@ -32,13 +32,13 @@ import {
SNYK_ANNOTATION_ORG,
SNYK_ANNOTATION_ORGS,
} from "../config";
import {mockedProjects} from "../utils/mockedProjects";
import {mockedIssues} from "../utils/mockedIssues";
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 { mockedProjects } from "../utils/mockedProjects";
import { mockedIssues } from "../utils/mockedIssues";
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";

const DEFAULT_PROXY_PATH_BASE = "";

Expand Down Expand Up @@ -71,6 +71,8 @@ export interface SnykApi {

getSnykApiVersion(): string;

getSnykIssuesApiVersion(): string;

getOrgSlug(orgId: string): Promise<string>;

isMocked(): boolean;
Expand All @@ -80,6 +82,8 @@ export interface SnykApi {
isShowResolvedInGraphs(entity: Entity): boolean;

getIssuesCount(issues: Array<Issue>): IssuesCount;

getIgnoredIssuesCount(issues: Array<Issue>): IssuesCount;
}

export class SnykApiClient implements SnykApi {
Expand Down Expand Up @@ -126,47 +130,92 @@ export class SnykApiClient implements SnykApi {
"2023-06-19~experimental"
);
}
getSnykIssuesApiVersion(): string {
return (
this.configApi.getOptionalString("snyk.issueApiVersion") ?? "2024-01-23"
);
}

isAvailableInEntity(entity: Entity): boolean {
return (
this.isMocked() ||
(
Boolean(entity.metadata.annotations?.[SNYK_ANNOTATION_ORG]) ||
Boolean(entity.metadata.annotations?.[SNYK_ANNOTATION_ORGS])
) && (
Boolean(entity.metadata.annotations?.[SNYK_ANNOTATION_TARGETNAME]) ||
Boolean(entity.metadata.annotations?.[SNYK_ANNOTATION_TARGETID]) ||
Boolean(entity.metadata.annotations?.[SNYK_ANNOTATION_TARGETS]) ||
Boolean(entity.metadata.annotations?.[SNYK_ANNOTATION_PROJECTIDS])
)
((Boolean(entity.metadata.annotations?.[SNYK_ANNOTATION_ORG]) ||
Boolean(entity.metadata.annotations?.[SNYK_ANNOTATION_ORGS])) &&
(Boolean(entity.metadata.annotations?.[SNYK_ANNOTATION_TARGETNAME]) ||
Boolean(entity.metadata.annotations?.[SNYK_ANNOTATION_TARGETID]) ||
Boolean(entity.metadata.annotations?.[SNYK_ANNOTATION_TARGETS]) ||
Boolean(entity.metadata.annotations?.[SNYK_ANNOTATION_PROJECTIDS])))
);
}

getIssuesCount = (issues: Array<Issue>): IssuesCount => {
const criticalSevCount = issues.filter(
(issue) =>
issue.attributes.effective_severity_level === "critical" &&
!issue.attributes.ignored &&
(issue.attributes.status !== "resolved" ||
this.isShowResolvedInGraphs())
).length;
const highSevCount = issues.filter(
(issue) =>
issue.attributes.effective_severity_level === "high" &&
!issue.attributes.ignored &&
(issue.attributes.status !== "resolved" ||
this.isShowResolvedInGraphs())
).length;
const mediumSevCount = issues.filter(
(issue) =>
issue.attributes.effective_severity_level === "medium" &&
!issue.attributes.ignored &&
(issue.attributes.status !== "resolved" ||
this.isShowResolvedInGraphs())
).length;
const lowSevCount = issues.filter(
(issue) =>
issue.attributes.effective_severity_level === "low" &&
!issue.attributes.ignored &&
(issue.attributes.status !== "resolved" ||
this.isShowResolvedInGraphs())
).length;

return {
critical: criticalSevCount,
high: highSevCount,
medium: mediumSevCount,
low: lowSevCount,
};
};

getIgnoredIssuesCount = (issues: Array<Issue>): IssuesCount => {
const criticalSevCount = issues.filter(
(issue) =>
issue.attributes.effective_severity_level === "critical" &&
issue.attributes.ignored &&
(issue.attributes.status !== "resolved" ||
this.isShowResolvedInGraphs())
).length;
const highSevCount = issues.filter(
(issue) =>
issue.attributes.effective_severity_level === "high" &&
issue.attributes.ignored &&
(issue.attributes.status !== "resolved" ||
this.isShowResolvedInGraphs())
).length;
const mediumSevCount = issues.filter(
(issue) =>
issue.attributes.effective_severity_level === "medium" &&
issue.attributes.ignored &&
(issue.attributes.status !== "resolved" ||
this.isShowResolvedInGraphs())
).length;
const lowSevCount = issues.filter(
(issue) =>
issue.attributes.effective_severity_level === "low" &&
issue.attributes.ignored &&
(issue.attributes.status !== "resolved" ||
this.isShowResolvedInGraphs())
).length;

return {
critical: criticalSevCount,
high: highSevCount,
Expand All @@ -183,7 +232,7 @@ export class SnykApiClient implements SnykApi {

const backendBaseUrl = await this.getApiUrl();
const v3Headers = this.headers;
const version = this.getSnykApiVersion();
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 fetch(`${apiUrl}`, {
Expand Down Expand Up @@ -307,53 +356,65 @@ export class SnykApiClient implements SnykApi {
`target_id=${await this.getTargetId(orgId, repoName[i])}`
);
} catch (e) {
if (!ignoreMissing) throw e
if (!ignoreMissing) throw e;
}
}
const backendBaseUrl = await this.getApiUrl();
const v3Headers = this.headers;
v3Headers["Content-Type"] = "application/vnd.api+json";
const version = this.getSnykApiVersion();
const projectsForTargetUrl = `${backendBaseUrl}/rest/orgs/${orgId}/projects?${TargetIdsArray.join(
"&"
)}&limit=100&version=${version}`;
const response = await fetch(`${projectsForTargetUrl}`, {
method: "GET",
headers: v3Headers,
});
if (TargetIdsArray.length > 0) {
const backendBaseUrl = await this.getApiUrl();
const v3Headers = this.headers;
v3Headers["Content-Type"] = "application/vnd.api+json";
const version = this.getSnykApiVersion();
const projectsForTargetUrl = `${backendBaseUrl}/rest/orgs/${orgId}/projects?${TargetIdsArray.join(
"&"
)}&limit=100&version=${version}`;
const response = await fetch(`${projectsForTargetUrl}`, {
method: "GET",
headers: v3Headers,
});

if (response.status >= 400 && response.status < 600) {
if (response.status >= 400 && response.status < 600) {
throw new Error(
`Error ${response.status} - Failed fetching Projects list snyk data`
);
}
const jsonResponse = await response.json();
return jsonResponse.data as ProjectsData[];
} else {
throw new Error(
`Error ${response.status} - Failed fetching Projects list snyk data`
`No target IDs found in org ${orgId} for the targets [${repoName.join(
","
)}].`
);
}
const jsonResponse = await response.json();
return jsonResponse.data as ProjectsData[];
}

async getProjectsListByProjectIds(
orgId: string,
projectIdsArray: string[]
): Promise<ProjectsData[]> {
const backendBaseUrl = await this.getApiUrl();
const v3Headers = this.headers;
v3Headers["Content-Type"] = "application/vnd.api+json";
const version = this.getSnykApiVersion();
const projectsForTargetUrl = `${backendBaseUrl}/rest/orgs/${orgId}/projects?ids=${projectIdsArray.join(
"%2C"
)}&limit=100&version=${version}`;
const response = await fetch(projectsForTargetUrl, {
method: "GET",
headers: v3Headers,
});
if (projectIdsArray.length > 0) {
const backendBaseUrl = await this.getApiUrl();
const v3Headers = this.headers;
v3Headers["Content-Type"] = "application/vnd.api+json";
const version = this.getSnykApiVersion();
const projectsForProjectIds = `${backendBaseUrl}/rest/orgs/${orgId}/projects?ids=${projectIdsArray.join(
"%2C"
)}&limit=100&version=${version}`;
const response = await fetch(projectsForProjectIds, {
method: "GET",
headers: v3Headers,
});

if (response.status >= 400 && response.status < 600) {
throw new Error(
`Error ${response.status} - Failed fetching Projects list snyk data`
);
if (response.status >= 400 && response.status < 600) {
throw new Error(
`Error ${response.status} - Failed fetching Projects list snyk data`
);
}
const jsonResponse = await response.json();
return jsonResponse.data as ProjectsData[];
} else {
throw new Error(`Error loading projects by Project IDs.`);
}
const jsonResponse = await response.json();
return jsonResponse.data as ProjectsData[];
}

private async getTargetId(
Expand Down
Loading

0 comments on commit 64d9c50

Please sign in to comment.