Skip to content

Commit f998353

Browse files
committed
Consolidate pr helpers
1 parent bcc7137 commit f998353

File tree

7 files changed

+464
-703
lines changed

7 files changed

+464
-703
lines changed

src/commands/fix/coana-fix.mts

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,9 @@ import { joinAnd } from '@socketsecurity/registry/lib/arrays'
44
import { debugDir, debugFn } from '@socketsecurity/registry/lib/debug'
55
import { logger } from '@socketsecurity/registry/lib/logger'
66

7-
import { getFixEnv } from './fix-env-helpers.mts'
8-
import {
9-
enablePrAutoMerge,
10-
fetchGhsaDetails,
11-
openCoanaPr,
12-
setGitRemoteGithubRepoUrl,
13-
} from './pull-request.mts'
7+
import { getFixEnv } from './env-helpers.mts'
8+
import { getSocketFixBranchName, getSocketFixCommitMessage } from './git.mts'
9+
import { openSocketFixPr } from './pull-request.mts'
1410
import { handleApiCall } from '../../utils/api.mts'
1511
import { cmdFlagValueToArray } from '../../utils/cmd.mts'
1612
import { spawnCoana } from '../../utils/coana.mts'
@@ -24,6 +20,11 @@ import {
2420
gitResetAndClean,
2521
gitUnstagedModifiedFiles,
2622
} from '../../utils/git.mts'
23+
import {
24+
enablePrAutoMerge,
25+
fetchGhsaDetails,
26+
setGitRemoteGithubRepoUrl,
27+
} from '../../utils/github.mts'
2728
import { getPackageFilesForScan } from '../../utils/path-resolve.mts'
2829
import { setupSdk } from '../../utils/sdk.mts'
2930
import { fetchSupportedScanFileNames } from '../scan/fetch-supported-scan-file-names.mts'
@@ -166,8 +167,8 @@ export async function coanaFix(
166167

167168
// Process each GHSA ID individually, similar to npm-fix/pnpm-fix.
168169
ghsaLoop: for (let i = 0, { length } = ids; i < length; i += 1) {
169-
const id = ids[i]!
170-
debugFn('notice', `check: ${id}`)
170+
const ghsaId = ids[i]!
171+
debugFn('notice', `check: ${ghsaId}`)
171172

172173
// Apply fix for single GHSA ID.
173174
// eslint-disable-next-line no-await-in-loop
@@ -178,7 +179,7 @@ export async function coanaFix(
178179
'--manifests-tar-hash',
179180
tarHash,
180181
'--apply-fixes-to',
181-
id,
182+
ghsaId,
182183
...(fixConfig.rangeStyle
183184
? ['--range-style', fixConfig.rangeStyle]
184185
: []),
@@ -190,7 +191,7 @@ export async function coanaFix(
190191

191192
if (!fixCResult.ok) {
192193
logger.error(
193-
`Update failed for ${id}: ${fixCResult.message || 'Unknown error'}`,
194+
`Update failed for ${ghsaId}: ${fixCResult.message || 'Unknown error'}`,
194195
)
195196
continue ghsaLoop
196197
}
@@ -205,13 +206,13 @@ export async function coanaFix(
205206
: []
206207

207208
if (!modifiedFiles.length) {
208-
debugFn('notice', `skip: no changes for ${id}`)
209+
debugFn('notice', `skip: no changes for ${ghsaId}`)
209210
continue ghsaLoop
210211
}
211212

212213
overallFixed = true
213214

214-
const branch = `socket/fix/${id}`
215+
const branch = getSocketFixBranchName(ghsaId)
215216

216217
try {
217218
// Check if branch already exists.
@@ -221,11 +222,13 @@ export async function coanaFix(
221222
continue ghsaLoop
222223
}
223224

224-
debugFn('notice', `pr: creating for ${id}`)
225+
debugFn('notice', `pr: creating for ${ghsaId}`)
225226

226-
const details = ghsaDetails.get(id)
227-
const summary = details?.summary
228-
debugFn('notice', `ghsa: ${id} details ${details ? 'found' : 'missing'}`)
227+
const details = ghsaDetails.get(ghsaId)
228+
debugFn(
229+
'notice',
230+
`ghsa: ${ghsaId} details ${details ? 'found' : 'missing'}`,
231+
)
229232

230233
const pushed =
231234
// eslint-disable-next-line no-await-in-loop
@@ -234,7 +237,7 @@ export async function coanaFix(
234237
(await gitCheckoutBranch(branch, cwd)) &&
235238
// eslint-disable-next-line no-await-in-loop
236239
(await gitCommit(
237-
`fix: ${id}${summary ? ` - ${summary}` : ''}`,
240+
getSocketFixCommitMessage(ghsaId, details),
238241
modifiedFiles,
239242
{
240243
cwd,
@@ -246,7 +249,7 @@ export async function coanaFix(
246249
(await gitPushBranch(branch, cwd))
247250

248251
if (!pushed) {
249-
logger.warn(`Push failed for ${id}, skipping PR creation.`)
252+
logger.warn(`Push failed for ${ghsaId}, skipping PR creation.`)
250253
// eslint-disable-next-line no-await-in-loop
251254
await gitResetAndClean(fixEnv.baseBranch, cwd)
252255
// eslint-disable-next-line no-await-in-loop
@@ -266,12 +269,12 @@ export async function coanaFix(
266269
)
267270

268271
// eslint-disable-next-line no-await-in-loop
269-
const prResponse = await openCoanaPr(
272+
const prResponse = await openSocketFixPr(
270273
fixEnv.repoInfo.owner,
271274
fixEnv.repoInfo.repo,
272275
branch,
273276
// Single GHSA ID.
274-
[id],
277+
[ghsaId],
275278
{
276279
baseBranch: fixEnv.baseBranch,
277280
cwd,
@@ -282,7 +285,7 @@ export async function coanaFix(
282285
if (prResponse) {
283286
const { data } = prResponse
284287
const prRef = `PR #${data.number}`
285-
logger.success(`Opened ${prRef} for ${id}.`)
288+
logger.success(`Opened ${prRef} for ${ghsaId}.`)
286289

287290
if (autoMerge) {
288291
logger.indent()
@@ -309,7 +312,7 @@ export async function coanaFix(
309312
await gitCheckoutBranch(fixEnv.baseBranch, cwd)
310313
} catch (e) {
311314
logger.warn(
312-
`Unexpected condition: Push failed for ${id}, skipping PR creation.`,
315+
`Unexpected condition: Push failed for ${ghsaId}, skipping PR creation.`,
313316
)
314317
debugDir('inspect', { error: e })
315318
// eslint-disable-next-line no-await-in-loop

src/commands/fix/fix-branch-helpers.mts

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

src/commands/fix/git.mts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { joinAnd } from '@socketsecurity/registry/lib/arrays'
2+
3+
import constants from '../../constants.mts'
4+
5+
import type { GhsaDetails } from '../../utils/github.mts'
6+
7+
const GITHUB_ADVISORIES_URL = 'https://github.com/advisories'
8+
9+
export type SocketFixBranchParser = (
10+
branch: string,
11+
) => SocketFixBranchParseResult | null
12+
13+
export type SocketFixBranchParseResult = {
14+
ghsaId: string
15+
}
16+
17+
export function createSocketFixBranchParser(
18+
ghsaId?: string | undefined,
19+
): SocketFixBranchParser {
20+
const pattern = getSocketFixBranchPattern(ghsaId)
21+
return function parse(branch: string): SocketFixBranchParseResult | null {
22+
const match = pattern.exec(branch) as [string, string] | null
23+
if (!match) {
24+
return null
25+
}
26+
const { 1: ghsaId } = match
27+
return { ghsaId } as SocketFixBranchParseResult
28+
}
29+
}
30+
31+
export const genericSocketFixBranchParser = createSocketFixBranchParser()
32+
33+
export function getSocketFixBranchName(ghsaId: string): string {
34+
return `socket/fix/${ghsaId}`
35+
}
36+
37+
export function getSocketFixBranchPattern(ghsaId?: string | undefined): RegExp {
38+
return new RegExp(`^socket/fix/(${ghsaId ?? '.+'})$`)
39+
}
40+
41+
export function getSocketFixCommitMessage(
42+
ghsaId: string,
43+
details?: GhsaDetails | undefined,
44+
): string {
45+
const summary = details?.summary
46+
return `fix: ${ghsaId}${summary ? ` - ${summary}` : ''}`
47+
}
48+
49+
export function getSocketFixPullRequestBody(
50+
ghsaIds: string[],
51+
ghsaDetails?: Map<string, GhsaDetails>,
52+
): string {
53+
const vulnCount = ghsaIds.length
54+
if (vulnCount === 1) {
55+
const ghsaId = ghsaIds[0]!
56+
const details = ghsaDetails?.get(ghsaId)
57+
const body = `[Socket](${constants.SOCKET_WEBSITE_URL}) fix for [${ghsaId}](${GITHUB_ADVISORIES_URL}/${ghsaId}).`
58+
if (!details) {
59+
return body
60+
}
61+
const packages = details.vulnerabilities.nodes.map(
62+
v => `${v.package.name} (${v.package.ecosystem})`,
63+
)
64+
return [
65+
body,
66+
'',
67+
'',
68+
`**Vulnerability Summary:** ${details.summary}`,
69+
'',
70+
`**Severity:** ${details.severity}`,
71+
'',
72+
`**Affected Packages:** ${joinAnd(packages)}`,
73+
].join('\n')
74+
}
75+
return [
76+
`[Socket](${constants.SOCKET_WEBSITE_URL}) fixes for ${vulnCount} GHSAs.`,
77+
'',
78+
'**Fixed Vulnerabilities:**',
79+
...ghsaIds.map(id => {
80+
const details = ghsaDetails?.get(id)
81+
const item = `- [${id}](${GITHUB_ADVISORIES_URL}/${id})`
82+
if (details) {
83+
const packages = details.vulnerabilities.nodes.map(
84+
v => `${v.package.name}`,
85+
)
86+
return `${item} - ${details.summary} (${joinAnd(packages)})`
87+
}
88+
return item
89+
}),
90+
].join('\n')
91+
}
92+
93+
export function getSocketFixPullRequestTitle(ghsaIds: string[]): string {
94+
const vulnCount = ghsaIds.length
95+
return vulnCount === 1
96+
? `Fix for ${ghsaIds[0]}`
97+
: `Fixes for ${vulnCount} GHSAs`
98+
}

0 commit comments

Comments
 (0)