Skip to content

Commit

Permalink
Add first working draft of the chart extension
Browse files Browse the repository at this point in the history
  • Loading branch information
rajbos committed Sep 17, 2023
1 parent 6451b7f commit a88c33b
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 24 deletions.
26 changes: 18 additions & 8 deletions chart/chart.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,20 @@
$title.text(`Configure the widget to get Advanced Security alerts trend information`);
}

// init empty object first
let alertTrendLines = {secretAlertTrend: [], dependencyAlertTrend: [], codeAlertsTrend: []};
try {
// get the trend data for alerts first
const secretAlertTrend = getAlertsTrend(organization, projectName, repoId)
consoleLog('alertTrend: ' + JSON.stringify(secretAlertTrend));
alertTrendLines = await getAlertsTrendLines(organization, projectName, repoId)
consoleLog('Dependencies AlertTrend: ' + JSON.stringify(alertTrendLines.dependencyAlertsTrend));
consoleLog('Code scanning AlertTrend: ' + JSON.stringify(alertTrendLines.codeAlertsTrend));
consoleLog('Secrets AlertTrend: ' + JSON.stringify(alertTrendLines.secretAlertsTrend));
}
catch (err) {
consoleLog(`Error loading the alerts trend: ${err}`);
}

const datePoints = getDatePoints();
var chartOptions = {
"hostOptions": {
"height": "290",
Expand All @@ -86,18 +92,22 @@
"series":
[
{
"name": "Design",
"data": [1,3,4,3,6,1,9,0,8,11]
"name": "Dependencies",
"data": alertTrendLines.dependencyAlertsTrend
},
{
"name": "On Deck",
"data": [2,4,5,6,7,8,9,10,11,12]
"name": "Code scanning",
"data": alertTrendLines.codeAlertsTrend
},
{
"name": "secrets",
"data": secretAlertTrend
"name": "Secrets",
"data": alertTrendLines.secretAlertsTrend
}
],
"xAxis": {
"labelValues": datePoints,
"labelFormatMode": "dateTime", // format is 2023-09-17
},
"specializedOptions": {
"includeMarkers": "true"
}
Expand Down
Binary file added img/example_chart_2x2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
69 changes: 55 additions & 14 deletions library.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ function authenticatedGet(url) {
.then(x => x.json());
}

async function getAlerts (organization, projectName, repoId) {
async function getAlerts(organization, projectName, repoId) {
consoleLog('getAlerts');

try{
// todo: add pagination
// no pagination option, so just get the first 5000 alerts
url = `https://advsec.dev.azure.com/${organization}/${projectName}/_apis/AdvancedSecurity/repositories/${repoId}/alerts?top=5000&criteria.onlyDefaultBranchAlerts=truen&criteria.states=1&api-version=7.2-preview.1`;
consoleLog(`Calling url: [${url}]`);
const alertResult = await authenticatedGet(url);
Expand All @@ -53,31 +53,56 @@ async function getAlerts (organization, projectName, repoId) {
}
}


async function getAlertsTrend (organization, projectName, repoId) {
async function getAlertsTrendLines(organization, projectName, repoId) {
consoleLog(`getAlertsTrend for organization [${organization}], project [${projectName}], repo [${repoId}]`);

try{
// todo: add pagination
try {
url = `https://advsec.dev.azure.com/${organization}/${projectName}/_apis/AdvancedSecurity/repositories/${repoId}/alerts?top=5000&criteria.onlyDefaultBranchAlerts=truen&api-version=7.2-preview.1`;
consoleLog(`Calling url: [${url}]`);
const alertResult = await authenticatedGet(url);
//consoleLog('alertResult: ' + JSON.stringify(alertResult));
consoleLog('alertResult count: ' + alertResult.count);

// load the secret alerts and create a trend line over the last 3 weeks
// load the Secret alerts and create a trend line over the last 3 weeks
const secretAlerts = alertResult.value.filter(alert => alert.alertType === "secret");
const secretAlertsTrend = getAlertsTrendLine(secretAlerts);
const secretAlertsTrend = getAlertsTrendLine(secretAlerts, 'secret');
console.log('');
// load the Dependency alerts and create a trend line over the last 3 weeks
const dependencyAlerts = alertResult.value.filter(alert => alert.alertType === "dependency");
const dependencyAlertsTrend = getAlertsTrendLine(dependencyAlerts, 'dependency');console.log('');
console.log('');
// load the Code alerts and create a trend line over the last 3 weeks
const codeAlerts = alertResult.value.filter(alert => alert.alertType === "code");
const codeAlertsTrend = getAlertsTrendLine(codeAlerts, 'code');

return secretAlertsTrend;
return {
secretAlertsTrend: secretAlertsTrend,
dependencyAlertsTrend: dependencyAlertsTrend,
codeAlertsTrend: codeAlertsTrend
};
}
catch (err) {
consoleLog('error in calling the advec api: ' + err);
}
}

function getAlertsTrendLine(alerts) {
consoleLog('getAlertsTrendLine');
function checkAlertActiveOnDate(alert, dateStr) {
// check if the alert.firstSeenDate is within the date range
// and if fixedDate is not set or is after the date range
const seenClosed = (alert.firstSeenDate.split('T')[0] <= dateStr && (!alert.fixedDate || alert.fixedDate.split('T')[0] > dateStr));
if (seenClosed) {
// check the dismissal.requestedOn date as well
if (alert.dismissal && alert.dismissal.requestedOn) {
const dismissed = (alert.dismissal.requestedOn.split('T')[0] <= dateStr);
return !dismissed;
}
}

return seenClosed;
}

function getAlertsTrendLine(alerts, type) {
consoleLog(`getAlertsTrendLine for type ${type}`);

const trendLine = [];
const trendLineSimple = [];
Expand All @@ -88,7 +113,9 @@ function getAlertsTrendLine(alerts) {
for (let d = threeWeeksAgo; d <= today; d.setDate(d.getDate() + 1)) {
const date = new Date(d);
const dateStr = date.toISOString().split('T')[0];
const alertsOnDate = alerts.filter(alert => alert.createdDate.split('T')[0] === dateStr);

const alertsOnDate = alerts.filter(alert => checkAlertActiveOnDate(alert, dateStr));
console.log(`On [${dateStr}] there were [${alertsOnDate.length}] active ${type} alerts`);
trendLine.push({
date: dateStr,
count: alertsOnDate.length
Expand All @@ -97,7 +124,21 @@ function getAlertsTrendLine(alerts) {
trendLineSimple.push(alertsOnDate.length);
}

consoleLog('trendLine: ' + JSON.stringify(trendLine));
return trendLine;
consoleLog('trendLine: ' + JSON.stringify(trendLineSimple));
return trendLineSimple;
}

function getDatePoints() {
const trendDates = [];
const today = new Date();
const threeWeeksAgo = new Date();
threeWeeksAgo.setDate(today.getDate() - 21);

for (let d = threeWeeksAgo; d <= today; d.setDate(d.getDate() + 1)) {
const date = new Date(d);
const dateStr = date.toISOString().split('T')[0];
trendDates.push(dateStr);
}

return trendDates;
}
3 changes: 3 additions & 0 deletions overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ Install from the marketplace: https://marketplace.visualstudio.com/items?itemNam
### Split it into three separate widgets (1 by 1) with just the single value you scan for:
![Screenshot of the widget in 1 by 1 showing the repository name and the alert count for dependencies, secrets, and code scanning](/img/example_1x1.png)

### Show a trend line (2 by 2) of all alerts in the last 3 weeks:
![Screenshot of the chart widget in 2 by 2 showing the repository name and the alert count for dependencies, secrets, and code scanning](/img/example_chart_2x2.png)

## GitHub repo
Please report issues, feature request, and feedback here: https://github.com/rajbos/GHAzDo-widget.

Expand Down
2 changes: 1 addition & 1 deletion vss-extension-dev.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifestVersion": 1,
"id": "GHAzDoWidget-DEV",
"version": "0.0.1.49",
"version": "0.0.1.66",
"public": false,
"name": "Advanced Security dashboard Widgets [DEV]",
"description": "[DEV] GitHub Advanced Security for Azure DevOps dashboard widgets",
Expand Down
38 changes: 37 additions & 1 deletion vss-extension.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifestVersion": 1,
"id": "GHAzDoWidget",
"version": "0.0.1.4",
"version": "0.0.1.5",
"public": true,
"name": "Advanced Security dashboard Widgets",
"description": "GitHub Advanced Security for Azure DevOps dashboard widgets",
Expand Down Expand Up @@ -104,6 +104,39 @@
"description": "Configures GHAzDoWidget",
"uri": "widget_1x1/configuration_1x1.html"
}
},
{
"id": "GHAzDoWidget.Chart",
"type": "ms.vss-dashboards-web.widget",
"targets": [
"ms.vss-dashboards-web.widget-catalog",
"RobBos.GHAzDoWidget-DEV.GHAzDoWidget.Chart.Configuration"
],
"properties": {
"name": "GHAzDoWidget - Chart",
"description": "A trend chart widget for Advanced Security alerts.",
"catalogIconUrl": "img/publogo.png",
"uri": "/chart/chart.html",
"supportedSizes": [
{
"rowSpan": 2,
"columnSpan": 2
}
],
"supportedScopes": [
"project_team"
]
}
},
{
"id": "GHAzDoWidget.Chart.Configuration",
"type": "ms.vss-dashboards-web.widget-configuration",
"targets": [ "ms.vss-dashboards-web.widget-configuration" ],
"properties": {
"name": "GHAzDoWidget Chart Configuration",
"description": "Configures GHAzDoWidget.Chart",
"uri": "chart/configuration_2x2.html"
}
}
],
"files": [
Expand All @@ -113,6 +146,9 @@
{
"path": "widget_2x1", "addressable": true
},
{
"path": "chart", "addressable": true
},
{
"path": "library.js", "addressable": true
},
Expand Down

0 comments on commit a88c33b

Please sign in to comment.