Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
"@socketsecurity/config": "3.0.1",
"@socketsecurity/registry": "1.1.17",
"@socketsecurity/sdk": "1.4.95",
"@socketsecurity/socket-patch": "1.0.0",
"@types/blessed": "0.1.25",
"@types/cmd-shim": "5.0.2",
"@types/js-yaml": "4.0.9",
Expand Down
13 changes: 13 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

143 changes: 31 additions & 112 deletions src/commands/patch/cmd-patch.mts
Original file line number Diff line number Diff line change
@@ -1,34 +1,13 @@
import { existsSync } from 'node:fs'
import path from 'node:path'
import constants from '../../constants.mts'
import { runPatch } from '@socketsecurity/socket-patch/run'

import { arrayUnique } from '@socketsecurity/registry/lib/arrays'

import { handlePatch } from './handle-patch.mts'
import constants, { DOT_SOCKET_DIR, MANIFEST_JSON } from '../../constants.mts'
import { commonFlags, outputFlags } from '../../flags.mts'
import { checkCommandInput } from '../../utils/check-input.mts'
import { cmdFlagValueToArray } from '../../utils/cmd.mts'
import { InputError } from '../../utils/errors.mts'
import { getOutputKind } from '../../utils/get-output-kind.mts'
import { meowOrExit } from '../../utils/meow-with-subcommands.mts'
import {
getFlagApiRequirementsOutput,
getFlagListOutput,
} from '../../utils/output-formatting.mts'
import { getPurlObject } from '../../utils/purl.mts'

import type {
CliCommandConfig,
CliCommandContext,
} from '../../utils/meow-with-subcommands.mts'
import type { PurlObject } from '../../utils/purl.mts'
import type { PackageURL } from '@socketregistry/packageurl-js'
import type { CliCommandContext } from '../../utils/meow-with-subcommands.mts'

export const CMD_NAME = 'patch'

const description = 'Apply CVE patches to dependencies'
const description = 'Manage CVE patches for dependencies'

const hidden = true
const hidden = false

export const cmdPatch = {
description,
Expand All @@ -38,100 +17,40 @@ export const cmdPatch = {

async function run(
argv: string[] | readonly string[],
importMeta: ImportMeta,
{ parentName }: CliCommandContext,
_importMeta: ImportMeta,
_context: CliCommandContext,
): Promise<void> {
const config: CliCommandConfig = {
commandName: CMD_NAME,
description,
hidden,
flags: {
...commonFlags,
...outputFlags,
purl: {
type: 'string',
default: [],
description:
'Specify purls to patch, as either a comma separated value or as multiple flags',
isMultiple: true,
shortFlag: 'p',
},
},
help: (command, config) => `
Usage
$ ${command} [options] [CWD=.]
const { ENV } = constants

API Token Requirements
${getFlagApiRequirementsOutput(`${parentName}:${CMD_NAME}`)}
// Map socket-cli environment to socket-patch options.
// Only include properties with defined values (exactOptionalPropertyTypes).
const options: Parameters<typeof runPatch>[1] = {}

Options
${getFlagListOutput(config.flags)}

Examples
$ ${command}
$ ${command} --package lodash
$ ${command} ./path/to/project --package lodash,react
`,
// Strip /v0/ suffix from API URL if present.
const apiUrl = ENV.SOCKET_CLI_API_BASE_URL?.replace(/\/v0\/?$/, '')
if (apiUrl) {
options.apiUrl = apiUrl
}

const cli = meowOrExit(
{
argv,
config,
parentName,
importMeta,
},
{ allowUnknownFlags: false },
)

const { dryRun, json, markdown } = cli.flags as {
dryRun: boolean
json: boolean
markdown: boolean
if (ENV.SOCKET_CLI_API_TOKEN) {
options.apiToken = ENV.SOCKET_CLI_API_TOKEN
}

const outputKind = getOutputKind(json, markdown)

const wasValidInput = checkCommandInput(outputKind, {
nook: true,
test: !json || !markdown,
message: 'The json and markdown flags cannot be both set, pick one',
fail: 'omit one',
})
if (!wasValidInput) {
return
if (ENV.SOCKET_CLI_ORG_SLUG) {
options.orgSlug = ENV.SOCKET_CLI_ORG_SLUG
}

let [cwd = '.'] = cli.input
// Note: path.resolve vs .join:
// If given path is absolute then cwd should not affect it.
cwd = path.resolve(process.cwd(), cwd)

const dotSocketDirPath = path.join(cwd, DOT_SOCKET_DIR)
if (!existsSync(dotSocketDirPath)) {
throw new InputError(
`No ${DOT_SOCKET_DIR} directory found in current directory`,
)
if (ENV.SOCKET_PATCH_PROXY_URL) {
options.patchProxyUrl = ENV.SOCKET_PATCH_PROXY_URL
}

const manifestPath = path.join(dotSocketDirPath, MANIFEST_JSON)
if (!existsSync(manifestPath)) {
throw new InputError(
`No ${MANIFEST_JSON} found in ${DOT_SOCKET_DIR} directory`,
)
if (ENV.SOCKET_CLI_API_PROXY) {
options.httpProxy = ENV.SOCKET_CLI_API_PROXY
}
if (ENV.SOCKET_CLI_DEBUG) {
options.debug = ENV.SOCKET_CLI_DEBUG
}

const { spinner } = constants

const purlObjs = arrayUnique(cmdFlagValueToArray(cli.flags['purl']))
.map(p => getPurlObject(p, { throws: false }))
.filter(Boolean) as Array<PurlObject<PackageURL>>
// Forward all arguments to socket-patch.
const exitCode = await runPatch([...argv], options)

await handlePatch({
cwd,
dryRun,
outputKind,
purlObjs,
spinner,
})
if (exitCode !== 0) {
process.exitCode = exitCode
}
}
Loading