Skip to content

Commit ffb930e

Browse files
committed
unified scanner docker image
unified scanner docker image unified scanner docker image debug + erase macOS runner debug... debug testing clean add back the generateUILink clean
1 parent f975e86 commit ffb930e

4 files changed

Lines changed: 288 additions & 118 deletions

File tree

.github/workflows/integration-test.yml

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,17 @@ on:
1010
workflow_dispatch:
1111

1212
env:
13-
LW_ACCOUNT_NAME: ${{ secrets.LW_ACCOUNT_CAT }}
14-
LW_API_KEY: ${{ secrets.LW_API_KEY_CAT }}
15-
LW_API_SECRET: ${{ secrets.LW_API_SECRET_CAT }}
13+
LW_ACCOUNT_NAME: ${{ secrets.LW_ACCOUNT_UEDEMO }}
14+
LW_API_KEY: ${{ secrets.LW_API_KEY_UEDEMO }}
15+
LW_API_SECRET: ${{ secrets.LW_API_SECRET_UEDEMO }}
1616
DEBUG: 'true'
1717

1818
jobs:
1919
build:
20-
strategy:
21-
fail-fast: false
22-
matrix:
23-
os:
24-
- macos-latest
25-
- ubuntu-latest
26-
runs-on: ${{ matrix.os }}
20+
runs-on: ubuntu-latest
2721
steps:
2822
- name: Checkout repository
2923
uses: actions/checkout@v3
30-
- name: Set up Java
31-
uses: actions/setup-java@v3
32-
with:
33-
distribution: 'temurin'
34-
java-version: '17'
3524
- name: Move action
3625
run: |
3726
mkdir ../action
@@ -44,7 +33,6 @@ jobs:
4433
target: push
4534
sources: ${{ github.workspace }}
4635
debug: true
47-
artifact-prefix: ${{ matrix.os }}
4836
- name: Check run succeeded
4937
env:
5038
RUN_OUTPUT: ${{ steps.run-action.outputs.push-completed }}
@@ -58,12 +46,12 @@ jobs:
5846
- name: Download results
5947
uses: actions/download-artifact@v4
6048
with:
61-
name: ${{ matrix.os }}-results-push
49+
name: results-push
6250
path: artifact
6351
- name: Check results
6452
working-directory: artifact
6553
run: |
66-
export SCA_RESULTS=`jq '.runs | map (.results | length) | add' sca.sarif`
54+
export SCA_RESULTS=`jq '.runs | map (.results | length) | add' scan-results/sca/sca-scan.sarif`
6755
echo "Got $SCA_RESULTS from SCA"
6856
if [ "$SCA_RESULTS" -eq 0 ]; then
6957
echo "::error::Expected to have $expectedScaResults SCA results!"

action.yaml

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,6 @@ runs:
4949
- if: runner.os == 'Linux'
5050
shell: bash
5151
run: echo "LACEWORK_START_TIME=$(date --rfc-3339=seconds)" >> $GITHUB_ENV
52-
- if: runner.os == 'macOS'
53-
shell: bash
54-
run: |
55-
brew install coreutils
56-
echo "LACEWORK_START_TIME=$(gdate --rfc-3339=seconds)" >> $GITHUB_ENV
5752
- id: init
5853
shell: bash
5954
env:
@@ -63,19 +58,11 @@ runs:
6358
echo "Lacework context ID: $LACEWORK_CONTEXT_ID"
6459
echo "LACEWORK_CONTEXT_ID=$(echo $LACEWORK_CONTEXT_ID)" >> $GITHUB_ENV
6560
echo "LACEWORK_ACTION_REF=$(echo $LACEWORK_ACTION_REF)" >> $GITHUB_ENV
66-
curl https://raw.githubusercontent.com/lacework/go-sdk/main/cli/install.sh | bash
6761
- name: Sets LW_LOG var for debug
6862
shell: bash
6963
if: ${{ inputs.debug == 'true' }}
7064
run: |
7165
echo "LW_LOG=debug" >> $GITHUB_ENV
72-
- name: Install Lacework CLI component
73-
shell: bash
74-
run: |
75-
lacework --noninteractive -a "${LW_ACCOUNT_NAME}" -k "${LW_API_KEY}" -s "${LW_API_SECRET}" component install sca
76-
lacework --noninteractive -a "${LW_ACCOUNT_NAME}" -k "${LW_API_KEY}" -s "${LW_API_SECRET}" version
77-
env:
78-
CDK_DOWNLOAD_TIMEOUT_MINUTES: 2
7966
- uses: actions/setup-node@v4
8067
with:
8168
node-version: 18

src/index.ts

Lines changed: 100 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
import { 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'
34
import {
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

1712
async 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 = /Found\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

116149
async function main() {

0 commit comments

Comments
 (0)