-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
160 lines (126 loc) · 5.58 KB
/
index.js
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
const axios = require('axios')
const core = require('@actions/core');
const fs = require('fs');
crypto = require("crypto");
// Load Configuration
const veracodeWebhook = core.getInput('VERACODE_WEBHOOK');
const id = core.getInput('VERACODE_SECRET_ID');
const key = core.getInput('VERACODE_SECRET_ID_KEY');
const region = core.getInput('REGION');
const pullReport = core.getInput('pull-report');
const preFix = "VERACODE-HMAC-SHA-256";
const verStr = "vcode_request_version_1";
let host = "api.veracode.com";
let urlPrefix = "/dae/api/core-api/webhook";
if(region === "eu") {
host = "api.veracode.eu";
}
let hmac256 = async (data, key) => {
let hash = require('crypto').createHmac('sha256', key).update(data);
// no format = Buffer / byte array
return hash.digest();
}
let getByteArray = (hex) => {
let bytes = [];
for(let i = 0; i < hex.length-1; i+=2){
bytes.push(parseInt(hex.substr(i, 2), 16));
}
// signed 8-bit integer array (byte array)
return Int8Array.from(bytes);
}
let generateHeader = async (url, method) => {
let data = `id=${id}&host=${host}&url=${url}&method=${method}`;
let timestamp = (new Date().getTime()).toString();
let nonce = require('crypto').randomBytes(16).toString('hex');
// calculate signature
let hashedNonce = await hmac256(getByteArray(nonce), getByteArray(key));
let hashedTimestamp = await hmac256(buffer(timestamp), getByteArray(hex(hashedNonce)));
let hashedVerStr = await hmac256(buffer(verStr), getByteArray(hex(hashedTimestamp)));
let signature = hex(await hmac256(buffer(data), getByteArray(hex(hashedVerStr))));
return `${preFix} id=${id},ts=${timestamp},nonce=${nonce},sig=${signature}`;
}
const wait = function (milliseconds) {
return new Promise((resolve) => {
if (typeof milliseconds !== 'number') {
throw new Error('milliseconds not a number');
}
setTimeout(() => resolve("done!"), milliseconds)
});
};
// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#Converting_a_digest_to_a_hex_string
let hex = (buffer) => Array.from(new Uint8Array(buffer)).map(n => n.toString(16).padStart(2, "0")).join("");
let buffer = (string) => new TextEncoder("utf-8").encode(string);
async function run() {
try {
// Setup general variables
const pollTimeout = 60000; // Polling the scan status every 60 seconds
let status = 100; // 100 = Queued
let scanId = undefined;
let url = urlPrefix+"/"+veracodeWebhook;
console.log(`Sending Webhook to URL ${host}${url} for ${veracodeWebhook}`);
// Start the Security Scan
try {
let method = "POST";
let VERACODE_AUTH_HEADER = await generateHeader(url, method);
const response = await axios.post("https://"+`${host}${url}`, "", {headers: {'Authorization': VERACODE_AUTH_HEADER}});
scanId = response.data.data.scanId;
} catch(error) {
errorMsg = error.toString()
core.setFailed(`Could not start Scan for Webhook ${veracodeWebhook}. Reason: ${errorMsg}.`);
return
}
// Check if the scan was correctly started
if (!scanId) {
core.setFailed(`Could not start Scan for Webhook ${veracodeWebhook}.`);
return
}
console.log(`Started Scan for Webhook ${veracodeWebhook}. Scan ID is ${scanId}.`)
// Check if the action should wait for the report and download it
if (pullReport === 'false') {
console.log(`Skipping the download of the scan report as pull-report='${pullReport}'.`);
return
}
// Wait until the scan has finished
while (status <= 101) {
console.log(`Scan Status currently is ${status} (101 = Running)`);
// Only poll every minute
await wait(pollTimeout);
// Refresh status
try {
let method = "GET";
let url = urlPrefix+"/"+`${veracodeWebhook}/scans/${scanId}/status`;
let VERACODE_AUTH_HEADER = await generateHeader(url, method);
const response = await axios.get("https://"+`${host}${url}`, {headers: {'Authorization': VERACODE_AUTH_HEADER}});
status = response.data.data.status.status_code;
} catch(error) {
errorMsg = error.response.data.message
core.setFailed(`Retreiving Scan Status failed for Webhook ${veracodeWebhook}. Reason: ${errorMsg}.`);
return
}
}
console.log(`Scan finished with status ${status}.`)
// Download the JUnit Report
let junitReport = undefined;
try {
let method = "GET";
let url = urlPrefix+"/"+`${veracodeWebhook}/scans/${scanId}/report/junit`;
let VERACODE_AUTH_HEADER = await generateHeader(url, method);
const response = await axios.get("https://"+`${host}${url}`, {headers: {'Authorization': VERACODE_AUTH_HEADER}})
junitReport = response.data;
} catch(error) {
errorMsg = error.response.data.message
core.setFailed(`Downloading Report failed for Webhook ${veracodeWebhook}. Reason: ${errorMsg}.`);
return
}
fs.writeFile('report.xml', junitReport, function(error) {
if (error) {
core.setFailed(`Writing the Report failed for Webhook ${veracodeWebhook}. Reason: ${error}`);
}
});
console.log('Downloaded Report to report.xml');
} catch (error) {
core.setFailed(error.message);
return
}
}
run();