Skip to content

Commit

Permalink
Merge pull request #26 from rapid7/DF-4085
Browse files Browse the repository at this point in the history
DF-4085 - release 1.1.0
  • Loading branch information
trobinson-r7 authored Jul 5, 2021
2 parents c9cbfd9 + 4c9532a commit e827751
Show file tree
Hide file tree
Showing 10 changed files with 351 additions and 39 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ The following block of code contains the required parameters that must be set:

```
// Vars for testing locally
var application = "Application Name";
var scanConfig = "Scan Configuration Name";
var appInput = "Application Name/ID";
var scanConfigInput = "Scan Configuration Name/ID";
var endpoint = "https://us.api.insight.rapid7.com/ias/v1";
var apiKey = "your-api-key";
Expand All @@ -64,6 +64,8 @@ var scanTimeout = 60;
var hasScanGating = false;
var generateFindingsReport = true;
var debugMode = true;
var publishPipelineArtifactsBool = false;
var artifactPerReport = false;
```

With all prerequisites and configurations in place, you can now compile the project and then test:
Expand Down
1 change: 1 addition & 0 deletions help.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ To enable debug logging for:

# Version History

* 1.1.0 - Added option to upload report output for both build and release pipelines, added self-populating Scan Config dropdown list
* 1.0.8 - Added improved error logging for bad requests, all requests are now logged with system.debug set to true
* 1.0.7 - Bug fix for empty Vulnerability Query with Scan Gating checked, bug fix for undefined report path for release pipelines, replaced XMLHttpRequest module with Axios, added us2 and us3 regions
* 1.0.6 - Add basic validation to the Vulnerability Query field and additional logging if the vulnerability request fails
Expand Down
7 changes: 6 additions & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@
"sourceUrl": "https://github.com/rapid7/insightappsec-azure-devops-extension",
"licenseUrl": "https://github.com/rapid7/insightappsec-azure-devops-extension/blob/master/LICENSE.txt"
},
"version": "1.0.8",
"version": "1.1.0",
"versionHistory": [
{
"version": "1.1.0",
"date": "",
"changes": "Added option to upload report output for both build and release pipelines, added self-populating Scan Config dropdown list."
},
{
"version": "1.0.8",
"date": "",
Expand Down
134 changes: 133 additions & 1 deletion tasks/InsightAppSec/helpers/insightAppSecApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ const axios = require('axios').default;
const LOCATION_HEADER = "location";
const CONTENT_TYPE_HEADER = "application/json";
const ACCEPT_HEADER = "application/json";
const USER_AGENT_HEADER = "r7:insightappsec-azure-devops-extension/1.0.8";
const USER_AGENT_HEADER = "r7:insightappsec-azure-devops-extension/1.1.0";
const UUID_REGEX = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/

export default class InsightAppSecApi
{
Expand Down Expand Up @@ -112,6 +113,71 @@ export default class InsightAppSecApi
}.bind(this));
}

public async getAppName(appID)
{
return new Promise(async function (resolve, reject)
{
let response;
let payload = {type: "APP", query: "app.id='" + appID + "'"};
let app;

try
{
response = await this.makeApiRequest(this.endpoint + "/search", "POST", payload);

if (response != null)
{
app = JSON.parse(response);
}
else
{
reject("Error retrieving application for " + appID + ". Response: " + response);
}

if (app.data.length > 0) {
resolve(app.data[0].name);
}
else {
reject("Failed to find application for " + appID + ". Please ensure the ID is correct and the application still exists.")
}
}
catch (err)
{
reject("Error retrieving application - " + err + "; payload: " + JSON.stringify(payload) +
"; response: " + response);
}
}.bind(this));
}

public async getScanConfigName(configId, applicationId)
{
return new Promise(async function (resolve, reject)
{
try
{
var response;
var payload = {type: "SCAN_CONFIG", query: "scanconfig.id='" + configId + "' && scanconfig.app.id='" + applicationId + "'"};

response = await this.makeApiRequest(this.endpoint + "/search", "POST", payload);

if (response != null)
{
var scanConfig = JSON.parse(response);
var scanConfigName = scanConfig.data[0].name;
resolve(scanConfigName);
}
else
{
reject("Error retrieving scan configuration Name");
}
}
catch (err)
{
reject("Error retrieving scan configuration Name - " + err);
}
}.bind(this));
}

public async submitScan(scanConfigId)
{
return new Promise(async function (resolve, reject)
Expand Down Expand Up @@ -408,4 +474,70 @@ export default class InsightAppSecApi

}.bind(this));
}

public async getApplicationData(appInput)
{
return new Promise(async function (resolve, reject)
{
try{
// Check if input is in UUID format to determine whether to get name or ID from API
let appUuidMatch = UUID_REGEX.exec(appInput);
let appId;
let appName;
if (appUuidMatch)
{
appId = appInput;
appName = await this.getAppName(appId);
}
else
{
if(this.debugMode)
{
console.log('##[debug]Detected existing app name input, retrieving ID from API.');
}
appName = appInput;
appId = await this.getAppId(appName);
}
resolve([appId, appName]);
}
catch (err)
{
reject("Error retrieving application data - " + err);
}
}.bind(this));
}

public async getScanConfigData(scanConfigInput, appId)
{
return new Promise(async function (resolve, reject)
{
try
{
let scanConfigUuidMatch = UUID_REGEX.exec(scanConfigInput);
let scanConfigId;
let scanConfigName;
if (scanConfigUuidMatch)
{
scanConfigId = scanConfigInput;
scanConfigName = await this.getScanConfigName(scanConfigId, appId);
}
else
{
if(this.debugMode)
{
console.log('##[debug]Detected existing scan config name input, retrieving ID from API.');
}
scanConfigName = scanConfigInput;
scanConfigId = await this.getScanConfigId(scanConfigName, appId);
}
resolve([scanConfigId, scanConfigName]);
}
catch (err)
{
reject("Error retrieving scan configuration data - " + err);
}
}.bind(this));
}


}
5 changes: 3 additions & 2 deletions tasks/InsightAppSec/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
"license": "MIT",
"dependencies": {
"@types/es6-promise": "^3.3.0",
"vsts-task-lib": "^2.1.0",
"axios": "0.21.1"
"adm-zip": "^0.5.5",
"axios": "0.21.1",
"vsts-task-lib": "^2.1.0"
},
"devDependencies": {
"@types/node": "^13.5.0",
Expand Down
34 changes: 30 additions & 4 deletions tasks/InsightAppSec/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
],
"version": {
"Major": 1,
"Minor": 0,
"Patch": 8
"Minor": 1,
"Patch": 0
},
"instanceNameFormat": "Rapid7 InsightAppSec",
"inputs": [
Expand All @@ -34,7 +34,7 @@
},
{
"name": "scanConfig",
"type": "string",
"type": "pickList",
"label": "Scan Configuration",
"required": true,
"helpMarkDown": "The configuration you want to apply during the scan."
Expand Down Expand Up @@ -107,13 +107,39 @@
"expression": "isMatch(value, '^(?!.*\").*$', 'IgnoreCase')",
"message": "Double quote (\") is an invalid character, use single quote (')."
}
},
{
"name": "publishPipelineArtifacts",
"type": "boolean",
"label": "Upload report output?",
"required": false,
"helpMarkDown": "For build pipelines: attach metrics and findings reports as pipeline artifacts. For release pipelines: attach metrics and findings reports as a zipfile, accessible in the logs.",
"defaultValue": "false"
},
{
"name": "artifactPerReport",
"type": "boolean",
"label": "Upload artifact per report?",
"visibleRule": "publishPipelineArtifacts = true && generateFindingsReport = true",
"required": false,
"helpMarkDown": "For build pipelines only. Findings report will be created as its own separate artifact, rather than grouped with the metrics report.",
"defaultValue": "false"
}

],
"dataSourceBindings": [
{
"target": "application",
"endpointId": "$(apiConnection)",
"dataSourceName": "Application"
"dataSourceName": "Application",
"resultTemplate" : "{\"Value\": \"{{{id}}}\", \"DisplayValue\": \"{{{name}}}\"}"
},
{
"target": "scanConfig",
"endpointId": "$(apiConnection)",
"dataSourceName": "ScanConfig",
"parameters": {"appID": "$(application)"},
"resultTemplate" : "{\"Value\": \"{{{id}}}\", \"DisplayValue\": \"{{{name}}}\"}"
}
],
"execution": {
Expand Down
Loading

0 comments on commit e827751

Please sign in to comment.