Skip to content
This repository was archived by the owner on Jul 8, 2025. It is now read-only.

Commit 8edb235

Browse files
authored
Merge pull request #5 from MetLife/v1.1
V1.1
2 parents a2abc28 + 8016e8f commit 8edb235

8 files changed

Lines changed: 123 additions & 100 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,9 @@
22

33
# v1.0.0
44
- Initial Release
5+
6+
# v1.1.0
7+
- Removed scanner installation functionality. We now run the SRCCLR CI script from https://download.sourceclear.com/ci.sh. This will ensure we are always running the latest version of the SRCCLR scanner when using a local Azure DevOps Agent and will preclude us from needing root permissions to install the scanner.
8+
- Added the --recursive directive so that url and directory scans provide better coverage when applications use multiple package managers.
9+
- Set the CACHE_DIR to Agent.TempDirectory. CACHE_DIR is a feature for SCA to direct where the SCA scanner is downloaded to. The Agent.TempDirectory is cleaned out after every job, which is useful for users leveraging a local Azure DevOps agent and disk space fills up (default was /tmp).
10+
- Improved error handling for python tasks.

README.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,3 @@ The location of the latest self-hosted agents is [here](https://github.com/micro
8282
## References
8383

8484
[Here](https://www.paraesthesia.com/archive/2020/02/25/tips-for-custom-azure-devops-build-tasks/) are some useful tips for developing tasks for Azure DevOps.
85-
86-
## Feedback
87-
88-
Send me mail at gattjoseph@hotmail.com

buildAndReleaseTask/en-US/resources.resjson

Lines changed: 0 additions & 5 deletions
This file was deleted.

buildAndReleaseTask/package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

buildAndReleaseTask/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"azure-pipelines-tool-lib": "^0.13.2"
1616
},
1717
"devDependencies": {
18-
"@types/node": "^14.14.11",
18+
"@types/node": "^14.14.14",
1919
"@types/q": "^1.5.4"
2020
}
2121
}

buildAndReleaseTask/scascan.ts

Lines changed: 112 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,20 @@ import * as tl from 'azure-pipelines-task-lib/task';
88
import * as trm from 'azure-pipelines-task-lib/toolrunner';
99
import * as path from 'path';
1010

11+
/**
12+
* Get Agent.TempDirectory which is a temp folder that is cleaned after each pipeline job.
13+
* This is where we will store the Veracode SCA tool so we do not take up too much disk space
14+
* on self hosted agents.
15+
*/
16+
const tempPath: string = <string>tl.getVariable('Agent.TempDirectory');
17+
if (tempPath !== undefined) {
18+
// Per https://help.veracode.com/r/c_sc_ci_script if we set
19+
// the CACHE_DIR variable, we can direct where the files are downloaded to
20+
tl.setVariable('CACHE_DIR', tempPath);
21+
console.log(`CACHE_DIR: ${tempPath}`);
22+
}
23+
24+
1125
async function run(): Promise<void> {
1226
try {
1327
tl.setResourcePath(path.join(__dirname, 'task.json'));
@@ -48,93 +62,54 @@ async function run(): Promise<void> {
4862

4963
//This only works on linux or MacOs Agents
5064
if (agentPlatform === 'linux' || agentPlatform === 'darwin') {
51-
52-
try {
53-
// Is srcclr already installed?
54-
const srcclrPath: string = tl.which('srcclr', true);
55-
console.log('Found SCA Agent install here: ' + `${srcclrPath}`);
56-
57-
} catch {
58-
// Install srcclr
59-
const curlPath: string = tl.which('curl', true);
60-
const shPath: string = tl.which('sh', true);
61-
62-
// Install SCA Agent
63-
const curl: trm.ToolRunner = tl.tool(curlPath);
64-
curl.arg('-sSL');
65-
curl.arg('https://www.sourceclear.com/install');
66-
const sh: trm.ToolRunner = tl.tool(shPath);
67-
// On self-hosted agents this may not work if the agent is not running as root
68-
const pipe: trm.ToolRunner = curl.pipeExecOutputToTool(sh);
69-
const scaAgentInstall: number = await pipe.exec();
70-
tl.setResult(tl.TaskResult.Succeeded, tl.loc('curlReturnCode', scaAgentInstall));
71-
72-
}
73-
65+
7466
// Test the environment to see which collectors are available, equivalent to 'srcclr test'
7567
if (testAgent === true) {
76-
const scaAgentTest: trm.ToolRunner = tl.tool('srcclr');
77-
scaAgentTest.arg('test');
78-
const scaAgentTestResult: number = await scaAgentTest.exec();
79-
tl.setResult(tl.TaskResult.Succeeded, tl.loc('bashReturnCode', scaAgentTestResult));
68+
await testSCA();
8069
}
70+
71+
// Run the scan
72+
await runScan(scanType, scanTarget);
73+
74+
// Find the python3 installation
75+
const pythonPath: string = tl.which('python3');
8176

82-
// Scan against an artifact directory
83-
if (scanType === 'directory') {
84-
const scanDirectory: trm.ToolRunner = tl.tool('srcclr');
85-
scanDirectory.arg('scan');
86-
scanDirectory.arg(`${scanTarget}`);
87-
scanDirectory.arg('--json');
88-
scanDirectory.arg('scaresults.json');
89-
const directoryResults: number = await scanDirectory.exec();
90-
tl.setResult(tl.TaskResult.Succeeded, tl.loc('bashReturnCode', directoryResults));
91-
// Scan against a URL - Need to make sure it begins with http(s)
92-
} else if (scanType === 'url') {
93-
const scanUrl: trm.ToolRunner = tl.tool('srcclr');
94-
scanUrl.arg('scan');
95-
scanUrl.arg('--url');
96-
scanUrl.arg(`${scanTarget}`);
97-
scanUrl.arg('--json');
98-
scanUrl.arg('scaresults.json');
99-
const urlResults: number = await scanUrl.exec();
100-
tl.setResult(tl.TaskResult.Succeeded, tl.loc('bashReturnCode', urlResults));
101-
// Scan a Docker image
102-
} else if (scanType === 'image') {
103-
const scanDockerImage: trm.ToolRunner = tl.tool('srcclr');
104-
scanDockerImage.arg('scan');
105-
scanDockerImage.arg('--image');
106-
scanDockerImage.arg(`${scanTarget}`);
107-
scanDockerImage.arg('--json');
108-
scanDockerImage.arg('scaresults.json');
109-
const dockerResults: number = await scanDockerImage.exec();
110-
tl. setResult(tl.TaskResult.Succeeded, tl.loc('bashReturnCode', dockerResults));
77+
try {
78+
// Install junitparser
79+
const python3: trm.ToolRunner = tl.tool(pythonPath);
80+
python3.arg('-m');
81+
python3.arg('pip');
82+
python3.arg('install');
83+
python3.arg('--upgrade');
84+
python3.arg('pip');
85+
python3.arg('junitparser');
86+
// Run the command
87+
await python3.exec();
88+
tl.setResult(tl.TaskResult.Succeeded, "pip install was successful.");
89+
90+
} catch(err) {
91+
92+
return tl.setResult(tl.TaskResult.Failed, "pip install failed.");
11193
}
11294

113-
// Need error handling when selecting python for non Microsoft hosted agents
114-
// Install junitparser
115-
const pythonPath: string = tl.which('python3');
116-
const python3: trm.ToolRunner = tl.tool(pythonPath);
117-
python3.arg('-m');
118-
python3.arg('pip');
119-
python3.arg('install');
120-
python3.arg('--upgrade');
121-
python3.arg('junitparser');
122-
const pipinstall: number = await python3.exec();
123-
tl.setResult(tl.TaskResult.Succeeded, tl.loc('pipReturnCode', pipinstall));
124-
125-
// Generate the results
126-
const genResults: trm.ToolRunner = tl.tool(pythonPath);
127-
genResults.arg(path.join(__dirname, 'parsescaresults.py'));
128-
genResults.arg('--target');
129-
genResults.arg(`${appName}`);
130-
genResults.arg('--mincvss');
131-
genResults.arg(`${minCVSS}`);
132-
genResults.arg('--failbuild');
133-
genResults.arg(`${failBuild}`);
134-
const publishResults: number = await genResults.exec();
135-
tl.setResult(tl.TaskResult.Succeeded, tl.loc('bashReturnCode', publishResults));
136-
137-
return;
95+
try {
96+
// Generate the results
97+
const genResults: trm.ToolRunner = tl.tool(pythonPath);
98+
genResults.arg(path.join(__dirname, 'parsescaresults.py'));
99+
genResults.arg('--target');
100+
genResults.arg(`${appName}`);
101+
genResults.arg('--mincvss');
102+
genResults.arg(`${minCVSS}`);
103+
genResults.arg('--failbuild');
104+
genResults.arg(`${failBuild}`);
105+
// Run the command
106+
await genResults.exec();
107+
return tl.setResult(tl.TaskResult.Succeeded, "SCA result parsing and upload was successful.");
108+
109+
} catch(err) {
110+
111+
return tl.setResult(tl.TaskResult.Failed, "SCA result parsing and upload failed.");
112+
}
138113

139114
} else {
140115
// Need to add Windows support
@@ -150,4 +125,60 @@ async function run(): Promise<void> {
150125
}
151126
}
152127

128+
// Run the SCA scan
129+
async function runScan(scanType: string,
130+
scanTarget: string): Promise<void> {
131+
132+
try {
133+
const curlPath: string = tl.which('curl', true);
134+
const shPath: string = tl.which('sh', true);
135+
const curl: trm.ToolRunner = tl.tool(curlPath);
136+
curl.arg('-sSL');
137+
curl.arg('https://download.sourceclear.com/ci.sh');
138+
const sh: trm.ToolRunner = tl.tool(shPath);
139+
sh.arg('-s');
140+
sh.arg('--');
141+
sh.arg('scan');
142+
if (scanType !== 'directory') {
143+
sh.arg(`--${scanType}`);
144+
}
145+
sh.arg(`${scanTarget}`);
146+
sh.arg('--recursive');
147+
sh.arg('--json');
148+
sh.arg('scaresults.json');
149+
const pipe: trm.ToolRunner = curl.pipeExecOutputToTool(sh);
150+
await pipe.exec();
151+
152+
return tl.setResult(tl.TaskResult.Succeeded, "SCA scan completed.");
153+
154+
} catch (err) {
155+
throw new Error(err);
156+
157+
}
158+
}
159+
160+
// Test the SCA scan environment
161+
async function testSCA(): Promise<void> {
162+
163+
try {
164+
const curlPath: string = tl.which('curl', true);
165+
const shPath: string = tl.which('sh', true);
166+
const curl: trm.ToolRunner = tl.tool(curlPath);
167+
curl.arg('-sSL');
168+
curl.arg('https://download.sourceclear.com/ci.sh');
169+
const sh: trm.ToolRunner = tl.tool(shPath);
170+
sh.arg('-s');
171+
sh.arg('--');
172+
sh.arg('test');
173+
const pipe: trm.ToolRunner = curl.pipeExecOutputToTool(sh);
174+
await pipe.exec();
175+
176+
return tl.setResult(tl.TaskResult.Succeeded, "SCA test completed.");
177+
178+
} catch (err) {
179+
throw new Error(err);
180+
181+
}
182+
}
183+
153184
run();

buildAndReleaseTask/task.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,6 @@
8989
}
9090
},
9191
"showEnvironmentVariables": true,
92-
"messages": {
93-
"curlReturnCode": "Task exited with return code: %s",
94-
"bashReturnCode": "Task exited with return code: %s",
95-
"pipReturnCode": "Task exited with return code: %s"
96-
},
9792
"visibility": [
9893
"Build",
9994
"Release"

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
junitparser==1.4.1
1+
junitparser==1.6.3
22
pytest==6.1.1
33
pytest-azurepipelines==0.8.0
44
pytest-cov==2.10.1

0 commit comments

Comments
 (0)