Skip to content

Commit

Permalink
Adding new widgets to the PR and Build windows
Browse files Browse the repository at this point in the history
  • Loading branch information
rajbos committed Oct 17, 2023
1 parent 3d7a470 commit 8541c45
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 39 deletions.
111 changes: 78 additions & 33 deletions dependencyReviewTask/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,48 @@ function getSystemAccessToken() : string {
}
}

interface IValue {
alertId: number;
title: string;
}
interface IResult {
count: number;
value: IValue[];
}

interface IResponse {
result: IResult;
}

async function getAlerts(connection: WebApi, orgSlug: string, project: string, repository: string, branchName: string) {
const branchUrl = `https://advsec.dev.azure.com/${orgSlug}/${project}/_apis/AdvancedSecurity/repositories/${repository}/alerts?criteria.alertType=1&criteria.ref=${branchName}&criteria.onlyDefaultBranchAlerts=true&useDatabaseProvider=true`;
let branchResponse: IResponse

try {
branchResponse = await connection.rest.get<IResult>(branchUrl);
}
catch (err: unknown) {
if (err instanceof Error) {
if (err.message.includes('Branch does not exist')) {
console.log(`Branch [${branchName}] does not exist in GHAzDo yet. Make sure to run the Dependency Scan task first on this branch (easiest to do in the same pipeline).`);
}
else {
console.log(`An error occurred: ${err.message}`);
}
}
}
return branchResponse
}

async function run() {
try {
// test to see if this build was triggered with a PR context
const buildReason = tl.getVariable('Build.Reason');
if (buildReason != 'PullRequest') {
tl.setResult(tl.TaskResult.Skipped, `This extension only works when triggered by a Pull Request and not by a [${buildReason}]`);
return
}

// todo: convert to some actual setting
const inputString: string | undefined = tl.getInput('samplestring', true);
if (inputString == 'bad') {
Expand All @@ -34,47 +74,52 @@ async function run() {
const orgSlug = organization.split('/')[3];
const project = tl.getVariable('System.TeamProject');
const repository = tl.getVariable('Build.Repository.ID');
const sourceBranchName = tl.getVariable('Build.SourceBranchName');
const targetBranchName = tl.getVariable('Build.TargetBranchName');
const url = `https://advsec.dev.azure.com/${orgSlug}/${project}/_apis/AdvancedSecurity/repositories/${repository}/alerts?criteria.alertType=1&criteria.ref=${sourceBranchName}&criteria.onlyDefaultBranchAlerts=true&useDatabaseProvider=true`;
const sourceBranch = tl.getVariable('System.PullRequest.SourceBranch');
const sourceBranchName = sourceBranch?.split('/')[2];
const targetBranchName = tl.getVariable('System.PullRequest.targetBranchName');

tl.debug(`Retrieving alerts with token: [${token}], organization: [${organization}], orgSlug: [${orgSlug}], project: [${project}], sourceBranchName: [${sourceBranchName}], targetBranchName: [${targetBranchName}]`);
tl.debug(`Full url: ${url}`);
console.log(`Retrieving alerts with token: [${token}], organization: [${organization}], orgSlug: [${orgSlug}], project: [${project}], sourceBranchName: [${sourceBranchName}], targetBranchName: [${targetBranchName}]`);

try {
interface IResult {
count: number;
}
const sourceBranchResponse = await getAlerts(connection, orgSlug, project, repository, sourceBranchName);
const targetBranchResponse = await getAlerts(connection, orgSlug, project, repository, targetBranchName);

interface IResponse {
result: IResult;
}
tl.debug(`source response: ${JSON.stringify(sourceBranchResponse)}`);
tl.debug(`target response: ${JSON.stringify(targetBranchResponse)}`);

if (sourceBranchResponse.result.count == 0) {
console.log('No alerts found for this branch');

const response: IResponse = await connection.rest.get<IResult>(url);
tl.debug(`response: ${JSON.stringify(response)}`);
tl.setResult(tl.TaskResult.Succeeded, `Found no alerts for the source branch`);
return;
}
else {
// check by result.alertId if there is a new alert or not (so alert not in targetBranch)

if (response.result.count == 0) {
console.log('No alerts found for this branch');
// first get the only the alertid's from the source branch
const sourceAlertIds = sourceBranchResponse.result.value.map((alert) => {return alert.alertId;});
// do the same for the target branch
const targetAlertIds = targetBranchResponse.result.value.map((alert) => {return alert.alertId;});
// now find the delta
const newAlertIds = sourceAlertIds.filter((alertId) => {
return !targetAlertIds.includes(alertId);
});

tl.setResult(tl.TaskResult.Succeeded, `Found no alerts for the source branch`);
return;
if (newAlertIds.length > 0) {

console.log(`Found [${sourceBranchResponse.result.count}] alerts for the source branch [${sourceBranchName}] of which [${newAlertIds.length}] are new:`);
for (const alertId of newAlertIds) {
// get the alert details:
const alertUrl = `https://dev.azure.com/${orgSlug}/${project}/_git/${repository}/alerts/${alertId}?branch=refs/heads/${sourceBranchName}`;
const alertTitle = sourceBranchResponse.result.value.find((alert) => {return alert.alertId == alertId;})?.title;
// and show them:
console.log(`- ${alertId}: ${alertTitle}, url: ${alertUrl}`);
}

tl.setResult(tl.TaskResult.Failed, `Found [${sourceBranchResponse.result.count}] alerts for the source branch [${sourceBranchName}] of which [${newAlertIds.length}] are new`);
}
else {
// todo: support configuration for checking with the target branch for a delta
console.log(`Found [${response.result.count}] alerts for the source branch [${sourceBranchName}]`);
tl.setResult(tl.TaskResult.Failed, `Found [${response.result.count}] alerts for the source branch [${sourceBranchName}]`);
}
}
catch (err: unknown) {
if (err instanceof Error) {
if (err.message.includes('Branch does not exist')) {
console.log(`Branch [${sourceBranchName}] does not exist in GHAzDo yet. Make sure to run the Dependency Scan task first on this branch (easies to do in the same pipeline).`);
}
else {
tl.setResult(tl.TaskResult.Failed, JSON.stringify(err.message));
}
} else {
tl.setResult(tl.TaskResult.Failed, 'An unknown error occurred:' + JSON.stringify(err));
console.log(`Found no new alerts for the source branch [${sourceBranchName}]`);
tl.setResult(tl.TaskResult.Succeeded, `Found no new alerts for the source branch [${sourceBranchName}], only [${targetBranchResponse.result.count}] existing ones`);
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions dependencyReviewTask/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
"id": "10c1d88a-9d0f-4288-8e37-58762caa0b8b",
"name": "Advanced-Dependency-Review",
"friendlyName": "Advanced Security Dependency Review",
"description": "Scan the branch in your PR for known Dependency issues",
"helpMarkDown": "Checks the branch in your PR for known Dependency issues",
"description": "Scan the source branch in your PR for known Dependency issues",
"helpMarkDown": "Checks the source branch in your PR for known Dependency issues",
"category": "Utility",
"author": "RobBos",
"version": {
"Major": 0,
"Minor": 1,
"Patch": 18
"Patch": 23
},
"instanceNameFormat": "Echo $(samplestring)",
"inputs": [
Expand All @@ -28,4 +28,4 @@
"target": "index.js"
}
}
}
}
33 changes: 32 additions & 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.2.119",
"version": "0.2.133",
"public": false,
"name": "Advanced Security dashboard Widgets [DEV]",
"description": "[DEV] GitHub Advanced Security for Azure DevOps dashboard widgets",
Expand Down Expand Up @@ -46,6 +46,31 @@
"url": "https://github.com/rajbos/GHAzDo-widget/issues"
},
"contributions": [
{
"id": "GHAzDoWidget.PR-tab",
"type": "ms.vss-web.tab",
"targets": [
"ms.vss-code-web.pr-tabs"
],
"properties": {
"name": "GHAzDo Alerts",
"title": "GHAzDo Alerts",
"uri": "widgets/pr-tab/index.html",
"action": "GHAzDo Alerts"
}
},
{
"id": "GHAzDoWidget.build-info-tab",
"type": "ms.vss-build-web.build-results-tab",
"description": "Advanced Security Alerts",
"targets": [
"ms.vss-build-web.build-results-view"
],
"properties": {
"name": "Advanced Security Alerts",
"uri": "widgets/build-info/index.html"
}
},
{
"id": "GHAzDoWidget",
"type": "ms.vss-dashboards-web.widget",
Expand Down Expand Up @@ -205,6 +230,12 @@
{
"path": "widgets/widgets", "addressable": true
},
{
"path": "widgets/build-info", "addressable": true
},
{
"path": "widgets/pr-tab", "addressable": true
},
{
"path": "widgets/library.js", "addressable": true
},
Expand Down
45 changes: 45 additions & 0 deletions widgets/build-info/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html>
<head>
<script src="../../lib/VSS.SDK.min.js"></script>
<link rel="stylesheet" href="../styles.css" />

<script type="text/javascript">
VSS.init({
explicitNotifyLoaded: true,
usePlatformStyles: true
});

VSS.require(
["VSS/Service", "TFS/Dashboards/WidgetHelpers", "VSS/Context", "TFS/VersionControl/GitRestClient", "TFS/Core/RestClient"],
async function (Service, WidgetHelpers, context, GitWebApi, RestClient)
{
WidgetHelpers.IncludeWidgetStyles();
VSS.register("GHAzDoWidget.TestingWidget", async function () {
const webContext = VSS.getWebContext();
const project = webContext.project;
const organization = webContext.account.name;
const projectId = project.id;
// convert project.name to url encoding
const projectName = project.name.replace(/ /g, "%20").replace(/&/g, "%26");

consoleLog('project id: ' + projectId);
consoleLog('project name: ' + projectName);
consoleLog('organization name: ' + organization);

return {
load: async function (widgetSettings) {
return WidgetHelpers.WidgetStatusHelper.Success();
}
}
});
VSS.notifyLoadSucceeded();
}
);
</script>

</head>
<body>
Hello build info with GHAzDo info!
</body>
</html>
45 changes: 45 additions & 0 deletions widgets/pr-tab/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html>
<head>
<script src="../../lib/VSS.SDK.min.js"></script>
<link rel="stylesheet" href="../styles.css" />

<script type="text/javascript">
VSS.init({
explicitNotifyLoaded: true,
usePlatformStyles: true
});

VSS.require(
["VSS/Service", "TFS/Dashboards/WidgetHelpers", "VSS/Context", "TFS/VersionControl/GitRestClient", "TFS/Core/RestClient"],
async function (Service, WidgetHelpers, context, GitWebApi, RestClient)
{
WidgetHelpers.IncludeWidgetStyles();
VSS.register("GHAzDoWidget.TestingWidget", async function () {
const webContext = VSS.getWebContext();
const project = webContext.project;
const organization = webContext.account.name;
const projectId = project.id;
// convert project.name to url encoding
const projectName = project.name.replace(/ /g, "%20").replace(/&/g, "%26");

consoleLog('project id: ' + projectId);
consoleLog('project name: ' + projectName);
consoleLog('organization name: ' + organization);

return {
load: async function (widgetSettings) {
return WidgetHelpers.WidgetStatusHelper.Success();
}
}
});
VSS.notifyLoadSucceeded();
}
);
</script>

</head>
<body>
Hello PR tab with GHAzDo info!
</body>
</html>
15 changes: 14 additions & 1 deletion widgets/widgets/testing_widget/testing.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
$title.text(message);
}

function extraLogs(message) {
var $logs = $('#logs');
$logs.append(message + '</br>');
}

WidgetHelpers.IncludeWidgetStyles();
VSS.register("GHAzDoWidget.TestingWidget", async function () {
const webContext = VSS.getWebContext();
Expand Down Expand Up @@ -64,6 +69,9 @@
}

try {
// log the current time
extraLogs('start the download: ' + (new Date()).toISOString());

const projects = await getProjects(VSS, Service, RestClient);
consoleLog(`Found [${projects?.length}] projects`);
// show the project names:
Expand Down Expand Up @@ -99,6 +107,10 @@

$queryinfocontainer = $('#query-info-container');
$queryinfocontainer.append(`<ul>${nameList}</ul>`);

// log the current time
extraLogs('completed the download: ' + (new Date()).toISOString());

}
catch (err) {
consoleLog('error loading projects: ' + JSON.stringify(err));
Expand All @@ -115,8 +127,9 @@

</head>
<body>
<div class="widget GHAzDo-widget">
<div class="widget GHAzDo-widget" style="overflow-y: scroll;">
<h2 class="ghazdo-title" title="" style="font-size: 15px;text-align: left;">Testing info</h2>
<p id="logs"></p>
<div id="query-info-container" class="column-container" style="font-size: 15px;text-align: left;display: block;">
Projects: </br>
</div>
Expand Down

0 comments on commit 8541c45

Please sign in to comment.