Skip to content

Commit 106d599

Browse files
authored
Alert status trend (#42)
* start of closed alerts chart * fix hub (#41) * reset the hub locations * adding back overwritten changes * Rerelease with correct fixes * Adding missing things * Touch ups
1 parent 430b572 commit 106d599

File tree

6 files changed

+201
-75
lines changed

6 files changed

+201
-75
lines changed

vss-extension-dev.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"manifestVersion": 1,
33
"id": "GHAzDoWidget-DEV",
4-
"version": "0.2.404",
4+
"version": "0.2.415",
55
"public": false,
66
"name": "Advanced Security dashboard Widgets [DEV]",
77
"description": "[DEV] GitHub Advanced Security for Azure DevOps dashboard widgets",

vss-extension.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"manifestVersion": 1,
33
"id": "GHAzDoWidget",
4-
"version": "0.0.1.17",
4+
"version": "0.0.1.19",
55
"public": true,
66
"name": "Advanced Security dashboard Widgets",
77
"description": "GitHub Advanced Security for Azure DevOps dashboard widgets",

widgets/library.js

+73-20
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ async function storeAlerts(repoId, alertResult) {
187187
}
188188
}
189189

190-
async function getAlertsTrendLines(organization, projectName, repoId, daysToGoBack, summaryBucket) {
190+
async function getAlertsTrendLines(organization, projectName, repoId, daysToGoBack, summaryBucket, alertType, overviewType = false, showClosed = false) {
191191
consoleLog(`getAlertsTrend for organization [${organization}], project [${projectName}], repo [${repoId}]`)
192192
try {
193193
alertResult = null
@@ -214,23 +214,40 @@ async function getAlertsTrendLines(organization, projectName, repoId, daysToGoBa
214214
codeAlertsTrend: []
215215
}
216216
}
217+
if (overviewType === false) {
218+
consoleLog('Loading all alerts trend lines')
219+
// load the Secret alerts and create a trend line over the last 3 weeks
220+
const secretAlerts = alertResult.value.filter(alert => alert.alertType === AlertType.SECRET.name)
221+
const secretAlertsTrend = getAlertsTrendLine(secretAlerts, AlertType.SECRET.name, daysToGoBack, summaryBucket)
222+
consoleLog('')
223+
// load the Dependency alerts and create a trend line over the last 3 weeks
224+
const dependencyAlerts = alertResult.value.filter(alert => alert.alertType === AlertType.DEPENDENCY.name)
225+
const dependencyAlertsTrend = getAlertsTrendLine(dependencyAlerts, AlertType.DEPENDENCY.name, daysToGoBack, summaryBucket)
226+
consoleLog('')
227+
// load the Code alerts and create a trend line over the last 3 weeks
228+
const codeAlerts = alertResult.value.filter(alert => alert.alertType === AlertType.CODE.name)
229+
const codeAlertsTrend = getAlertsTrendLine(codeAlerts, AlertType.CODE.name, daysToGoBack, summaryBucket)
217230

218-
// load the Secret alerts and create a trend line over the last 3 weeks
219-
const secretAlerts = alertResult.value.filter(alert => alert.alertType === AlertType.SECRET.name)
220-
const secretAlertsTrend = getAlertsTrendLine(secretAlerts, AlertType.SECRET.name, daysToGoBack, summaryBucket)
221-
consoleLog('')
222-
// load the Dependency alerts and create a trend line over the last 3 weeks
223-
const dependencyAlerts = alertResult.value.filter(alert => alert.alertType === AlertType.DEPENDENCY.name)
224-
const dependencyAlertsTrend = getAlertsTrendLine(dependencyAlerts, AlertType.DEPENDENCY.name, daysToGoBack, summaryBucket)
225-
consoleLog('')
226-
// load the Code alerts and create a trend line over the last 3 weeks
227-
const codeAlerts = alertResult.value.filter(alert => alert.alertType === AlertType.CODE.name)
228-
const codeAlertsTrend = getAlertsTrendLine(codeAlerts, AlertType.CODE.name, daysToGoBack, summaryBucket)
231+
return {
232+
secretAlertsTrend: secretAlertsTrend,
233+
dependencyAlertsTrend: dependencyAlertsTrend,
234+
codeAlertsTrend: codeAlertsTrend
235+
}
236+
}
237+
else {
238+
consoleLog(`Loading alerts trend lines for alert type: [$alertType.name}]`)
239+
// filter the alerts based on the alertType
240+
const alerts = alertResult.value.filter(alert => alert.alertType === alertType.name)
241+
// create a trend line over the last 3 weeks for number of open alerts
242+
const alertsOpenTrend = getAlertsTrendLine(alerts, alertType.name, daysToGoBack, summaryBucket, 'open')
243+
const alertsDismissedTrend = getAlertsTrendLine(alerts, alertType.name, daysToGoBack, summaryBucket, 'dismissed')
244+
const alertFixedTrend = getAlertsTrendLine(alerts, alertType.name, daysToGoBack, summaryBucket, 'fixed')
229245

230-
return {
231-
secretAlertsTrend: secretAlertsTrend,
232-
dependencyAlertsTrend: dependencyAlertsTrend,
233-
codeAlertsTrend: codeAlertsTrend
246+
return {
247+
alertsOpenTrend: alertsOpenTrend,
248+
alertsDismissedTrend: alertsDismissedTrend,
249+
alertFixedTrend: alertFixedTrend
250+
}
234251
}
235252
}
236253
catch (err) {
@@ -258,7 +275,29 @@ function checkAlertActiveOnDate(alert, dateStr) {
258275
return seenClosed;
259276
}
260277

261-
function getAlertsTrendLine(alerts, type, daysToGoBack = 21, summaryBucket = 1) {
278+
function checkAlertDismissedOnDate(alert, dateStr) {
279+
// check if the alert.firstSeenDate is within the date range
280+
// and if fixedDate is not set or is after the date range
281+
const seenClosed = (alert.firstSeenDate.split('T')[0] <= dateStr && (!alert.fixedDate || alert.fixedDate.split('T')[0] > dateStr));
282+
if (seenClosed) {
283+
// check the dismissal.requestedOn date as well
284+
if (alert.dismissal && alert.dismissal.requestedOn) {
285+
const dismissed = (alert.dismissal.requestedOn.split('T')[0] <= dateStr);
286+
return dismissed;
287+
}
288+
}
289+
290+
return false;
291+
}
292+
293+
function checkAlertFixedOnDate(alert, dateStr) {
294+
// check if the alert.firstSeenDate is within the date range
295+
// and if fixedDate is not set or is after the date range
296+
const seenClosed = (alert.firstSeenDate.split('T')[0] <= dateStr && (alert.fixedDate && alert.fixedDate.split('T')[0] < dateStr));
297+
return seenClosed;
298+
}
299+
300+
function getAlertsTrendLine(alerts, type, daysToGoBack = 21, summaryBucket = 1, filter = 'open') {
262301
consoleLog(`getAlertsTrendLine for type ${type}`);
263302

264303
const trendLine = [];
@@ -270,9 +309,23 @@ function getAlertsTrendLine(alerts, type, daysToGoBack = 21, summaryBucket = 1)
270309
for (let d = startDate; d <= today; d.setDate(d.getDate() + summaryBucket)) {
271310
const date = new Date(d);
272311
const dateStr = date.toISOString().split('T')[0];
273-
274-
const alertsOnDate = alerts.filter(alert => checkAlertActiveOnDate(alert, dateStr));
275-
console.log(`On [${dateStr}] there were [${alertsOnDate.length}] active ${type} alerts`);
312+
let alertsOnDate = []
313+
switch (filter) {
314+
case 'open':
315+
alertsOnDate = alerts.filter(alert => checkAlertActiveOnDate(alert, dateStr));
316+
break;
317+
case 'dismissed':
318+
alertsOnDate = alerts.filter(alert => checkAlertDismissedOnDate(alert, dateStr));
319+
break;
320+
case 'fixed':
321+
alertsOnDate = alerts.filter(alert => checkAlertFixedOnDate(alert, dateStr));
322+
break;
323+
default:
324+
// get all active alerts on this date
325+
alertsOnDate = alerts.filter(alert => checkAlertActiveOnDate(alert, dateStr));
326+
break;
327+
}
328+
console.log(`On [${dateStr}] there were [${alertsOnDate.length}] [${filter}] [${type}] alerts`);
276329
trendLine.push({
277330
date: dateStr,
278331
count: alertsOnDate.length

widgets/widgets/chart/chart.html

+46-36
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
VSS.init({
1212
explicitNotifyLoaded: true,
1313
usePlatformStyles: true
14-
});
14+
})
1515

1616
VSS.require([
1717
"TFS/Dashboards/WidgetHelpers",
@@ -26,85 +26,95 @@
2626
return {
2727
load: async function(widgetSettings) {
2828
return Services.ChartsService.getService().then(async function(chartService){
29-
consoleLog("Starting to create chart");
30-
var $container = $('#Chart-Container');
31-
var $title = $('h2.ghazdo-title');
29+
consoleLog("Starting to create chart")
30+
var $container = $('#Chart-Container')
31+
var $title = $('h2.ghazdo-title')
3232

33-
const webContext = VSS.getWebContext();
34-
const project = webContext.project;
35-
const organization = webContext.account.name;
36-
const projectId = project.id;
33+
const webContext = VSS.getWebContext()
34+
const project = webContext.project
35+
const organization = webContext.account.name
36+
const projectId = project.id
3737
// convert project.name to url encoding
38-
const projectName = project.name.replace(/ /g, "%20").replace(/&/g, "%26");
38+
const projectName = project.name.replace(/ /g, "%20").replace(/&/g, "%26")
3939

40-
consoleLog('project id: ' + projectId);
41-
consoleLog('project name: ' + projectName);
42-
consoleLog('organization name: ' + organization);
40+
consoleLog('project id: ' + projectId)
41+
consoleLog('project name: ' + projectName)
42+
consoleLog('organization name: ' + organization)
4343

44-
consoleLog(`WidgetSettings inside loadChartWidget_2x2: ${JSON.stringify(widgetSettings)}`);
44+
consoleLog(`WidgetSettings inside loadChartWidget_2x2: ${JSON.stringify(widgetSettings)}`)
4545

4646
// data contains a stringified json object, so we need to make a json object from it
47-
const data = JSON.parse(widgetSettings.customSettings.data);
47+
const data = JSON.parse(widgetSettings.customSettings.data)
4848

4949
let repoName
5050
let repoId
5151
// init empty object first
52-
let alertTrendLines = {secretAlertTrend: [], dependencyAlertTrend: [], codeAlertsTrend: []};
53-
let chartType = 1;
54-
let alertTypeConfig = 1;
52+
let alertTrendLines = {secretAlertTrend: [], dependencyAlertTrend: [], codeAlertsTrend: []}
53+
let chartType = 1
54+
let alertTypeConfig = 1
5555
if (data && data.chartType && data.chartType !== "") {
56-
chartType = data.chartType;
57-
consoleLog('loaded chartType from widgetSettings: ' + chartType);
56+
chartType = data.chartType
57+
consoleLog('loaded chartType from widgetSettings: ' + chartType)
5858
}
5959
else {
60-
consoleLog('chartType is not set, using default value: ' + chartType);
60+
consoleLog('chartType is not set, using default value: ' + chartType)
6161
}
6262

6363
if (data && data.alertType) {
64-
alertTypeConfig = data.alertType;
65-
consoleLog('loaded alertType from widgetSettings: ' + alertTypeConfig);
64+
alertTypeConfig = data.alertType
65+
consoleLog('loaded alertType from widgetSettings: ' + alertTypeConfig)
6666
}
6767

6868
if (data && data.repo && data.repo !== "") {
69-
repoName = data.repo;
70-
repoId = data.repoId;
69+
repoName = data.repo
70+
repoId = data.repoId
7171

7272
$container.text(`${data.repo}`)
7373

7474
switch (chartType) {
75+
case "3":
76+
try {
77+
const alertType = GetAlertTypeFromValue(alertTypeConfig)
78+
$title.text(`${alertType.display} Alerts status trend`)
79+
renderDurationChart({organization, projectName, repoId, $container, chartService, alertType, widgetSize: widgetSettings.size})
80+
}
81+
catch (err) {
82+
consoleLog(`Error loading the alerts pie: ${err}`)
83+
}
84+
break
7585
case "2":
7686
try {
7787
const alertType = GetAlertTypeFromValue(alertTypeConfig);
7888
$title.text(`${alertType.display} Alerts by Severity`)
7989
renderPieChart(organization, projectName, repoId, $container, chartService, alertType, widgetSettings.size);
8090
}
8191
catch (err) {
82-
consoleLog(`Error loading the alerts pie: ${err}`);
92+
consoleLog(`Error loading the alerts pie: ${err}`)
8393
}
84-
break;
94+
break
8595
default:
8696
try {
87-
$title.text(`Advanced Security Alerts Trend`)
88-
renderTrendLine(organization, projectName, repoId, $container, chartService, widgetSettings.size);
97+
$title.text(`Advanced Security alerts trend`)
98+
renderTrendLine(organization, projectName, repoId, $container, chartService, widgetSettings.size)
8999
}
90100
catch (err) {
91-
consoleLog(`Error loading the alerts trend: ${err}`);
101+
consoleLog(`Error loading the alerts trend: ${err}`)
92102
}
93-
break;
103+
break
94104
}
95105
}
96106
else {
97-
consoleLog('configuration is needed first, opening with empty values');
107+
consoleLog('configuration is needed first, opening with empty values')
98108
// set the tile to indicate config is needed
99-
$title.text(`Configure the widget to get Advanced Security alerts trend information`);
109+
$title.text(`Configure the widget to get Advanced Security alerts trend information`)
100110
}
101111

102-
return WidgetHelpers.WidgetStatusHelper.Success();
103-
});
112+
return WidgetHelpers.WidgetStatusHelper.Success()
113+
})
104114
}
105115
}
106-
});
107-
VSS.notifyLoadSucceeded();
116+
})
117+
VSS.notifyLoadSucceeded()
108118
});
109119
</script>
110120

0 commit comments

Comments
 (0)