11import { error , getInput , info , setOutput } from '@actions/core'
2- import { existsSync , readFileSync } from 'fs'
2+ import { existsSync , mkdirSync } from 'fs'
3+ import * as path from 'path'
34import {
45 downloadArtifact ,
56 postCommentIfInPr ,
67 resolveExistingCommentIfFound ,
78 uploadArtifact ,
89} from './actions'
9- import { callLaceworkCli , debug , generateUILink , getOptionalEnvVariable } from './util'
10-
11- import path from 'path'
12-
13- const artifactPrefix = getInput ( 'artifact-prefix' )
14- const sarifReportPath = getInput ( 'code-scanning-path' )
15- const comparisonMarkdownPath = 'comparison.md'
10+ import { callCommand , codesecRun , getOptionalEnvVariable , readMarkdownFile } from './util'
1611
1712async function runAnalysis ( ) {
1813 const target = getInput ( 'target' )
@@ -30,87 +25,125 @@ async function runAnalysis() {
3025 info ( 'Analyzing ' + target )
3126 const toUpload : string [ ] = [ ]
3227
33- // command to print both sarif and lwjson formats
34- var args = [ 'scan' , '.' , '--formats' , 'sarif' , '--output' , sarifReportPath , '--deployment' , 'ci' ]
35- if ( target === 'push' ) {
36- args . push ( '--save-results' )
28+ // Run codesec Docker scanner
29+ // targetScan: 'new'/'old' for PR mode, 'scan' for push mode (should upload results to db)
30+ var targetScan = target
31+ if ( target == 'push' ) {
32+ targetScan = 'scan'
3733 }
38- if ( debug ( ) ) {
39- args . push ( '--debug' )
34+ const resultsPath = await codesecRun ( 'scan' , true , true , targetScan )
35+
36+ // Upload SCA SARIF from the returned results path
37+ const scaSarifFile = path . join ( resultsPath , 'sca' , `sca-${ targetScan } .sarif` )
38+ if ( existsSync ( scaSarifFile ) ) {
39+ info ( `Found SCA SARIF file to upload: ${ scaSarifFile } ` )
40+ toUpload . push ( scaSarifFile )
41+ } else {
42+ info ( `SCA SARIF file not found at: ${ scaSarifFile } ` )
4043 }
41- await callLaceworkCli ( ...args )
42- toUpload . push ( sarifReportPath )
4344
44- const uploadStart = Date . now ( )
45+ // Upload IAC JSON from the returned results path
46+ const iacJsonFile = path . join ( resultsPath , 'iac' , `iac-${ targetScan } .json` )
47+ if ( existsSync ( iacJsonFile ) ) {
48+ info ( `Found IAC JSON file to upload: ${ iacJsonFile } ` )
49+ toUpload . push ( iacJsonFile )
50+ } else {
51+ info ( `IAC JSON file not found at: ${ iacJsonFile } ` )
52+ }
4553
46- await uploadArtifact ( getArtifactName ( target ) , ...toUpload )
54+ const artifactPrefix = getInput ( 'artifact-prefix' )
55+ const artifactName =
56+ artifactPrefix !== '' ? artifactPrefix + '-results-' + target : 'results-' + target
57+ info ( `Uploading artifact '${ artifactName } ' with ${ toUpload . length } file(s)` )
58+ await uploadArtifact ( artifactName , ...toUpload )
4759 setOutput ( `${ target } -completed` , true )
4860}
4961
50- export async function compareResults ( oldReport : string , newReport : string ) : Promise < string > {
51- const args = [
52- 'compare' ,
53- '--old' ,
54- oldReport ,
55- '--new' ,
56- newReport ,
57- '--output' ,
58- sarifReportPath ,
59- '--markdown' ,
60- comparisonMarkdownPath ,
61- '--markdown-variant' ,
62- 'GitHub' ,
63- '--deployment' ,
64- 'ci' ,
65- ]
66- const uiLink = generateUILink ( )
67- if ( uiLink ) args . push ( ...[ '--ui-link' , uiLink ] )
68- if ( debug ( ) ) args . push ( '--debug' )
62+ async function displayResults ( ) {
63+ info ( 'Displaying results' )
6964
70- await callLaceworkCli ( ...args )
71- await uploadArtifact ( getArtifactName ( 'compare' ) , sarifReportPath , comparisonMarkdownPath )
65+ // Download artifacts from previous jobs
66+ const artifactOld = await downloadArtifact ( 'results-old' )
67+ const artifactNew = await downloadArtifact ( 'results-new' )
7268
73- return existsSync ( comparisonMarkdownPath ) ? readFileSync ( comparisonMarkdownPath , 'utf8' ) : ''
74- }
69+ // Create local scan-results directory for compare
70+ mkdirSync ( 'scan-results/sca' , { recursive : true } )
71+ mkdirSync ( 'scan-results/iac' , { recursive : true } )
7572
76- async function displayResults ( ) {
77- info ( 'Displaying results' )
78- const downloadStart = Date . now ( )
79- const artifactOld = await downloadArtifact ( getArtifactName ( 'old' ) )
80- const artifactNew = await downloadArtifact ( getArtifactName ( 'new' ) )
81- const sarifFileOld = path . join ( artifactOld , sarifReportPath )
82- const sarifFileNew = path . join ( artifactNew , sarifReportPath )
83-
84- var compareMessage : string
85- if ( existsSync ( sarifFileOld ) && existsSync ( sarifFileNew ) ) {
86- compareMessage = await compareResults ( sarifFileOld , sarifFileNew )
87- } else {
88- throw new Error ( 'SARIF file not found' )
73+ // Check and copy files for each scanner type
74+ const scaAvailable = await prepareScannerFiles ( 'sca' , artifactOld , artifactNew )
75+ const iacAvailable = await prepareScannerFiles ( 'iac' , artifactOld , artifactNew )
76+
77+ // Need at least one scanner to compare
78+ if ( ! scaAvailable && ! iacAvailable ) {
79+ info ( 'No scanner files available for comparison. Nothing to compare.' )
80+ setOutput ( 'display-completed' , true )
81+ return
8982 }
9083
91- const commentStart = Date . now ( )
92- if ( compareMessage . length > 0 && getInput ( 'token' ) . length > 0 ) {
93- info ( 'Posting comment to GitHub PR as there were new issues introduced:' )
94- if ( getInput ( 'footer' ) !== '' ) {
95- compareMessage += '\n\n' + getInput ( 'footer' )
84+ // Run codesec compare mode with available scanners
85+ await codesecRun ( 'compare' , iacAvailable , scaAvailable )
86+
87+ // Read comparison output - check all possible outputs
88+ const outputs = [
89+ 'scan-results/compare/merged-compare.md' ,
90+ 'scan-results/compare/sca-compare.md' ,
91+ 'scan-results/compare/iac-compare.md' ,
92+ ]
93+
94+ let message : string | null = null
95+ for ( const output of outputs ) {
96+ if ( existsSync ( output ) ) {
97+ info ( `Using comparison output: ${ output } ` )
98+ message = readMarkdownFile ( output )
99+ break
96100 }
97- info ( compareMessage )
98- const commentUrl = await postCommentIfInPr ( compareMessage )
101+ }
102+
103+ if ( ! message ) {
104+ info ( 'No comparison output produced. No changes detected.' )
105+ setOutput ( 'display-completed' , true )
106+ return
107+ }
108+
109+ // Check if there are new violations (non-zero count in "Found N new potential violations")
110+ const hasViolations = / F o u n d \s + [ 1 - 9 ] \d * \s + / . test ( message )
111+
112+ if ( hasViolations && getInput ( 'token' ) . length > 0 ) {
113+ info ( 'Posting comment to GitHub PR as there were new issues introduced' )
114+ const commentUrl = await postCommentIfInPr ( message )
99115 if ( commentUrl !== undefined ) {
100116 setOutput ( 'posted-comment' , commentUrl )
101117 }
102118 } else {
119+ // No new violations or no token - resolve existing comment if found
103120 await resolveExistingCommentIfFound ( )
104121 }
105- setOutput ( `display-completed` , true )
122+
123+ setOutput ( 'display-completed' , true )
106124}
107125
108- function getArtifactName ( target : string ) : string {
109- var artifactName = 'results-'
110- if ( artifactPrefix !== '' ) {
111- artifactName = artifactPrefix + '-' + artifactName
126+ async function prepareScannerFiles (
127+ scanner : 'sca' | 'iac' ,
128+ artifactOld : string ,
129+ artifactNew : string
130+ ) : Promise < boolean > {
131+ const ext = scanner === 'sca' ? 'sarif' : 'json'
132+ const oldPath = path . join ( artifactOld , 'scan-results' , scanner , `${ scanner } -old.${ ext } ` )
133+ const newPath = path . join ( artifactNew , 'scan-results' , scanner , `${ scanner } -new.${ ext } ` )
134+
135+ const oldExists = existsSync ( oldPath )
136+ const newExists = existsSync ( newPath )
137+
138+ if ( ! oldExists || ! newExists ) {
139+ info ( `${ scanner . toUpperCase ( ) } files not found for compare. old=${ oldExists } , new=${ newExists } ` )
140+ return false
112141 }
113- return artifactName + target
142+
143+ info ( `Copying ${ scanner . toUpperCase ( ) } files for compare` )
144+ await callCommand ( 'cp' , oldPath , path . join ( 'scan-results' , scanner , `${ scanner } -old.${ ext } ` ) )
145+ await callCommand ( 'cp' , newPath , path . join ( 'scan-results' , scanner , `${ scanner } -new.${ ext } ` ) )
146+ return true
114147}
115148
116149async function main ( ) {
0 commit comments