|
1 | 1 | import { endGroup, startGroup } from '@actions/core' |
2 | | -import { context } from '@actions/github' |
3 | 2 | import { existsSync, readFileSync } from 'fs' |
4 | | -import { simpleGit, SimpleGitOptions } from 'simple-git' |
5 | | -import { getPrApi } from './actions' |
6 | | -import { LWJSON } from './lw-json' |
7 | | -import { |
8 | | - callLaceworkCli, |
9 | | - debug, |
10 | | - generateUILink, |
11 | | - getOptionalEnvVariable, |
12 | | - getRequiredEnvVariable, |
13 | | -} from './util' |
14 | | - |
15 | | -export function splitStringAtFirstSlash(inputString: string | undefined): [string, string] { |
16 | | - if (inputString != null) { |
17 | | - const [firstPart, secondPart] = inputString.split('/', 2) |
18 | | - return [firstPart, secondPart] |
19 | | - } |
20 | | - return ['', ''] |
21 | | -} |
22 | | - |
23 | | -export const options: Partial<SimpleGitOptions> = { |
24 | | - baseDir: process.cwd(), |
25 | | - binary: 'git', |
26 | | - maxConcurrentProcesses: 6, |
27 | | - trimmed: false, |
28 | | -} |
29 | | - |
30 | | -export async function prForFixSuggestion( |
31 | | - jsonFile: string, |
32 | | - fixId: string, |
33 | | - repoOwner: string, |
34 | | - repoName: string, |
35 | | - telem: { |
36 | | - prsCounter: number |
37 | | - prsUpdated: number |
38 | | - errors: any[] |
39 | | - totalAPITime: number |
40 | | - } |
41 | | -) { |
42 | | - let newBranch: string = 'codesec/sca/' |
43 | | - |
44 | | - // git configuration |
45 | | - const git = simpleGit(options) |
46 | | - await git.addConfig('user.name', 'Lacework Code Security', false, 'global') |
47 | | - await git.addConfig('user.email', '[email protected]', false, 'global') |
48 | | - |
49 | | - // get current branch |
50 | | - // trigger: on pr |
51 | | - let currBranch = getOptionalEnvVariable('GITHUB_HEAD_REF', '') |
52 | | - if (currBranch == '') { |
53 | | - // trigger: on push |
54 | | - currBranch = getRequiredEnvVariable('GITHUB_REF_NAME') |
55 | | - } |
56 | | - |
57 | | - newBranch += currBranch + '/' |
58 | | - |
59 | | - var patchReport = 'patchSummary.md' |
60 | | - |
61 | | - // create command to run on branch |
62 | | - var args = ['sca', 'patch', '.', '--sbom', jsonFile, '--fix-id', fixId, '-o', patchReport] |
63 | | - |
64 | | - // call patch command |
65 | | - await callLaceworkCli(...args) |
66 | | - |
67 | | - let patch = readFileSync(patchReport, 'utf-8') |
68 | | - // title is the first line of the patch summary |
69 | | - let titlePR = patch.split('\n')[0].substring(2) |
70 | | - newBranch += titlePR.split('bump ')[1].split(' to')[0].replaceAll(' ', '_').replaceAll(':', '-') |
71 | | - if (newBranch[newBranch.length - 1] == '.') { |
72 | | - newBranch = newBranch.substring(0, newBranch.length - 1) |
73 | | - } |
74 | | - |
75 | | - // create local branch |
76 | | - await git.checkoutLocalBranch(newBranch) |
77 | | - |
78 | | - // parse the modified files from the patch summary |
79 | | - const startKeyword = '## Files that have been modified:' |
80 | | - const endKeyword = '## Explanation: why is this SmartFix recommended?' |
81 | | - |
82 | | - const startIndex = patch.indexOf(startKeyword) |
83 | | - const endIndex = patch.indexOf(endKeyword, startIndex) |
84 | | - const files: string[] = [] |
85 | | - if (startIndex !== -1 && endIndex !== -1) { |
86 | | - const modifiedFilesText = patch.substring(startIndex + startKeyword.length, endIndex) |
87 | | - |
88 | | - const lines = modifiedFilesText.split('\n') |
89 | | - for (const line of lines) { |
90 | | - const cleanedLine = line.trim().substring(3, line.length - 1) |
91 | | - if (cleanedLine) { |
92 | | - files.push(cleanedLine) |
93 | | - } |
94 | | - } |
95 | | - } |
96 | | - // add modified files to branch |
97 | | - for (const file of files) { |
98 | | - if (file != '') { |
99 | | - await git.add(file) |
100 | | - } |
101 | | - } |
102 | | - |
103 | | - // commit and push changes --force to overwrite remote branch |
104 | | - await git.commit('Fix for: ' + newBranch + '.').push('origin', newBranch, ['--force']) |
105 | | - |
106 | | - // open PR |
107 | | - let prFound = false |
108 | | - // retrieve list of PRs |
109 | | - const prList = await getPrApi().list({ |
110 | | - owner: repoOwner, |
111 | | - repo: repoName, |
112 | | - state: 'open', |
113 | | - }) |
114 | | - // look for PR corresponding to this branch |
115 | | - let filtered = prList.data.filter((pr) => pr.head.ref == newBranch) |
116 | | - for (const pr of filtered) { |
117 | | - prFound = true |
118 | | - let pullNr = pr.number |
119 | | - // update with right title and body. |
120 | | - try { |
121 | | - const before = Date.now() |
122 | | - await getPrApi().update({ |
123 | | - owner: repoOwner, |
124 | | - repo: repoName, |
125 | | - pull_number: pullNr, |
126 | | - title: titlePR, |
127 | | - body: patch, |
128 | | - }) |
129 | | - const after = Date.now() |
130 | | - telem.totalAPITime += after - before |
131 | | - telem.prsUpdated++ |
132 | | - telem.prsCounter++ |
133 | | - } catch (e) { |
134 | | - telem.errors.push(e) |
135 | | - } |
136 | | - } |
137 | | - // create PR if not found |
138 | | - if (!prFound) { |
139 | | - try { |
140 | | - await getPrApi().create({ |
141 | | - owner: repoOwner, |
142 | | - repo: repoName, |
143 | | - head: newBranch, |
144 | | - base: currBranch, |
145 | | - title: titlePR, |
146 | | - body: patch, |
147 | | - }) |
148 | | - telem.prsCounter++ |
149 | | - } catch (e) { |
150 | | - telem.errors.push(e) |
151 | | - } |
152 | | - } |
153 | | - |
154 | | - // go back to currBranch |
155 | | - await git.checkout(currBranch) |
156 | | -} |
157 | | - |
158 | | -export async function createPRs(jsonFile: string) { |
159 | | - const before: number = Date.now() |
160 | | - const results: LWJSON = JSON.parse(readFileSync(jsonFile, 'utf-8')) |
161 | | - |
162 | | - // get owner and name of current repository |
163 | | - const [repoOwner, repoName] = splitStringAtFirstSlash(getRequiredEnvVariable('GITHUB_REPOSITORY')) |
164 | | - |
165 | | - if (results.FixSuggestions == undefined) { |
166 | | - return |
167 | | - } |
168 | | - |
169 | | - const telem = { |
170 | | - prsCounter: 0, |
171 | | - prsUpdated: 0, |
172 | | - errors: Array(), |
173 | | - totalAPITime: 0, |
174 | | - } |
175 | | - for (const fix of results.FixSuggestions) { |
176 | | - let fixId: string = fix.Id |
177 | | - await prForFixSuggestion(jsonFile, fixId, repoOwner, repoName, telem) |
178 | | - } |
179 | | - const after = Date.now() |
180 | | -} |
| 3 | +import { callLaceworkCli, debug, generateUILink } from './util' |
181 | 4 |
|
182 | 5 | export async function compareResults( |
183 | 6 | tool: string, |
|
0 commit comments