-
Notifications
You must be signed in to change notification settings - Fork 29
Expand file tree
/
Copy pathGitHubDependencies.ts
More file actions
119 lines (96 loc) · 3.29 KB
/
Copy pathGitHubDependencies.ts
File metadata and controls
119 lines (96 loc) · 3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import { Octokit } from '@octokit/rest';
import { RequestHeaders, RequestParameters } from '@octokit/types';
import {
QUERY_SECURITY_VULNERABILITIES,
QUERY_DEPENDENCY_GRAPH,
VulnerabilityAlert,
DependencySetData, RepositoryVulnerabilityAlerts, DependencyGraphResult
} from './DependencyTypes';
import Vulnerability from './Vulnerability';
import DependencySet from './DependencySet';
type Repo = {
owner: string,
repo: string,
}
export default class GitHubDependencies {
private readonly octokit: Octokit;
constructor(octokit) {
this.octokit = octokit;
}
async getAllVulnerabilities(repo: Repo): Promise<Vulnerability[]> {
function extractVulnerabilityAlerts(data: RepositoryVulnerabilityAlerts): VulnerabilityAlert[] {
return data.repository.vulnerabilityAlerts.nodes;
}
const data: VulnerabilityAlert[] = await this.getPaginatedQuery<RepositoryVulnerabilityAlerts, VulnerabilityAlert>(
QUERY_SECURITY_VULNERABILITIES,
{organizationName: repo.owner, repositoryName: repo.repo},
'repository.vulnerabilityAlerts.pageInfo',
extractVulnerabilityAlerts
);
return data.map(val => {
return new Vulnerability(val);
});
}
async getAllDependencies(repo: Repo): Promise<DependencySet[]> {
function extractDependencySetData(data: DependencyGraphResult): DependencySetData[] {
return data.repository.dependencyGraphManifests.edges;
}
const data = await this.getPaginatedQuery(
QUERY_DEPENDENCY_GRAPH,
{organizationName: repo.owner, repositoryName: repo.repo},
'repository.dependencyGraphManifests.pageInfo',
extractDependencySetData,
{accept: 'application/vnd.github.hawkgirl-preview+json'}
);
return data.map(node => {
return new DependencySet(node);
});
}
async getPaginatedQuery<T, Y>(query: string,
parameters: Object,
pageInfoPath: string,
extractResultsFn: (val: T) => Y[],
headers?): Promise<Y[]> {
const octokit = this.octokit
, results: Y[] = []
, queryParameters = Object.assign({cursor: null}, parameters)
;
let hasNextPage = false;
do {
const graphqlParameters = buildGraphQLParameters(query, queryParameters, headers)
, queryResult = await octokit.graphql(graphqlParameters)
;
// @ts-ignore
const extracted: Y = extractResultsFn(queryResult);
// @ts-ignore
results.push(...extracted);
const pageInfo = getObject(queryResult, ...pageInfoPath.split('.'));
hasNextPage = pageInfo ? pageInfo.hasNextPage : false;
if (hasNextPage) {
queryParameters.cursor = pageInfo.endCursor;
}
} while (hasNextPage);
return results;
}
}
function buildGraphQLParameters(query: string, parameters?: Object, headers?: RequestHeaders): RequestParameters {
const result: RequestParameters = {
...(parameters || {}),
query: query,
};
if (headers) {
result.headers = headers;
}
return result;
}
function getObject(target, ...path) {
if (target !== null && target !== undefined) {
const value = target[path[0]];
if (path.length > 1) {
return getObject(value, ...path.slice(1));
} else {
return value;
}
}
return null;
}