@@ -5,6 +5,7 @@ import * as tl from 'azure-pipelines-task-lib/task';
5
5
import { IExecOptions } from "azure-pipelines-task-lib/toolrunner" ;
6
6
import * as common from './msdo-common' ;
7
7
import * as installer from './msdo-installer' ;
8
+ import AdmZip = require( 'adm-zip' ) ;
8
9
9
10
/**
10
11
* The default version of Guardian to install if no version is specified.
@@ -87,10 +88,23 @@ async function init() {
87
88
*/
88
89
export async function run ( inputArgs : string [ ] , successfulExitCodes : number [ ] = null , publish : boolean = true , publishArtifactName : string = null , telemetryEnvironment : string = 'azdevops' ) : Promise < void > {
89
90
let tool = null ;
91
+ let debugDrop = common . parseBool ( process . env . GDN_DEBUG_DROP ) ;
90
92
91
93
let sarifFile : string = path . join ( process . env . BUILD_STAGINGDIRECTORY , '.gdn' , 'msdo.sarif' ) ;
92
94
tl . debug ( `sarifFile = ${ sarifFile } ` ) ;
93
95
96
+ const gdnTaskLibFolder = path . resolve ( __dirname ) ;
97
+ tl . debug ( `gdnTaskLibFolder = ${ gdnTaskLibFolder } ` ) ;
98
+
99
+ const nodeModulesFolder = path . dirname ( path . dirname ( gdnTaskLibFolder ) ) ;
100
+ tl . debug ( `nodeModulesFolder = ${ nodeModulesFolder } ` ) ;
101
+
102
+ const taskFolder = path . dirname ( nodeModulesFolder ) ;
103
+ tl . debug ( `taskFolder = ${ taskFolder } ` ) ;
104
+
105
+ const debugFolder = path . join ( taskFolder , 'debug' ) ;
106
+ tl . debug ( `debugFolder = ${ debugFolder } ` ) ;
107
+
94
108
try {
95
109
96
110
if ( successfulExitCodes == null ) {
@@ -140,6 +154,18 @@ export async function run(inputArgs: string[], successfulExitCodes: number[] = n
140
154
141
155
tool . arg ( '--telemetry-environment' ) ;
142
156
tool . arg ( telemetryEnvironment ) ;
157
+
158
+ // Include the debug drop option on the command line if applicable.
159
+ tl . debug ( `GdnDebugDrop = ${ debugDrop } ` ) ;
160
+ if ( debugDrop )
161
+ {
162
+ const dropPathValue = path . join ( taskFolder , 'debug' ) ;
163
+ tool . arg ( '--debug-drop' ) . arg ( '--debug-drop-path' ) . arg ( dropPathValue ) ;
164
+ const dropPathName = `GDN_DEBUGDROPPATH` ;
165
+
166
+ tl . debug ( `Debug Drop enabled. ${ dropPathName } : ${ dropPathValue } ` ) ;
167
+ process . env [ dropPathName ] = dropPathValue ;
168
+ }
143
169
} catch ( error ) {
144
170
console . error ( 'Exception occurred while initializing MSDO:' ) ;
145
171
tl . setResult ( tl . TaskResult . Failed , error ) ;
@@ -154,6 +180,9 @@ export async function run(inputArgs: string[], successfulExitCodes: number[] = n
154
180
155
181
tl . debug ( 'Running Microsoft Security DevOps...' ) ;
156
182
183
+ // Ensure debug folder starts clean
184
+ cleanupDirectory ( debugFolder ) ;
185
+
157
186
let exitCode = await tool . exec ( options ) ;
158
187
159
188
let success = false ;
@@ -164,6 +193,40 @@ export async function run(inputArgs: string[], successfulExitCodes: number[] = n
164
193
}
165
194
}
166
195
196
+ // Package up debug drop if applicable.
197
+ let debugStagingDir = '' ;
198
+ tl . debug ( `GdnDebugDrop = ${ debugDrop } ` ) ;
199
+ if ( debugDrop ) {
200
+ if ( fs . existsSync ( debugFolder ) ) {
201
+ tl . debug ( "Creating debug drop archive..." ) ;
202
+ let zippedOutput = getZippedFolder ( debugFolder ) ;
203
+
204
+ const taskFilePath = path . join ( taskFolder , `task.json` ) ;
205
+ tl . debug ( `taskFilePath = ${ taskFilePath } ` ) ;
206
+ const taskFile = require ( taskFilePath ) ;
207
+ const taskName = taskFile . name . toUpperCase ( ) ;
208
+
209
+ const instanceDirectory = getInstanceDirectory ( ) ;
210
+ debugStagingDir = path . join ( instanceDirectory , '.gdn' , 'debugdrop' ) ;
211
+ if ( ! fs . existsSync ( debugStagingDir ) ) {
212
+ tl . debug ( `Creating missing folder: ${ debugStagingDir } ` )
213
+ fs . mkdirSync ( debugStagingDir )
214
+ }
215
+
216
+ let debugDropArtifact = path . join ( debugStagingDir , `${ taskName } _debug.zip` ) ;
217
+ let dupeCount = 0 ;
218
+ while ( fs . existsSync ( debugDropArtifact ) ) {
219
+ dupeCount += 1 ;
220
+ debugDropArtifact = path . join ( debugStagingDir , `${ taskName } _${ dupeCount } _debug.zip` )
221
+ }
222
+ fs . copyFileSync ( zippedOutput , debugDropArtifact ) ;
223
+ tl . debug ( `Finished creating: ${ debugDropArtifact } ` ) ;
224
+ tl . debug ( `Cleaning up: ${ path . join ( taskFolder , 'debug' ) } ` ) ;
225
+ cleanupDirectory ( path . join ( taskFolder , 'debug' ) ) ;
226
+ tl . debug ( `Successfully cleaned up debug dump.` ) ;
227
+ }
228
+ }
229
+
167
230
if ( publish && fs . existsSync ( sarifFile ) ) {
168
231
if ( common . isNullOrWhiteSpace ( publishArtifactName ) ) {
169
232
publishArtifactName = 'CodeAnalysisLogs' ;
@@ -172,10 +235,88 @@ export async function run(inputArgs: string[], successfulExitCodes: number[] = n
172
235
console . log ( `##vso[artifact.upload artifactname=${ publishArtifactName } ]${ sarifFile } ` ) ;
173
236
}
174
237
238
+ if ( publish && fs . existsSync ( debugStagingDir ) ) {
239
+ console . log ( `##vso[artifact.upload artifactname=DebugDrop]${ debugStagingDir } ` ) ;
240
+ }
241
+
175
242
if ( ! success ) {
176
243
throw `MSDO CLI exited with an error exit code: ${ exitCode } ` ;
177
244
}
178
245
} catch ( error ) {
179
246
tl . setResult ( tl . TaskResult . Failed , error ) ;
180
247
}
248
+ }
249
+
250
+ function getInstanceDirectory ( ) : string {
251
+ let hostType = process . env . SYSTEM_HOSTTYPE ;
252
+ if ( hostType ) {
253
+ hostType = hostType . toUpperCase ( ) ;
254
+ }
255
+
256
+ if ( hostType == "RELEASE" ) {
257
+ return process . env . AGENT_RELEASEDIRECTORY ;
258
+ } else { // hostType == "BUILD" or default
259
+ return process . env . BUILD_SOURCESDIRECTORY ;
260
+ }
261
+ }
262
+
263
+ function getZippedFolder ( dir ) : string {
264
+ tl . debug ( `Zipping up folder: ${ dir } ` )
265
+ let allPaths = getFilePathsRecursively ( dir ) ;
266
+ const zip = new AdmZip ( ) ;
267
+ for ( let filePath of allPaths ) {
268
+ tl . debug ( `Adding file to archive: ${ filePath } ` ) ;
269
+ zip . addLocalFile ( filePath ) ;
270
+ }
271
+
272
+ let destPath = `${ dir } .zip` ;
273
+ tl . debug ( `Writing to file: ${ destPath } ` )
274
+ zip . writeZip ( destPath ) ;
275
+ if ( fs . existsSync ( destPath ) ) {
276
+ tl . debug ( `Successfully wrote file: ${ destPath } ` )
277
+ } else {
278
+ tl . debug ( `Something went wrong! File does not exist: ${ destPath } ` )
279
+ }
280
+ return destPath ;
281
+ }
282
+
283
+ // Returns a flat array of absolute paths to all files contained in the dir
284
+ function getFilePathsRecursively ( dir ) {
285
+ tl . debug ( `Searching for files under dir: ${ dir } ` )
286
+ var files = [ ] ;
287
+ let fileList = fs . readdirSync ( dir ) ;
288
+ var remaining = fileList . length ;
289
+ if ( ! remaining ) return files ;
290
+
291
+ for ( let file of fileList ) {
292
+ file = path . resolve ( dir , file ) ;
293
+ let stat = fs . statSync ( file ) ;
294
+ if ( stat && stat . isDirectory ( ) ) {
295
+ let f = getFilePathsRecursively ( file ) ;
296
+ files = files . concat ( f ) ;
297
+ } else {
298
+ files . push ( file ) ;
299
+ }
300
+ if ( ! -- remaining ) {
301
+ return files ;
302
+ }
303
+ }
304
+ }
305
+
306
+ function cleanupDirectory ( dir ) {
307
+ if ( ! fs . existsSync ( dir ) ) return ;
308
+
309
+ let items = fs . readdirSync ( dir ) ;
310
+
311
+ for ( let item of items ) {
312
+ item = path . resolve ( dir , item )
313
+ let stat = fs . statSync ( item ) ;
314
+ if ( stat && stat . isDirectory ( ) ) {
315
+ cleanupDirectory ( item )
316
+ } else {
317
+ fs . unlinkSync ( item ) ;
318
+ }
319
+ }
320
+
321
+ fs . rmdirSync ( dir ) ;
181
322
}
0 commit comments