socket 0.14.111 → 0.14.113
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module-sync/cli.js +62 -63
- package/dist/module-sync/cli.js.map +1 -1
- package/dist/module-sync/shadow-npm-inject.js +3 -2
- package/dist/module-sync/shadow-npm-inject.js.map +1 -1
- package/dist/require/cli.js +62 -63
- package/dist/require/cli.js.map +1 -1
- package/dist/require/shadow-npm-inject.js +3 -2
- package/dist/require/shadow-npm-inject.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sources":["../../src/utils/fail-msg-with-badge.ts","../../src/utils/api.ts","../../src/commands/analytics/fetch-org-analytics.ts","../../src/commands/analytics/fetch-repo-analytics.ts","../../src/utils/markdown.ts","../../src/commands/analytics/display-analytics.ts","../../src/flags.ts","../../src/utils/handle-bad-input.ts","../../src/utils/output-formatting.ts","../../src/utils/meow-with-subcommands.ts","../../src/commands/analytics/cmd-analytics.ts","../../src/commands/audit-log/fetch-audit-log.ts","../../src/commands/audit-log/output-audit-log.ts","../../src/commands/audit-log/handle-audit-log.ts","../../src/commands/audit-log/cmd-audit-log.ts","../../src/commands/cdxgen/run-cyclonedx.ts","../../src/utils/cmd.ts","../../src/commands/cdxgen/cmd-cdxgen.ts","../../src/commands/ci/fetch-default-org-slug.ts","../../src/commands/scan/fetch-create-org-full-scan.ts","../../src/commands/scan/fetch-supported-scan-file-names.ts","../../src/commands/scan/fetch-report-data.ts","../../src/commands/scan/generate-report.ts","../../src/utils/map-to-object.ts","../../src/utils/walk-nested-map.ts","../../src/commands/scan/output-scan-report.ts","../../src/commands/scan/handle-scan-report.ts","../../src/commands/scan/output-create-new-scan.ts","../../src/commands/scan/handle-create-new-scan.ts","../../src/commands/ci/handle-ci.ts","../../src/commands/ci/cmd-ci.ts","../../src/commands/config/discover-config-value.ts","../../src/commands/config/output-config-auto.ts","../../src/commands/config/handle-config-auto.ts","../../src/commands/config/cmd-config-auto.ts","../../src/commands/config/output-config-get.ts","../../src/commands/config/handle-config-get.ts","../../src/commands/config/cmd-config-get.ts","../../src/commands/config/output-config-list.ts","../../src/commands/config/cmd-config-list.ts","../../src/commands/config/output-config-set.ts","../../src/commands/config/handle-config-set.ts","../../src/commands/config/cmd-config-set.ts","../../src/commands/config/output-config-unset.ts","../../src/commands/config/handle-config-unset.ts","../../src/commands/config/cmd-config-unset.ts","../../src/commands/config/cmd-config.ts","../../src/commands/dependencies/fetch-dependencies.ts","../../src/commands/dependencies/output-dependencies.ts","../../src/commands/dependencies/handle-dependencies.ts","../../src/commands/dependencies/cmd-dependencies.ts","../../src/commands/diff-scan/fetch-diff-scan.ts","../../src/commands/diff-scan/output-diff-scan.ts","../../src/commands/diff-scan/handle-diff-scan.ts","../../src/commands/diff-scan/cmd-diff-scan-get.ts","../../src/commands/diff-scan/cmd-diff-scan.ts","../../src/commands/fix/git.ts","../../src/commands/fix/open-pr.ts","../../src/commands/fix/npm-fix.ts","../../src/utils/npm.ts","../../src/utils/agent.ts","../../src/commands/fix/pnpm-fix.ts","../../src/commands/fix/shared.ts","../../src/utils/package-environment.ts","../../src/commands/fix/run-fix.ts","../../src/commands/fix/cmd-fix.ts","../../src/commands/info/fetch-package-info.ts","../../src/commands/info/output-package-info.ts","../../src/commands/info/handle-package-info.ts","../../src/commands/info/cmd-info.ts","../../src/commands/login/apply-login.ts","../../src/commands/login/attempt-login.ts","../../src/commands/login/cmd-login.ts","../../src/commands/logout/apply-logout.ts","../../src/commands/logout/attempt-logout.ts","../../src/commands/logout/cmd-logout.ts","../../src/commands/manifest/convert-conda-to-requirements.ts","../../src/commands/manifest/output-requirements.ts","../../src/commands/manifest/handle-manifest-conda.ts","../../src/commands/manifest/cmd-manifest-conda.ts","../../src/commands/manifest/convert_gradle_to_maven.ts","../../src/commands/manifest/cmd-manifest-gradle.ts","../../src/commands/manifest/convert_sbt_to_maven.ts","../../src/commands/manifest/cmd-manifest-scala.ts","../../src/commands/manifest/cmd-manifest-auto.ts","../../src/commands/manifest/cmd-manifest-kotlin.ts","../../src/commands/manifest/cmd-manifest.ts","../../src/commands/npm/wrap-npm.ts","../../src/commands/npm/cmd-npm.ts","../../src/commands/npx/wrap-npx.ts","../../src/commands/npx/cmd-npx.ts","../../src/commands/oops/cmd-oops.ts","../../src/commands/optimize/deps-includes-by-agent.ts","../../src/commands/optimize/get-dependency-entries.ts","../../src/commands/optimize/get-overrides-by-agent.ts","../../src/commands/optimize/lockfile-includes-by-agent.ts","../../src/commands/optimize/ls-by-agent.ts","../../src/commands/optimize/shared.ts","../../src/commands/optimize/update-manifest-by-agent.ts","../../src/commands/optimize/add-overrides.ts","../../src/commands/optimize/update-lockfile.ts","../../src/commands/optimize/apply-optimization.ts","../../src/commands/optimize/cmd-optimize.ts","../../src/commands/organization/fetch-organization-list.ts","../../src/commands/organization/output-organization-list.ts","../../src/commands/organization/handle-organization-list.ts","../../src/commands/organization/cmd-organization-list.ts","../../src/commands/organization/fetch-license-policy.ts","../../src/commands/organization/output-license-policy.ts","../../src/commands/organization/handle-license-policy.ts","../../src/commands/organization/cmd-organization-policy-license.ts","../../src/commands/organization/fetch-security-policy.ts","../../src/commands/organization/output-security-policy.ts","../../src/commands/organization/handle-security-policy.ts","../../src/commands/organization/cmd-organization-policy-security.ts","../../src/commands/organization/cmd-organization-policy.ts","../../src/commands/organization/fetch-quota.ts","../../src/commands/organization/output-quota.ts","../../src/commands/organization/handle-quota.ts","../../src/commands/organization/cmd-organization-quota.ts","../../src/commands/organization/cmd-organization.ts","../../src/commands/package/fetch-purl-deep-score.ts","../../src/commands/package/output-purl-score.ts","../../src/commands/package/handle-purl-deep-score.ts","../../src/commands/package/parse-package-specifiers.ts","../../src/commands/package/cmd-package-score.ts","../../src/commands/package/fetch-purls-shallow-score.ts","../../src/commands/package/output-purls-shallow-score.ts","../../src/commands/package/handle-purls-shallow-score.ts","../../src/commands/package/cmd-package-shallow.ts","../../src/commands/package/cmd-package.ts","../../src/commands/raw-npm/run-raw-npm.ts","../../src/commands/raw-npm/cmd-raw-npm.ts","../../src/commands/raw-npx/run-raw-npx.ts","../../src/commands/raw-npx/cmd-raw-npx.ts","../../src/commands/report/cmd-report-create.ts","../../src/commands/report/cmd-report-view.ts","../../src/commands/report/cmd-report.ts","../../src/commands/repos/fetch-create-repo.ts","../../src/commands/repos/output-create-repo.ts","../../src/commands/repos/handle-create-repo.ts","../../src/commands/repos/cmd-repos-create.ts","../../src/commands/repos/handle-delete-repo.ts","../../src/commands/repos/cmd-repos-del.ts","../../src/commands/repos/fetch-list-repos.ts","../../src/commands/repos/output-list-repos.ts","../../src/commands/repos/handle-list-repos.ts","../../src/commands/repos/cmd-repos-list.ts","../../src/commands/repos/fetch-update-repo.ts","../../src/commands/repos/output-update-repo.ts","../../src/commands/repos/handle-update-repo.ts","../../src/commands/repos/cmd-repos-update.ts","../../src/commands/repos/fetch-view-repo.ts","../../src/commands/repos/output-view-repo.ts","../../src/commands/repos/handle-view-repo.ts","../../src/commands/repos/cmd-repos-view.ts","../../src/commands/repos/cmd-repos.ts","../../src/commands/scan/suggest-org-slug.ts","../../src/commands/scan/suggest_target.ts","../../src/commands/scan/cmd-scan-create.ts","../../src/commands/scan/fetch-delete-org-full-scan.ts","../../src/commands/scan/output-delete-scan.ts","../../src/commands/scan/handle-delete-scan.ts","../../src/commands/scan/cmd-scan-del.ts","../../src/commands/scan/fetch-diff-scan.ts","../../src/commands/scan/output-diff-scan.ts","../../src/commands/scan/handle-diff-scan.ts","../../src/commands/scan/cmd-scan-diff.ts","../../src/commands/scan/fetch-list-scans.ts","../../src/commands/scan/output-list-scans.ts","../../src/commands/scan/handle-list-scans.ts","../../src/commands/scan/cmd-scan-list.ts","../../src/commands/scan/fetch-scan-metadata.ts","../../src/commands/scan/output-scan-metadata.ts","../../src/commands/scan/handle-scan-metadata.ts","../../src/commands/scan/cmd-scan-metadata.ts","../../src/commands/scan/cmd-scan-report.ts","../../src/commands/scan/fetch-scan.ts","../../src/commands/scan/output-scan-view.ts","../../src/commands/scan/handle-scan-view.ts","../../src/commands/scan/streamScan.ts","../../src/commands/scan/cmd-scan-view.ts","../../src/commands/scan/cmd-scan.ts","../../src/commands/threat-feed/fetch-threat-feed.ts","../../src/commands/threat-feed/output-threat-feed.ts","../../src/commands/threat-feed/handle-threat-feed.ts","../../src/commands/threat-feed/cmd-threat-feed.ts","../../src/commands/wrapper/add-socket-wrapper.ts","../../src/commands/wrapper/check-socket-wrapper-setup.ts","../../src/commands/wrapper/postinstall-wrapper.ts","../../src/commands/wrapper/remove-socket-wrapper.ts","../../src/commands/wrapper/cmd-wrapper.ts","../../src/cli.ts"],"sourcesContent":["import colors from 'yoctocolors-cjs'\n\nexport function failMsgWithBadge(badge: string, msg: string): string {\n return `${colors.bgRed(colors.bold(colors.white(` ${badge}: `)))} ${colors.bold(msg)}`\n}\n","import process from 'node:process'\n\nimport { debugLog } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { isNonEmptyString } from '@socketsecurity/registry/lib/strings'\n\nimport { getConfigValue } from './config'\nimport { AuthError } from './errors'\nimport constants from '../constants'\nimport { failMsgWithBadge } from './fail-msg-with-badge'\n\nimport type {\n SocketSdkErrorType,\n SocketSdkOperations\n} from '@socketsecurity/sdk'\n\nexport function handleUnsuccessfulApiResponse<T extends SocketSdkOperations>(\n _name: T,\n sockSdkError: SocketSdkErrorType<T>\n): never {\n const message = sockSdkError.error || 'No error message returned'\n const { status } = sockSdkError\n if (status === 401 || status === 403) {\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.stop()\n\n throw new AuthError(message)\n }\n logger.fail(failMsgWithBadge('Socket API returned an error', message))\n // eslint-disable-next-line n/no-process-exit\n process.exit(1)\n}\n\nexport async function handleApiCall<T>(\n value: T,\n description: string\n): Promise<T> {\n let result: T\n try {\n result = await value\n } catch (e) {\n debugLog(`handleApiCall[${description}] error:\\n`, e)\n throw new Error(`Failed ${description}`, { cause: e })\n }\n return result\n}\n\nexport async function handleApiError(code: number) {\n if (code === 400) {\n return 'One of the options passed might be incorrect'\n }\n if (code === 403) {\n return 'Your API token may not have the required permissions for this command or you might be trying to access (data from) an organization that is not linked to the API key you are logged in with'\n }\n if (code === 404) {\n return 'The requested Socket API endpoint was not found (404) or there was no result for the requested parameters. This could be a temporary problem caused by an incident or a bug in the CLI. If the problem persists please let us know.'\n }\n return `Server responded with status code ${code}`\n}\n\nexport function getLastFiveOfApiToken(token: string): string {\n // Get the last 5 characters of the API token before the trailing \"_api\".\n return token.slice(-9, -4)\n}\n\n// The API server that should be used for operations.\nexport function getDefaultApiBaseUrl(): string | undefined {\n const baseUrl =\n process.env['SOCKET_SECURITY_API_BASE_URL'] || getConfigValue('apiBaseUrl')\n if (isNonEmptyString(baseUrl)) {\n return baseUrl\n }\n // Lazily access constants.API_V0_URL.\n const API_V0_URL = constants.API_V0_URL\n return API_V0_URL\n}\n\nexport async function queryApi(path: string, apiToken: string) {\n const API_V0_URL = getDefaultApiBaseUrl() || ''\n if (!API_V0_URL) {\n logger.warn(\n 'API endpoint is not set and default was empty. Request is likely to fail.'\n )\n }\n return await fetch(\n `${API_V0_URL}${API_V0_URL.endsWith('/') ? '' : '/'}${path}`,\n {\n method: 'GET',\n headers: {\n Authorization: `Basic ${btoa(`${apiToken}:`)}`\n }\n }\n )\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { Spinner } from '@socketsecurity/registry/lib/spinner'\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchOrgAnalyticsData(\n time: number,\n spinner: Spinner\n): Promise<SocketSdkReturnType<'getOrgAnalytics'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n const result = await handleApiCall(\n sockSdk.getOrgAnalytics(time.toString()),\n 'fetching analytics data'\n )\n\n if (result.success === false) {\n handleUnsuccessfulApiResponse('getOrgAnalytics', result)\n }\n\n spinner.stop()\n\n if (!result.data.length) {\n logger.log('No analytics data is available for this organization yet.')\n return\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { Spinner } from '@socketsecurity/registry/lib/spinner'\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchRepoAnalyticsData(\n repo: string,\n time: number,\n spinner: Spinner\n): Promise<SocketSdkReturnType<'getRepoAnalytics'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n const result = await handleApiCall(\n sockSdk.getRepoAnalytics(repo, time.toString()),\n 'fetching analytics data'\n )\n\n if (result.success === false) {\n handleUnsuccessfulApiResponse('getRepoAnalytics', result)\n }\n\n spinner.stop()\n\n if (!result.data.length) {\n logger.log('No analytics data is available for this organization yet.')\n return\n }\n\n return result.data\n}\n","export function mdTableStringNumber(\n title1: string,\n title2: string,\n obj: Record<string, number | string>\n): string {\n // | Date | Counts |\n // | ----------- | ------ |\n // | Header | 201464 |\n // | Paragraph | 18 |\n let mw1 = title1.length\n let mw2 = title2.length\n for (const [key, value] of Object.entries(obj)) {\n mw1 = Math.max(mw1, key.length)\n mw2 = Math.max(mw2, String(value ?? '').length)\n }\n\n const lines = []\n lines.push(`| ${title1.padEnd(mw1, ' ')} | ${title2.padEnd(mw2)} |`)\n lines.push(`| ${'-'.repeat(mw1)} | ${'-'.repeat(mw2)} |`)\n for (const [key, value] of Object.entries(obj)) {\n lines.push(\n `| ${key.padEnd(mw1, ' ')} | ${String(value ?? '').padStart(mw2, ' ')} |`\n )\n }\n lines.push(`| ${'-'.repeat(mw1)} | ${'-'.repeat(mw2)} |`)\n\n return lines.join('\\n')\n}\n\nexport function mdTable<T extends Array<Record<string, string>>>(\n logs: T,\n // This is saying \"an array of strings and the strings are a valid key of elements of T\"\n // In turn, T is defined above as the audit log event type from our OpenAPI docs.\n cols: Array<string & keyof T[number]>,\n titles: string[] = cols\n): string {\n // Max col width required to fit all data in that column\n const cws = cols.map(col => col.length)\n\n for (const log of logs) {\n for (let i = 0, { length } = cols; i < length; i += 1) {\n // @ts-ignore\n const val: unknown = log[cols[i] ?? ''] ?? ''\n cws[i] = Math.max(\n cws[i] ?? 0,\n String(val).length,\n (titles[i] || '').length\n )\n }\n }\n\n let div = '|'\n for (const cw of cws) {\n div += ' ' + '-'.repeat(cw) + ' |'\n }\n\n let header = '|'\n for (let i = 0, { length } = titles; i < length; i += 1) {\n header += ' ' + String(titles[i]).padEnd(cws[i] ?? 0, ' ') + ' |'\n }\n\n let body = ''\n for (const log of logs) {\n body += '|'\n for (let i = 0, { length } = cols; i < length; i += 1) {\n // @ts-ignore\n const val: unknown = log[cols[i] ?? ''] ?? ''\n body += ' ' + String(val).padEnd(cws[i] ?? 0, ' ') + ' |'\n }\n body += '\\n'\n }\n\n return [div, header, div, body.trim(), div].filter(s => !!s.trim()).join('\\n')\n}\n\nexport function mdTableOfPairs(\n arr: Array<[string, string]>,\n // This is saying \"an array of strings and the strings are a valid key of elements of T\"\n // In turn, T is defined above as the audit log event type from our OpenAPI docs.\n cols: string[]\n): string {\n // Max col width required to fit all data in that column\n const cws = cols.map(col => col.length)\n\n for (const [key, val] of arr) {\n cws[0] = Math.max(cws[0] ?? 0, String(key).length)\n cws[1] = Math.max(cws[1] ?? 0, String(val ?? '').length)\n }\n\n let div = '|'\n for (const cw of cws) {\n div += ' ' + '-'.repeat(cw) + ' |'\n }\n\n let header = '|'\n for (let i = 0, { length } = cols; i < length; i += 1) {\n header += ' ' + String(cols[i]).padEnd(cws[i] ?? 0, ' ') + ' |'\n }\n\n let body = ''\n for (const [key, val] of arr) {\n body += '|'\n body += ' ' + String(key).padEnd(cws[0] ?? 0, ' ') + ' |'\n body += ' ' + String(val ?? '').padEnd(cws[1] ?? 0, ' ') + ' |'\n body += '\\n'\n }\n\n return [div, header, div, body.trim(), div].filter(s => !!s.trim()).join('\\n')\n}\n","import fs from 'node:fs/promises'\n\nimport { codeBlock } from 'common-tags'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { fetchOrgAnalyticsData } from './fetch-org-analytics'\nimport { fetchRepoAnalyticsData } from './fetch-repo-analytics'\nimport constants from '../../constants'\nimport { mdTableStringNumber } from '../../utils/markdown'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\nimport type { Widgets } from 'blessed' // Note: Widgets does not seem to actually work as code :'(\nimport type { grid as ContribGrid } from 'blessed-contrib'\n\ninterface FormattedData {\n top_five_alert_types: Record<string, number>\n total_critical_alerts: Record<string, number>\n total_high_alerts: Record<string, number>\n total_medium_alerts: Record<string, number>\n total_low_alerts: Record<string, number>\n total_critical_added: Record<string, number>\n total_medium_added: Record<string, number>\n total_low_added: Record<string, number>\n total_high_added: Record<string, number>\n total_critical_prevented: Record<string, number>\n total_high_prevented: Record<string, number>\n total_medium_prevented: Record<string, number>\n total_low_prevented: Record<string, number>\n}\n\nconst METRICS = [\n 'total_critical_alerts',\n 'total_high_alerts',\n 'total_medium_alerts',\n 'total_low_alerts',\n 'total_critical_added',\n 'total_medium_added',\n 'total_low_added',\n 'total_high_added',\n 'total_critical_prevented',\n 'total_high_prevented',\n 'total_medium_prevented',\n 'total_low_prevented'\n] as const\n\n// Note: This maps `new Date(date).getMonth()` to English three letters\nconst Months = [\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'May',\n 'Jun',\n 'Jul',\n 'Aug',\n 'Sep',\n 'Oct',\n 'Nov',\n 'Dec'\n] as const\n\nexport async function displayAnalytics({\n filePath,\n outputKind,\n repo,\n scope,\n time\n}: {\n scope: string\n time: number\n repo: string\n outputKind: 'json' | 'markdown' | 'print'\n filePath: string\n}): Promise<void> {\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching analytics data')\n\n let data:\n | undefined\n | SocketSdkReturnType<'getOrgAnalytics'>['data']\n | SocketSdkReturnType<'getRepoAnalytics'>['data']\n if (scope === 'org') {\n data = await fetchOrgAnalyticsData(time, spinner)\n } else if (repo) {\n data = await fetchRepoAnalyticsData(repo, time, spinner)\n }\n\n // A message should already have been printed if we have no data here\n if (!data) {\n return\n }\n\n if (outputKind === 'json') {\n const serialized = renderJson(data)\n if (!serialized) {\n return\n }\n\n if (filePath && filePath !== '-') {\n try {\n await fs.writeFile(filePath, serialized, 'utf8')\n logger.log(`Data successfully written to ${filePath}`)\n } catch (e) {\n process.exitCode = 1\n logger.fail('There was an error trying to write the json to disk')\n logger.error(e)\n }\n } else {\n logger.log(serialized)\n }\n } else {\n const fdata = scope === 'org' ? formatDataOrg(data) : formatDataRepo(data)\n\n if (outputKind === 'markdown') {\n const serialized = renderMarkdown(fdata, time, repo)\n\n if (filePath && filePath !== '-') {\n try {\n await fs.writeFile(filePath, serialized, 'utf8')\n logger.log(`Data successfully written to ${filePath}`)\n } catch (e) {\n logger.error(e)\n }\n } else {\n logger.log(serialized)\n }\n } else {\n displayAnalyticsScreen(fdata)\n }\n }\n}\n\nfunction renderJson(data: unknown): string | undefined {\n try {\n return JSON.stringify(data, null, 2)\n } catch (e) {\n process.exitCode = 1\n // This could be caused by circular references, which is an \"us\" problem\n logger.fail(\n 'There was a problem converting the data set to JSON. Please try without --json or with --markdown'\n )\n return\n }\n}\n\nfunction renderMarkdown(\n data: FormattedData,\n days: number,\n repoSlug: string\n): string {\n return codeBlock`\n# Socket Alert Analytics\n\nThese are the Socket.dev stats are analytics for the ${repoSlug ? `${repoSlug} repo` : 'org'} of the past ${days} days\n\n${[\n [\n 'Total critical alerts',\n mdTableStringNumber('Date', 'Counts', data['total_critical_alerts'])\n ],\n [\n 'Total high alerts',\n mdTableStringNumber('Date', 'Counts', data['total_high_alerts'])\n ],\n [\n 'Total critical alerts added to the main branch',\n mdTableStringNumber('Date', 'Counts', data['total_critical_added'])\n ],\n [\n 'Total high alerts added to the main branch',\n mdTableStringNumber('Date', 'Counts', data['total_high_added'])\n ],\n [\n 'Total critical alerts prevented from the main branch',\n mdTableStringNumber('Date', 'Counts', data['total_critical_prevented'])\n ],\n [\n 'Total high alerts prevented from the main branch',\n mdTableStringNumber('Date', 'Counts', data['total_high_prevented'])\n ],\n [\n 'Total medium alerts prevented from the main branch',\n mdTableStringNumber('Date', 'Counts', data['total_medium_prevented'])\n ],\n [\n 'Total low alerts prevented from the main branch',\n mdTableStringNumber('Date', 'Counts', data['total_low_prevented'])\n ]\n]\n .map(\n ([title, table]) =>\n codeBlock`\n## ${title}\n\n${table}\n`\n )\n .join('\\n\\n')}\n\n## Top 5 alert types\n\n${mdTableStringNumber('Name', 'Counts', data['top_five_alert_types'])}\n`\n}\n\nfunction displayAnalyticsScreen(data: FormattedData): void {\n const ScreenWidget = require('blessed/lib/widgets/screen')\n // Lazily access constants.blessedOptions.\n const screen: Widgets.Screen = new ScreenWidget({\n ...constants.blessedOptions\n })\n const contrib = require('blessed-contrib')\n const grid = new contrib.grid({ rows: 5, cols: 4, screen })\n\n renderLineCharts(\n grid,\n screen,\n 'Total critical alerts',\n [0, 0, 1, 2],\n data['total_critical_alerts']\n )\n renderLineCharts(\n grid,\n screen,\n 'Total high alerts',\n [0, 2, 1, 2],\n data['total_high_alerts']\n )\n renderLineCharts(\n grid,\n screen,\n 'Total critical alerts added to the main branch',\n [1, 0, 1, 2],\n data['total_critical_added']\n )\n renderLineCharts(\n grid,\n screen,\n 'Total high alerts added to the main branch',\n [1, 2, 1, 2],\n data['total_high_added']\n )\n renderLineCharts(\n grid,\n screen,\n 'Total critical alerts prevented from the main branch',\n [2, 0, 1, 2],\n data['total_critical_prevented']\n )\n renderLineCharts(\n grid,\n screen,\n 'Total high alerts prevented from the main branch',\n [2, 2, 1, 2],\n data['total_high_prevented']\n )\n renderLineCharts(\n grid,\n screen,\n 'Total medium alerts prevented from the main branch',\n [3, 0, 1, 2],\n data['total_medium_prevented']\n )\n renderLineCharts(\n grid,\n screen,\n 'Total low alerts prevented from the main branch',\n [3, 2, 1, 2],\n data['total_low_prevented']\n )\n\n const bar = grid.set(4, 0, 1, 2, contrib.bar, {\n label: 'Top 5 alert types',\n barWidth: 10,\n barSpacing: 17,\n xOffset: 0,\n maxHeight: 9,\n barBgColor: 'magenta'\n })\n\n screen.append(bar) //must append before setting data\n\n bar.setData({\n titles: Object.keys(data.top_five_alert_types),\n data: Object.values(data.top_five_alert_types)\n })\n\n screen.render()\n // eslint-disable-next-line n/no-process-exit\n screen.key(['escape', 'q', 'C-c'], () => process.exit(0))\n}\n\nfunction formatDataRepo(\n data: SocketSdkReturnType<'getRepoAnalytics'>['data']\n): FormattedData {\n const sortedTopFiveAlerts: Record<string, number> = {}\n const totalTopAlerts: Record<string, number> = {}\n\n const formattedData = {} as Omit<FormattedData, 'top_five_alert_types'>\n for (const metric of METRICS) {\n formattedData[metric] = {}\n }\n\n for (const entry of data) {\n const topFiveAlertTypes = entry['top_five_alert_types']\n for (const type of Object.keys(topFiveAlertTypes)) {\n const count = topFiveAlertTypes[type] ?? 0\n if (!totalTopAlerts[type]) {\n totalTopAlerts[type] = count\n } else if (count > (totalTopAlerts[type] ?? 0)) {\n totalTopAlerts[type] = count\n }\n }\n }\n for (const entry of data) {\n for (const metric of METRICS) {\n formattedData[metric]![formatDate(entry['created_at'])] = entry[metric]\n }\n }\n\n const topFiveAlertEntries = Object.entries(totalTopAlerts)\n .sort(([_keya, a], [_keyb, b]) => b - a)\n .slice(0, 5)\n for (const [key, value] of topFiveAlertEntries) {\n sortedTopFiveAlerts[key] = value\n }\n\n return {\n ...formattedData,\n top_five_alert_types: sortedTopFiveAlerts\n }\n}\n\nfunction formatDataOrg(\n data: SocketSdkReturnType<'getOrgAnalytics'>['data']\n): FormattedData {\n const sortedTopFiveAlerts: Record<string, number> = {}\n const totalTopAlerts: Record<string, number> = {}\n\n const formattedData = {} as Omit<FormattedData, 'top_five_alert_types'>\n for (const metric of METRICS) {\n formattedData[metric] = {}\n }\n\n for (const entry of data) {\n const topFiveAlertTypes = entry['top_five_alert_types']\n for (const type of Object.keys(topFiveAlertTypes)) {\n const count = topFiveAlertTypes[type] ?? 0\n if (!totalTopAlerts[type]) {\n totalTopAlerts[type] = count\n } else {\n totalTopAlerts[type] += count\n }\n }\n }\n\n for (const metric of METRICS) {\n const formatted = formattedData[metric]\n for (const entry of data) {\n const date = formatDate(entry['created_at'])\n if (!formatted[date]) {\n formatted[date] = entry[metric]!\n } else {\n formatted[date] += entry[metric]!\n }\n }\n }\n\n const topFiveAlertEntries = Object.entries(totalTopAlerts)\n .sort(([_keya, a], [_keyb, b]) => b - a)\n .slice(0, 5)\n for (const [key, value] of topFiveAlertEntries) {\n sortedTopFiveAlerts[key] = value\n }\n\n return {\n ...formattedData,\n top_five_alert_types: sortedTopFiveAlerts\n }\n}\n\nfunction formatDate(date: string): string {\n return `${Months[new Date(date).getMonth()]} ${new Date(date).getDate()}`\n}\n\nfunction renderLineCharts(\n grid: ContribGrid,\n screen: Widgets.Screen,\n title: string,\n coords: number[],\n data: Record<string, number>\n): void {\n const contrib = require('blessed-contrib')\n const line = grid.set(...coords, contrib.line, {\n style: { line: 'cyan', text: 'cyan', baseline: 'black' },\n xLabelPadding: 0,\n xPadding: 0,\n xOffset: 0,\n wholeNumbersOnly: true,\n legend: {\n width: 1\n },\n label: title\n })\n\n screen.append(line)\n\n const lineData = {\n x: Object.keys(data),\n y: Object.values(data)\n }\n\n line.setData([lineData])\n}\n","import type { Flag } from 'meow'\n\n// TODO: not sure if I'm missing something but meow doesn't seem to expose this?\ntype StringFlag = Flag<'string', string> | Flag<'string', string[], true>\ntype BooleanFlag = Flag<'boolean', boolean> | Flag<'boolean', boolean[], true>\ntype NumberFlag = Flag<'number', number> | Flag<'number', number[], true>\ntype AnyFlag = StringFlag | BooleanFlag | NumberFlag\n\n// Note: we use this description in getFlagListOutput, meow doesn't care\nexport type MeowFlags = Record<\n string,\n AnyFlag & { description: string; hidden?: boolean }\n>\n\nexport const commonFlags: MeowFlags = {\n config: {\n type: 'string',\n default: '',\n hidden: true,\n description: 'Override the local config with this JSON'\n },\n dryRun: {\n type: 'boolean',\n default: false,\n hidden: true, // Only show in root command\n description: 'Do input validation for a command and exit 0 when input is ok'\n },\n help: {\n type: 'boolean',\n default: false,\n shortFlag: 'h',\n description: 'Print this help'\n },\n silent: {\n type: 'boolean',\n default: false,\n hidden: true,\n shortFlag: 's',\n description: 'Make the CLI less chatty'\n }\n}\n\nexport const outputFlags: MeowFlags = {\n json: {\n type: 'boolean',\n shortFlag: 'j',\n default: false,\n description: 'Output result as json'\n },\n markdown: {\n type: 'boolean',\n shortFlag: 'm',\n default: false,\n description: 'Output result as markdown'\n }\n}\n\nexport const validationFlags: MeowFlags = {\n all: {\n type: 'boolean',\n default: false,\n description: 'Include all issues'\n },\n strict: {\n type: 'boolean',\n default: false,\n description: 'Exits with an error code if any matching issues are found'\n }\n}\n","import colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { failMsgWithBadge } from './fail-msg-with-badge'\n\nexport function handleBadInput(\n ...checks: Array<{\n fail: string\n message: string\n pass: string\n test: boolean\n nook?: boolean | undefined\n }>\n) {\n if (checks.every(d => d.test)) {\n return false\n }\n\n const msg = [\n failMsgWithBadge(\n 'Input error',\n 'Please review the input requirements and try again'\n ),\n ''\n ]\n for (const d of checks) {\n // If nook, then ignore when test is ok\n if (d.nook && d.test) {\n continue\n }\n const lines = d.message.split('\\n')\n\n // If the message has newlines then format the first line with the input\n // expectation and teh rest indented below it\n msg.push(\n ` - ${lines[0]} (${d.test ? colors.green(d.pass) : colors.red(d.fail)})`\n )\n if (lines.length > 1) {\n msg.push(...lines.slice(1).map(str => ` ${str}`))\n }\n msg.push('')\n }\n\n logger.fail(msg.join('\\n'))\n\n // Use exit status of 2 to indicate incorrect usage, generally invalid\n // options or missing arguments.\n // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html\n process.exitCode = 2\n\n return true\n}\n","import type { MeowFlags } from '../flags'\n\ntype HelpListOptions = {\n keyPrefix: string\n padName: number\n}\n\ntype ListDescription =\n | { description: string }\n | { description: string; hidden: boolean }\n\nexport function getFlagListOutput(\n list: MeowFlags,\n indent: number,\n { keyPrefix = '--', padName } = {} as HelpListOptions\n): string {\n return getHelpListOutput(\n {\n ...list\n },\n indent,\n { keyPrefix, padName }\n )\n}\n\nexport function getHelpListOutput(\n list: Record<string, ListDescription>,\n indent: number,\n { keyPrefix = '', padName = 18 } = {} as HelpListOptions\n): string {\n let result = ''\n const names = Object.keys(list).sort()\n for (const name of names) {\n const entry = list[name]\n if (entry && 'hidden' in entry && entry?.hidden) {\n continue\n }\n const description =\n (typeof entry === 'object' ? entry.description : entry) || ''\n result +=\n ''.padEnd(indent) +\n (keyPrefix + name).padEnd(padName) +\n description +\n '\\n'\n }\n return result.trim() || '(none)'\n}\n","import path from 'node:path'\nimport process from 'node:process'\n\nimport meow from 'meow'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { toSortedObject } from '@socketsecurity/registry/lib/objects'\nimport { normalizePath } from '@socketsecurity/registry/lib/path'\nimport { escapeRegExp } from '@socketsecurity/registry/lib/regexps'\n\nimport { getLastFiveOfApiToken } from './api'\nimport {\n getConfigValue,\n isReadOnlyConfig,\n overrideCachedConfig,\n overrideConfigApiToken\n} from './config'\nimport { getFlagListOutput, getHelpListOutput } from './output-formatting'\nimport constants from '../constants'\nimport { MeowFlags, commonFlags } from '../flags'\nimport { getDefaultToken } from './sdk'\n\nimport type { Options } from 'meow'\n\nconst { DRY_RUN_LABEL, REDACTED } = constants\n\ninterface CliAlias {\n description: string\n argv: readonly string[]\n hidden?: boolean | undefined\n}\n\ntype CliAliases = Record<string, CliAlias>\n\ntype CliSubcommandRun = (\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n context: { parentName: string }\n) => Promise<void> | void\n\nexport interface CliSubcommand {\n description: string\n hidden?: boolean | undefined\n run: CliSubcommandRun\n}\n\n// Property names are picked such that the name is at the top when the props\n// get ordered by alphabet while flags is near the bottom and the help text\n// at the bottom, because they tend ot occupy the most lines of code.\nexport interface CliCommandConfig {\n commandName: string // tmp optional while we migrate\n description: string\n hidden: boolean\n flags: MeowFlags // tmp optional while we migrate\n help: (command: string, config: CliCommandConfig) => string\n}\n\ninterface MeowOptions extends Options<any> {\n aliases?: CliAliases | undefined\n argv: readonly string[]\n name: string\n // When no sub-command is given, default to this sub-command\n defaultSub?: string\n}\n\n// For debugging. Whenever you call meowOrExit it will store the command here\n// This module exports a getter that returns the current value.\nlet lastSeenCommand = ''\n\nexport function getLastSeenCommand(): string {\n return lastSeenCommand\n}\n\nexport async function meowWithSubcommands(\n subcommands: Record<string, CliSubcommand>,\n options: MeowOptions\n): Promise<void> {\n const {\n aliases = {},\n argv,\n defaultSub,\n importMeta,\n name,\n ...additionalOptions\n } = { __proto__: null, ...options }\n const [commandOrAliasName_, ...rawCommandArgv] = argv\n let commandOrAliasName = commandOrAliasName_\n if (!commandOrAliasName && defaultSub) {\n commandOrAliasName = defaultSub\n }\n\n const flags: MeowFlags = {\n ...commonFlags,\n ...additionalOptions.flags\n }\n\n // No further args or first arg is a flag (shrug)\n if (\n name === 'socket' &&\n (!commandOrAliasName || commandOrAliasName?.startsWith('-'))\n ) {\n flags['dryRun'] = {\n type: 'boolean',\n default: false,\n hidden: false, // Only show on root\n description:\n 'Do input validation for a command and exit 0 when input is ok. Every command should support this flag (not shown on help screens)'\n }\n }\n\n const cli = meow(\n `\n Usage\n $ ${name} <command>\n\n Commands\n ${getHelpListOutput(\n {\n ...toSortedObject(\n Object.fromEntries(\n Object.entries(subcommands).filter(\n ({ 1: subcommand }) => !subcommand.hidden\n )\n )\n ),\n ...toSortedObject(\n Object.fromEntries(\n Object.entries(aliases).filter(({ 1: alias }) => {\n const { hidden } = alias\n const cmdName = hidden ? '' : alias.argv[0]\n const subcommand = cmdName ? subcommands[cmdName] : undefined\n return subcommand && !subcommand.hidden\n })\n )\n )\n },\n 6\n )}\n\n Options\n ${getFlagListOutput(flags, 6)}\n\n Examples\n $ ${name} --help\n `,\n {\n argv,\n importMeta,\n ...additionalOptions,\n flags,\n // Do not strictly check for flags here.\n allowUnknownFlags: true,\n // We will emit help when we're ready\n // Plus, if we allow this then meow() can just exit here.\n autoHelp: false\n }\n )\n\n // Hard override the config if instructed to do so.\n // The env var overrides the --flag, which overrides the persisted config\n // Also, when either of these are used, config updates won't persist.\n let configOverrideResult\n if (process.env['SOCKET_CLI_CONFIG']) {\n configOverrideResult = overrideCachedConfig(\n process.env['SOCKET_CLI_CONFIG']\n )\n } else if (cli.flags['config']) {\n configOverrideResult = overrideCachedConfig(\n String(cli.flags['config'] || '')\n )\n }\n\n if (process.env['SOCKET_CLI_NO_API_TOKEN']) {\n // This overrides the config override and even the explicit token env var.\n // The config will be marked as readOnly to prevent persisting it.\n overrideConfigApiToken(undefined)\n } else {\n // Note: these are SOCKET_SECURITY prefixed because they're not specific to\n // the CLI. For the sake of consistency we'll also support the env\n // keys that do have the SOCKET_CLI prefix, it's an easy mistake.\n // In case multiple are supplied, the tokens supersede the keys and the\n // security prefix supersedes the cli prefix. \"Adventure mode\" ;)\n const tokenOverride =\n process.env['SOCKET_CLI_API_KEY'] ||\n process.env['SOCKET_SECURITY_API_KEY'] ||\n process.env['SOCKET_CLI_API_TOKEN'] ||\n process.env['SOCKET_SECURITY_API_TOKEN']\n if (tokenOverride) {\n // This will set the token (even if there was a config override) and\n // set it to readOnly, making sure the temp token won't be persisted.\n overrideConfigApiToken(tokenOverride)\n }\n }\n\n if (configOverrideResult?.ok === false) {\n emitBanner(name)\n logger.fail(configOverrideResult.message)\n process.exitCode = 2\n return\n }\n\n // If we got at least some args, then lets find out if we can find a command.\n if (commandOrAliasName) {\n const alias = aliases[commandOrAliasName]\n // First: Resolve argv data from alias if its an alias that's been given.\n const [commandName, ...commandArgv] = alias\n ? [...alias.argv, ...rawCommandArgv]\n : [commandOrAliasName, ...rawCommandArgv]\n // Second: Find a command definition using that data.\n const commandDefinition = commandName ? subcommands[commandName] : undefined\n // Third: If a valid command has been found, then we run it...\n if (commandDefinition) {\n return await commandDefinition.run(commandArgv, importMeta, {\n parentName: name\n })\n }\n }\n\n // ...else we provide basic instructions and help.\n if (!cli.flags['silent']) {\n emitBanner(name)\n }\n if (!cli.flags['help'] && cli.flags['dryRun']) {\n process.exitCode = 0\n logger.log(`${DRY_RUN_LABEL}: No-op, call a sub-command; ok`)\n } else {\n cli.showHelp()\n }\n}\n\n/**\n * Note: meow will exit immediately if it calls its .showHelp()\n */\nexport function meowOrExit({\n allowUnknownFlags, // commands that pass-through args need to allow this\n argv,\n config,\n importMeta,\n parentName\n}: {\n allowUnknownFlags?: boolean | undefined\n argv: readonly string[]\n config: CliCommandConfig\n parentName: string\n importMeta: ImportMeta\n}) {\n const command = `${parentName} ${config.commandName}`\n lastSeenCommand = command\n\n // This exits if .printHelp() is called either by meow itself or by us.\n const cli = meow({\n argv,\n description: config.description,\n help: config.help(command, config),\n importMeta,\n flags: config.flags,\n allowUnknownFlags: Boolean(allowUnknownFlags),\n autoHelp: false // otherwise we can't exit(0)\n })\n\n if (!cli.flags['silent']) {\n emitBanner(command)\n }\n if (cli.flags['help']) {\n cli.showHelp()\n }\n return cli\n}\n\nexport function emitBanner(name: string) {\n // Print a banner at the top of each command.\n // This helps with brand recognition and marketing.\n // It also helps with debugging since it contains version and command details.\n // Note: print over stderr to preserve stdout for flags like --json and\n // --markdown. If we don't do this, you can't use --json in particular\n // and pipe the result to other tools. By emitting the banner over stderr\n // you can do something like `socket scan view xyz | jq | process`.\n // The spinner also emits over stderr for example.\n logger.error(getAsciiHeader(name))\n}\n\nfunction getAsciiHeader(command: string) {\n // Note: In tests we return <redacted> because otherwise snapshots will fail.\n // The '@rollup/plugin-replace' will replace \"process.env['VITEST']\".\n const redacting = process.env['VITEST']\n const cliVersion = redacting\n ? REDACTED\n : // The '@rollup/plugin-replace' will replace \"process.env['INLINED_SOCKET_CLI_VERSION_HASH']\".\n process.env['INLINED_SOCKET_CLI_VERSION_HASH']\n const nodeVersion = redacting ? REDACTED : process.version\n const apiToken = getDefaultToken()\n const defaultOrg = getConfigValue('defaultOrg')\n const readOnlyConfig = isReadOnlyConfig() ? '*' : '.'\n const shownToken = redacting\n ? REDACTED\n : apiToken\n ? getLastFiveOfApiToken(apiToken)\n : 'no'\n const relCwd = redacting\n ? REDACTED\n : normalizePath(\n process\n .cwd()\n .replace(\n new RegExp(\n `^${escapeRegExp(constants.homePath)}(?:${path.sep}|$)`,\n 'i'\n ),\n '~/'\n )\n )\n const body = `\n _____ _ _ /---------------\n | __|___ ___| |_ ___| |_ | Socket.dev CLI ver ${cliVersion}\n |__ | ${readOnlyConfig} | _| '_| -_| _| | Node: ${nodeVersion}, API token set: ${shownToken}${defaultOrg ? `, default org: ${redacting ? REDACTED : defaultOrg}` : ''}\n |_____|___|___|_,_|___|_|.dev | Command: \\`${command}\\`, cwd: ${relCwd}`.trimStart()\n return ` ${body}\\n`\n}\n","import assert from 'node:assert'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { displayAnalytics } from './display-analytics'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'analytics',\n description: `Look up analytics data`,\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n file: {\n type: 'string',\n shortFlag: 'f',\n default: '-',\n description:\n 'Filepath to save output. Only valid with --json/--markdown. Defaults to stdout.'\n },\n repo: {\n type: 'string',\n shortFlag: 'r',\n default: '',\n description: 'Name of the repository. Only valid when scope=repo'\n },\n scope: {\n type: 'string',\n shortFlag: 's',\n default: 'org',\n description:\n \"Scope of the analytics data - either 'org' or 'repo', default: org\"\n },\n time: {\n type: 'number',\n shortFlag: 't',\n default: 7,\n description: 'Time filter - either 7, 30 or 90, default: 7'\n }\n },\n help: (command, { flags }) => `\n Usage\n $ ${command} --scope=<scope> --time=<time filter>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: report:write\n\n Default parameters are set to show the organization-level analytics over the\n last 7 days.\n\n Options\n ${getFlagListOutput(flags, 6)}\n\n Examples\n $ ${command} --scope=org --time=7\n $ ${command} --scope=org --time=30\n $ ${command} --scope=repo --repo=test-repo --time=30\n `\n}\n\nexport const cmdAnalytics = {\n description: config.description,\n hidden: config.hidden,\n run: run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { file, json, markdown, repo, scope, time } = cli.flags\n\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n test: scope === 'org' || scope === 'repo',\n message: 'Scope must be \"repo\" or \"org\"',\n pass: 'ok',\n fail: 'bad'\n },\n {\n test: time === 7 || time === 30 || time === 90,\n message: 'The time filter must either be 7, 30 or 90',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: scope === 'org' || !!repo,\n message: 'When scope=repo, repo name should be set through --repo',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: file === '-' || !!json || !!markdown,\n message:\n 'The `--file` flag is only valid when using `--json` or `--markdown`',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n assert(assertScope(scope))\n assert(assertTime(time))\n\n return await displayAnalytics({\n scope,\n time,\n repo: String(repo || ''),\n outputKind: json ? 'json' : markdown ? 'markdown' : 'print',\n filePath: String(file || '')\n })\n}\n\nfunction assertScope(scope: unknown): scope is 'org' | 'repo' {\n return scope === 'org' || scope === 'repo'\n}\n\nfunction assertTime(time: unknown): time is 7 | 30 | 90 {\n return time === 7 || time === 30 || time === 90\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchAuditLog({\n logType,\n orgSlug,\n outputKind,\n page,\n perPage\n}: {\n outputKind: 'json' | 'markdown' | 'print'\n orgSlug: string\n page: number\n perPage: number\n logType: string\n}): Promise<SocketSdkReturnType<'getAuditLogEvents'>['data'] | void> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start(`Looking up audit log for ${orgSlug}`)\n\n const result = await handleApiCall(\n sockSdk.getAuditLogEvents(orgSlug, {\n // I'm not sure this is used at all.\n outputJson: String(outputKind === 'json'),\n // I'm not sure this is used at all.\n outputMarkdown: String(outputKind === 'markdown'),\n orgSlug,\n type: logType,\n page: String(page),\n per_page: String(perPage)\n }),\n `Looking up audit log for ${orgSlug}\\n`\n )\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getAuditLogEvents', result)\n }\n\n spinner.stop()\n\n return result.data\n}\n","import process from 'node:process'\n\nimport { debugLog, isDebug } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { mdTable } from '../../utils/markdown'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nconst { REDACTED } = constants\n\nexport async function outputAuditLog(\n auditLogs: SocketSdkReturnType<'getAuditLogEvents'>['data'],\n {\n logType,\n orgSlug,\n outputKind,\n page,\n perPage\n }: {\n outputKind: 'json' | 'markdown' | 'print'\n orgSlug: string\n page: number\n perPage: number\n logType: string\n }\n): Promise<void> {\n if (outputKind === 'json') {\n logger.log(\n await outputAsJson(auditLogs.results, {\n logType,\n orgSlug,\n page,\n perPage\n })\n )\n } else {\n logger.log(\n await outputAsMarkdown(auditLogs.results, {\n logType,\n orgSlug,\n page,\n perPage\n })\n )\n }\n}\n\nexport async function outputAsJson(\n auditLogs: SocketSdkReturnType<'getAuditLogEvents'>['data']['results'],\n {\n logType,\n orgSlug,\n page,\n perPage\n }: {\n orgSlug: string\n page: number\n perPage: number\n logType: string\n }\n): Promise<string> {\n let json\n try {\n json = JSON.stringify(\n {\n desc: 'Audit logs for given query',\n generated: process.env['VITEST'] ? REDACTED : new Date().toISOString(),\n org: orgSlug,\n logType,\n page,\n perPage,\n logs: auditLogs.map(log => {\n // Note: The subset is pretty arbitrary\n const {\n created_at,\n event_id,\n ip_address,\n type,\n user_agent,\n user_email\n } = log\n return {\n event_id,\n created_at,\n ip_address,\n type,\n user_agent,\n user_email\n }\n })\n },\n null,\n 2\n )\n } catch (e) {\n process.exitCode = 1\n logger.fail(\n 'There was a problem converting the logs to JSON, please try without the `--json` flag'\n )\n if (isDebug()) {\n debugLog('Error:\\n', e)\n }\n return '{}'\n }\n\n return json\n}\n\nexport async function outputAsMarkdown(\n auditLogs: SocketSdkReturnType<'getAuditLogEvents'>['data']['results'],\n {\n logType,\n orgSlug,\n page,\n perPage\n }: {\n orgSlug: string\n page: number\n perPage: number\n logType: string\n }\n): Promise<string> {\n try {\n const table = mdTable<any>(auditLogs, [\n 'event_id',\n 'created_at',\n 'type',\n 'user_email',\n 'ip_address',\n 'user_agent'\n ])\n\n return `\n# Socket Audit Logs\n\nThese are the Socket.dev audit logs as per requested query.\n- org: ${orgSlug}\n- type filter: ${logType || '(none)'}\n- page: ${page}\n- per page: ${perPage}\n- generated: ${process.env['VITEST'] ? REDACTED : new Date().toISOString()}\n\n${table}\n`\n } catch (e) {\n process.exitCode = 1\n logger.fail(\n 'There was a problem converting the logs to Markdown, please try the `--json` flag'\n )\n if (isDebug()) {\n debugLog('Error:\\n', e)\n }\n // logger.error(e)\n return ''\n }\n}\n","import { fetchAuditLog } from './fetch-audit-log'\nimport { outputAuditLog } from './output-audit-log'\n\nexport async function handleAuditLog({\n logType,\n orgSlug,\n outputKind,\n page,\n perPage\n}: {\n outputKind: 'json' | 'markdown' | 'print'\n orgSlug: string\n page: number\n perPage: number\n logType: string\n}): Promise<void> {\n const auditLogs = await fetchAuditLog({\n orgSlug,\n outputKind,\n page,\n perPage,\n logType\n })\n if (!auditLogs) {\n return\n }\n\n await outputAuditLog(auditLogs, {\n logType,\n orgSlug,\n outputKind,\n page,\n perPage\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleAuditLog } from './handle-audit-log'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'audit-log',\n description: 'Look up the audit log for an organization',\n hidden: false,\n flags: {\n type: {\n type: 'string',\n shortFlag: 't',\n default: '',\n description: 'Type of log event'\n },\n perPage: {\n type: 'number',\n shortFlag: 'pp',\n default: 30,\n description: 'Results per page - default is 30'\n },\n page: {\n type: 'number',\n shortFlag: 'p',\n default: 1,\n description: 'Page number - default is 1'\n },\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: audit-log:list\n\n This feature requires an Enterprise Plan. To learn more about getting access\n to this feature and many more, please visit https://socket.dev/pricing\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg\n `\n}\n\nexport const cmdAuditLog = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown, page, perPage, type } = cli.flags\n const logType = String(type || '')\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n test: !!orgSlug,\n message: 'Org name should be the first arg',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleAuditLog({\n orgSlug,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'print',\n page: Number(page || 0),\n perPage: Number(perPage || 0),\n logType: logType.charAt(0).toUpperCase() + logType.slice(1)\n })\n}\n","import { existsSync, promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\n\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport shadowBin from '../../shadow/npm/bin'\n\nconst { NPM, NPX, PACKAGE_LOCK_JSON, PNPM, YARN, YARN_LOCK } = constants\n\nconst nodejsPlatformTypes = new Set([\n 'javascript',\n 'js',\n 'nodejs',\n NPM,\n PNPM,\n 'ts',\n 'tsx',\n 'typescript'\n])\n\nexport async function runCycloneDX(yargvWithYes: any) {\n let cleanupPackageLock = false\n const { yes, ...yargv } = { __proto__: null, ...yargvWithYes } as any\n const yesArgs = yes ? ['--yes'] : []\n if (\n yargv.type !== YARN &&\n nodejsPlatformTypes.has(yargv.type) &&\n existsSync(`./${YARN_LOCK}`)\n ) {\n if (existsSync(`./${PACKAGE_LOCK_JSON}`)) {\n yargv.type = NPM\n } else {\n // Use synp to create a package-lock.json from the yarn.lock,\n // based on the node_modules folder, for a more accurate SBOM.\n try {\n await shadowBin(NPX, [\n ...yesArgs,\n // The '@rollup/plugin-replace' will replace \"process.env['INLINED_SYNP_VERSION']\".\n `synp@${process.env['INLINED_SYNP_VERSION']}`,\n '--source-file',\n `./${YARN_LOCK}`\n ])\n yargv.type = NPM\n cleanupPackageLock = true\n } catch {}\n }\n }\n await shadowBin(NPX, [\n ...yesArgs,\n // The '@rollup/plugin-replace' will replace \"process.env['INLINED_CYCLONEDX_CDXGEN_VERSION']\".\n `@cyclonedx/cdxgen@${process.env['INLINED_CYCLONEDX_CDXGEN_VERSION']}`,\n ...argvToArray(yargv)\n ])\n if (cleanupPackageLock) {\n try {\n await fs.rm(`./${PACKAGE_LOCK_JSON}`)\n } catch {}\n }\n const fullOutputPath = path.join(process.cwd(), yargv.output)\n if (existsSync(fullOutputPath)) {\n logger.log(colors.cyanBright(`${yargv.output} created!`))\n }\n}\n\nfunction argvToArray(argv: {\n [key: string]: boolean | null | number | string | Array<string | number>\n}): string[] {\n if (argv['help']) {\n return ['--help']\n }\n const result = []\n for (const { 0: key, 1: value } of Object.entries(argv)) {\n if (key === '_' || key === '--') {\n continue\n }\n if (key === 'babel' || key === 'install-deps' || key === 'validate') {\n // cdxgen documents no-babel, no-install-deps, and no-validate flags so\n // use them when relevant.\n result.push(`--${value ? key : `no-${key}`}`)\n } else if (value === true) {\n result.push(`--${key}`)\n } else if (typeof value === 'string') {\n result.push(`--${key}`, String(value))\n } else if (Array.isArray(value)) {\n result.push(`--${key}`, ...value.map(String))\n }\n }\n if (argv['--']) {\n result.push('--', ...(argv as any)['--'])\n }\n return result\n}\n","const helpFlags = new Set(['--help', '-h'])\n\nexport function cmdFlagsToString(args: string[]) {\n const result = []\n for (let i = 0, { length } = args; i < length; i += 1) {\n if (args[i]!.startsWith('--')) {\n // Check if the next item exists and is NOT another flag.\n if (i + 1 < length && !args[i + 1]!.startsWith('--')) {\n result.push(`${args[i]}=${args[i + 1]}`)\n i += 1\n } else {\n result.push(args[i])\n }\n }\n }\n return result.join(' ')\n}\n\nexport function cmdPrefixMessage(cmdName: string, text: string): string {\n const cmdPrefix = cmdName ? `${cmdName}: ` : ''\n return `${cmdPrefix}${text}`\n}\n\nexport function isHelpFlag(cmdArg: string) {\n return helpFlags.has(cmdArg)\n}\n","// import { meowOrExit } from '../../utils/meow-with-subcommands'\nimport yargsParse from 'yargs-parser'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { pluralize } from '@socketsecurity/registry/lib/words'\n\nimport { runCycloneDX } from './run-cyclonedx'\nimport constants from '../../constants'\nimport { isHelpFlag } from '../../utils/cmd'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\n// TODO: convert yargs to meow. Or convert all the other things to yargs.\nconst toLower = (arg: string) => arg.toLowerCase()\nconst arrayToLower = (arg: string[]) => arg.map(toLower)\n\nconst yargsConfig = {\n configuration: {\n 'camel-case-expansion': false,\n 'strip-aliased': true,\n 'parse-numbers': false,\n 'populate--': true,\n 'unknown-options-as-args': true\n },\n coerce: {\n author: arrayToLower,\n filter: arrayToLower,\n only: arrayToLower,\n profile: toLower,\n standard: arrayToLower,\n type: arrayToLower\n },\n default: {\n //author: ['OWASP Foundation'],\n //'auto-compositions': true,\n //babel: true,\n //evidence: false,\n //'include-crypto': false,\n //'include-formulation': false,\n\n // Default 'install-deps' to `false` and 'lifecycle' to 'pre-build' to\n // sidestep arbitrary code execution during a cdxgen scan.\n // https://github.com/CycloneDX/cdxgen/issues/1328\n 'install-deps': false,\n lifecycle: 'pre-build',\n\n //output: 'bom.json',\n //profile: 'generic',\n //'project-version': '',\n //recurse: true,\n //'server-host': '127.0.0.1',\n //'server-port': '9090',\n //'spec-version': '1.5',\n type: ['js']\n //validate: true,\n },\n alias: {\n help: ['h'],\n output: ['o'],\n print: ['p'],\n recurse: ['r'],\n 'resolve-class': ['c'],\n type: ['t'],\n version: ['v'],\n yes: ['y']\n },\n array: [\n { key: 'author', type: 'string' },\n { key: 'exclude', type: 'string' },\n { key: 'filter', type: 'string' },\n { key: 'only', type: 'string' },\n { key: 'standard', type: 'string' },\n { key: 'type', type: 'string' }\n ],\n boolean: [\n 'auto-compositions',\n 'babel',\n 'deep',\n 'evidence',\n 'fail-on-error',\n 'generate-key-and-sign',\n 'help',\n 'include-formulation',\n 'include-crypto',\n 'install-deps',\n 'print',\n 'required-only',\n 'server',\n 'validate',\n 'version',\n // The --yes flag and -y alias map to the corresponding flag and alias of npx.\n // https://docs.npmjs.com/cli/v7/commands/npx#compatibility-with-older-npx-versions\n 'yes'\n ],\n string: [\n 'api-key',\n 'lifecycle',\n 'output',\n 'parent-project-id',\n 'profile',\n 'project-group',\n 'project-name',\n 'project-version',\n 'project-id',\n 'server-host',\n 'server-port',\n 'server-url',\n 'spec-version'\n ]\n}\n\nconst config: CliCommandConfig = {\n commandName: 'cdxgen',\n description: 'Create an SBOM with CycloneDX generator (cdxgen)',\n hidden: false,\n flags: {\n // TODO: convert from yargsConfig\n },\n help: (command, config) => `\n Usage\n $ ${command} [options]\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n `\n}\n\nexport const cmdCdxgen = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n allowUnknownFlags: true,\n // Don't let meow take over --help.\n argv: argv.filter(a => !isHelpFlag(a)),\n config,\n importMeta,\n parentName\n })\n\n // TODO: Convert to meow.\n const yargv = {\n ...yargsParse(argv as string[], yargsConfig)\n } as any\n\n const unknown: string[] = yargv._\n const { length: unknownLength } = unknown\n if (unknownLength) {\n // Use exit status of 2 to indicate incorrect usage, generally invalid\n // options or missing arguments.\n // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html\n process.exitCode = 2\n logger.fail(\n `Unknown ${pluralize('argument', unknownLength)}: ${yargv._.join(', ')}`\n )\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n if (yargv.output === undefined) {\n yargv.output = 'socket-cdx.json'\n }\n\n await runCycloneDX(yargv)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleApiCall } from '../../utils/api'\nimport { getConfigValue } from '../../utils/config'\nimport { setupSdk } from '../../utils/sdk'\n\n// Use the config defaultOrg when set, otherwise discover from remote\nexport async function getDefaultOrgSlug(): Promise<string | void> {\n let defaultOrg = getConfigValue('defaultOrg')\n if (defaultOrg) {\n logger.info(`Using default org: ${defaultOrg}`)\n } else {\n const sockSdk = await setupSdk()\n const result = await handleApiCall(\n sockSdk.getOrganizations(),\n 'looking up organizations'\n )\n // Ignore a failed request here. It was not the primary goal of\n // running this command and reporting it only leads to end-user confusion.\n if (!result.success) {\n logger.fail(\n 'Failed to fetch default organization from API. Unable to continue.'\n )\n process.exitCode = 1\n return\n }\n const orgs = result.data.organizations\n const keys = Object.keys(orgs)\n\n if (!keys[0]) {\n logger.fail(\n 'Could not find default organization for the current API token. Unable to continue.'\n )\n process.exitCode = 1\n return\n }\n\n const slug = (keys[0] in orgs && orgs?.[keys[0]]?.name) ?? undefined\n\n if (slug) {\n defaultOrg = slug\n logger.info(`Resolved org to: ${defaultOrg}`)\n }\n }\n\n if (!defaultOrg) {\n logger.fail(\n 'Could not find the default organization for the current API token. Unable to continue.'\n )\n process.exitCode = 1\n return\n }\n\n return defaultOrg\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchCreateOrgFullScan(\n packagePaths: string[],\n orgSlug: string,\n defaultBranch: boolean,\n pendingHead: boolean,\n tmp: boolean,\n cwd: string,\n {\n branchName,\n commitHash,\n commitMessage,\n committers,\n pullRequest,\n repoName\n }: {\n branchName: string\n commitHash: string\n commitMessage: string\n committers: string\n pullRequest: number\n repoName: string\n }\n): Promise<SocketSdkReturnType<'CreateOrgFullScan'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start(\n `Sending request to create a scan with ${packagePaths.length} packages...`\n )\n\n const result = await handleApiCall(\n sockSdk.createOrgFullScan(\n orgSlug,\n {\n ...(branchName ? { branch: branchName } : {}),\n ...(commitHash ? { commit_hash: commitHash } : {}),\n ...(commitMessage ? { commit_message: commitMessage } : {}),\n ...(committers ? { committers } : {}),\n make_default_branch: String(defaultBranch),\n ...(pullRequest ? { pull_request: String(pullRequest) } : {}),\n repo: repoName || 'socket-default-repository', // mandatory, this is server default for repo\n set_as_pending_head: String(pendingHead),\n tmp: String(tmp)\n },\n packagePaths,\n cwd\n ),\n 'Creating scan'\n )\n\n spinner.successAndStop('Completed request to create a new scan.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('CreateOrgFullScan', result)\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchSupportedScanFileNames(): Promise<\n SocketSdkReturnType<'getReportSupportedFiles'>['data'] | undefined\n> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Requesting supported scan file types from API...')\n\n const result = await handleApiCall(\n sockSdk.getReportSupportedFiles(),\n 'fetching supported scan file types'\n )\n\n spinner.stop()\n logger.success('Received response while fetched supported scan file types.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getReportSupportedFiles', result)\n }\n\n return result.data\n}\n","import { debugLog } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { handleApiCall, handleApiError, queryApi } from '../../utils/api'\nimport { AuthError } from '../../utils/errors'\nimport { failMsgWithBadge } from '../../utils/fail-msg-with-badge'\nimport { getDefaultToken, setupSdk } from '../../utils/sdk'\n\nimport type {\n SocketSdkResultType,\n SocketSdkReturnType\n} from '@socketsecurity/sdk'\nimport type { components } from '@socketsecurity/sdk/types/api'\n\n/**\n * This fetches all the relevant pieces of data to generate a report, given a\n * full scan ID.\n */\nexport async function fetchReportData(\n orgSlug: string,\n scanId: string,\n includeLicensePolicy: boolean\n): Promise<\n | {\n ok: true\n scan: Array<components['schemas']['SocketArtifact']>\n securityPolicy: SocketSdkReturnType<'getOrgSecurityPolicy'>\n }\n | {\n ok: false\n scan: undefined\n securityPolicy: undefined\n }\n> {\n const apiToken = getDefaultToken()\n if (!apiToken) {\n throw new AuthError(\n 'User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.'\n )\n }\n\n const sockSdk = await setupSdk(apiToken)\n\n let scanStatus = 'requested..'\n let policyStatus = 'requested..'\n let finishedFetching = false\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n function updateScan(desc: string) {\n scanStatus = desc\n updateProgress()\n }\n\n function updatePolicy(desc: string) {\n policyStatus = desc\n updateProgress()\n }\n\n function updateProgress() {\n if (finishedFetching) {\n spinner.stop()\n logger.info(\n `Scan result: ${scanStatus}. Security policy: ${policyStatus}.`\n )\n } else {\n spinner.start(\n `Scan result: ${scanStatus}. Security policy: ${policyStatus}.`\n )\n }\n }\n\n async function fetchScanResult(apiToken: string) {\n const response = await queryApi(\n `orgs/${orgSlug}/full-scans/${encodeURIComponent(scanId)}${includeLicensePolicy ? '?include_license_details=true' : ''}`,\n apiToken\n )\n updateScan('received response')\n\n if (!response.ok) {\n spinner.stop()\n const err = await handleApiError(response.status)\n logger.fail(failMsgWithBadge(response.statusText, `Fetch error: ${err}`))\n debugLog(err)\n updateScan(`request resulted in status code ${response.status}`)\n return undefined\n }\n\n updateScan(`ok, downloading response..`)\n const jsons = await response.text()\n updateScan(`received`)\n\n const lines = jsons.split('\\n').filter(Boolean)\n const data = lines.map(line => {\n try {\n return JSON.parse(line)\n } catch {\n scanStatus = `received invalid JSON response`\n spinner.stop()\n logger.error(\n 'Response was not valid JSON but it ought to be (please report if this persists)'\n )\n debugLog(line)\n updateProgress()\n return\n }\n }) as unknown as Array<components['schemas']['SocketArtifact']>\n\n return data\n }\n\n async function fetchSecurityPolicy() {\n const r = await sockSdk.getOrgSecurityPolicy(orgSlug)\n updatePolicy('received response')\n\n const s = await handleApiCall(\n r,\n \"looking up organization's security policy\"\n )\n updatePolicy('received')\n return s\n }\n\n updateProgress()\n\n const [scan, securityPolicyMaybe]: [\n undefined | Array<components['schemas']['SocketArtifact']>,\n SocketSdkResultType<'getOrgSecurityPolicy'>\n ] = await Promise.all([\n fetchScanResult(apiToken).catch(e => {\n updateScan(`failure; unknown blocking problem occurred`)\n throw e\n }),\n fetchSecurityPolicy().catch(e => {\n updatePolicy(`failure; unknown blocking problem occurred`)\n throw e\n })\n ]).finally(() => {\n finishedFetching = true\n updateProgress()\n })\n\n if (!Array.isArray(scan)) {\n logger.error('Was unable to fetch scan result, bailing')\n process.exitCode = 1\n return {\n ok: false,\n scan: undefined,\n securityPolicy: undefined\n }\n }\n\n if (!securityPolicyMaybe?.success) {\n logger.error('Was unable to fetch security policy, bailing')\n process.exitCode = 1\n return {\n ok: false,\n scan: undefined,\n securityPolicy: undefined\n }\n }\n\n return {\n ok: true,\n scan,\n securityPolicy: securityPolicyMaybe\n }\n}\n","import type { Spinner } from '@socketsecurity/registry/lib/spinner'\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\nimport type { components } from '@socketsecurity/sdk/types/api'\n\ntype AlertAction = 'defer' | 'ignore' | 'monitor' | 'error' | 'warn'\ntype AlertKey = string\n\ntype FileMap = Map<string, ReportLeafNode | Map<AlertKey, ReportLeafNode>>\ntype VersionMap = Map<string, ReportLeafNode | FileMap>\ntype PackageMap = Map<string, ReportLeafNode | VersionMap>\ntype EcoMap = Map<string, ReportLeafNode | PackageMap>\nexport type ViolationsMap = Map<string, EcoMap>\n\nexport interface ShortScanReport {\n healthy: boolean\n}\nexport interface ScanReport {\n orgSlug: string\n scanId: string\n options: { fold: string; reportLevel: string }\n healthy: boolean\n alerts: ViolationsMap\n}\n\nexport type ReportLeafNode = {\n type: string\n policy: 'defer' | 'ignore' | 'monitor' | 'warn' | 'error'\n url: string\n manifest: string[]\n}\n\nexport function generateReport(\n scan: Array<components['schemas']['SocketArtifact']>,\n securityPolicy: SocketSdkReturnType<'getOrgSecurityPolicy'>,\n {\n fold,\n orgSlug,\n reportLevel,\n scanId,\n short,\n spinner\n }: {\n fold: 'pkg' | 'version' | 'file' | 'none'\n orgSlug: string\n reportLevel: 'defer' | 'ignore' | 'monitor' | 'warn' | 'error'\n scanId: string\n short?: boolean | undefined\n spinner?: Spinner | undefined\n }\n): ScanReport | ShortScanReport {\n const now = Date.now()\n\n spinner?.start('Generating report...')\n\n // Create an object that includes:\n // healthy: boolean\n // worst violation level;\n // per eco\n // per package\n // per version\n // per offending file\n // reported issue -> policy action\n\n // In the context of a report;\n // - the alert.severity is irrelevant\n // - the securityPolicyDefault is irrelevant\n // - the report defaults to healthy:true with no alerts\n // - the appearance of an alert will trigger the policy action;\n // - error: healthy will end up as false, add alerts to report\n // - warn: healthy unchanged, add alerts to report\n // - monitor/ignore: no action\n // - defer: unknown (no action)\n\n // Note: the server will emit alerts for license policy violations but\n // those are only included if you set the flag when requesting the scan\n // data. The alerts map to a single security policy key that determines\n // what to do with any violation, regardless of the concrete license.\n // That rule is called \"License Policy Violation\".\n // The license policy part is implicitly handled here. Either they are\n // included and may show up, or they are not and won't show up.\n\n const violations = new Map()\n\n let healthy = true\n\n const securityRules: SocketSdkReturnType<'getOrgSecurityPolicy'>['data']['securityPolicyRules'] =\n securityPolicy.data.securityPolicyRules\n if (securityRules) {\n // Note: reportLevel: error > warn > monitor > ignore > defer\n scan.forEach(artifact => {\n const {\n alerts,\n name: pkgName = '<unknown>',\n type: ecosystem,\n version = '<unknown>'\n } = artifact\n\n alerts?.forEach(\n (\n alert: NonNullable<\n components['schemas']['SocketArtifact']['alerts']\n >[number]\n ) => {\n const alertName = alert.type as keyof typeof securityRules // => policy[type]\n const action = securityRules[alertName]?.action || ''\n switch (action) {\n case 'error': {\n healthy = false\n if (!short) {\n addAlert(\n artifact,\n violations,\n fold,\n ecosystem,\n pkgName,\n version,\n alert,\n action\n )\n }\n break\n }\n case 'warn': {\n if (!short && reportLevel !== 'error') {\n addAlert(\n artifact,\n violations,\n fold,\n ecosystem,\n pkgName,\n version,\n alert,\n action\n )\n }\n break\n }\n case 'monitor': {\n if (!short && reportLevel !== 'warn' && reportLevel !== 'error') {\n addAlert(\n artifact,\n violations,\n fold,\n ecosystem,\n pkgName,\n version,\n alert,\n action\n )\n }\n break\n }\n\n case 'ignore': {\n if (\n !short &&\n reportLevel !== 'warn' &&\n reportLevel !== 'error' &&\n reportLevel !== 'monitor'\n ) {\n addAlert(\n artifact,\n violations,\n fold,\n ecosystem,\n pkgName,\n version,\n alert,\n action\n )\n }\n break\n }\n\n case 'defer': {\n // Not sure but ignore for now. Defer to later ;)\n if (!short && reportLevel === 'defer') {\n addAlert(\n artifact,\n violations,\n fold,\n ecosystem,\n pkgName,\n version,\n alert,\n action\n )\n }\n break\n }\n\n default: {\n // This value was not emitted from the api at the time of writing.\n }\n }\n }\n )\n })\n }\n\n spinner?.successAndStop(`Generated reported in ${Date.now() - now} ms`)\n\n const report = short\n ? { healthy }\n : {\n healthy,\n orgSlug,\n scanId,\n options: { fold, reportLevel },\n alerts: violations\n }\n\n return report\n}\n\nfunction createLeaf(\n art: components['schemas']['SocketArtifact'],\n alert: NonNullable<components['schemas']['SocketArtifact']['alerts']>[number],\n policyAction: AlertAction\n): ReportLeafNode {\n const leaf: ReportLeafNode = {\n type: alert.type,\n policy: policyAction,\n url: `https://socket.dev/${art.type}/package/${art.name}/${art.version}`,\n manifest: art.manifestFiles?.map(obj => obj.file) ?? []\n }\n return leaf\n}\n\nfunction addAlert(\n art: components['schemas']['SocketArtifact'],\n violations: ViolationsMap,\n foldSetting: 'pkg' | 'version' | 'file' | 'none',\n ecosystem: string,\n pkgName: string,\n version: string,\n alert: NonNullable<components['schemas']['SocketArtifact']['alerts']>[number],\n policyAction: AlertAction\n): void {\n if (!violations.has(ecosystem)) {\n violations.set(ecosystem, new Map())\n }\n const ecomap: EcoMap = violations.get(ecosystem)!\n if (foldSetting === 'pkg') {\n const existing = ecomap.get(pkgName) as ReportLeafNode | undefined\n if (!existing || isStricterPolicy(existing.policy, policyAction)) {\n ecomap.set(pkgName, createLeaf(art, alert, policyAction))\n }\n } else {\n if (!ecomap.has(pkgName)) {\n ecomap.set(pkgName, new Map())\n }\n const pkgmap = ecomap.get(pkgName) as PackageMap\n if (foldSetting === 'version') {\n const existing = pkgmap.get(version) as ReportLeafNode | undefined\n if (!existing || isStricterPolicy(existing.policy, policyAction)) {\n pkgmap.set(version, createLeaf(art, alert, policyAction))\n }\n } else {\n if (!pkgmap.has(version)) {\n pkgmap.set(version, new Map())\n }\n const file = alert.file || '<unknown>'\n const vermap = pkgmap.get(version) as VersionMap\n\n if (foldSetting === 'file') {\n const existing = vermap.get(file) as ReportLeafNode | undefined\n if (!existing || isStricterPolicy(existing.policy, policyAction)) {\n vermap.set(file, createLeaf(art, alert, policyAction))\n }\n } else {\n if (!vermap.has(file)) {\n vermap.set(file, new Map())\n }\n const key = `${alert.type} at ${alert.start}:${alert.end}`\n const filemap: FileMap = vermap.get(file) as FileMap\n const existing = filemap.get(key) as ReportLeafNode | undefined\n if (!existing || isStricterPolicy(existing.policy, policyAction)) {\n filemap.set(key, createLeaf(art, alert, policyAction))\n }\n }\n }\n }\n}\n\nfunction isStricterPolicy(\n was: 'error' | 'warn' | 'monitor' | 'ignore' | 'defer',\n is: 'error' | 'warn' | 'monitor' | 'ignore' | 'defer'\n): boolean {\n // error > warn > monitor > ignore > defer > {unknown}\n if (was === 'error') {\n return false\n }\n if (is === 'error') {\n return true\n }\n if (was === 'warn') {\n return false\n }\n if (is === 'warn') {\n return false\n }\n if (was === 'monitor') {\n return false\n }\n if (is === 'monitor') {\n return false\n }\n if (was === 'ignore') {\n return false\n }\n if (is === 'ignore') {\n return false\n }\n if (was === 'defer') {\n return false\n }\n if (is === 'defer') {\n return false\n }\n // unreachable?\n return false\n}\n","interface NestedRecord<T> {\n [key: string]: T | NestedRecord<T>\n}\n\n/**\n * Convert a Map<string, Map|string> to a nested object of similar shape.\n * The goal is to serialize it with JSON.stringify, which Map can't do.\n */\nexport function mapToObject<T>(\n map: Map<string, T | Map<string, T | Map<string, T>>>\n): NestedRecord<T> {\n return Object.fromEntries(\n Array.from(map.entries()).map(([k, v]) => [\n k,\n v instanceof Map ? mapToObject(v) : v\n ])\n )\n}\n","type NestedMap<T> = Map<string, T | NestedMap<T>>\n\nexport function* walkNestedMap<T>(\n map: NestedMap<T>,\n keys: string[] = []\n): Generator<{ keys: string[]; value: T }> {\n for (const [key, value] of map.entries()) {\n if (value instanceof Map) {\n yield* walkNestedMap(value as NestedMap<T>, keys.concat(key))\n } else {\n yield { keys: keys.concat(key), value: value }\n }\n }\n}\n","import fs from 'node:fs/promises'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { generateReport } from './generate-report'\nimport constants from '../../constants'\nimport { mapToObject } from '../../utils/map-to-object'\nimport { mdTable } from '../../utils/markdown'\nimport { walkNestedMap } from '../../utils/walk-nested-map'\n\nimport type { ReportLeafNode, ScanReport } from './generate-report'\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\nimport type { components } from '@socketsecurity/sdk/types/api'\n\nexport async function outputScanReport(\n scan: Array<components['schemas']['SocketArtifact']>,\n securityPolicy: SocketSdkReturnType<'getOrgSecurityPolicy'>,\n {\n filePath,\n fold,\n includeLicensePolicy,\n orgSlug,\n outputKind,\n reportLevel,\n scanId,\n short\n }: {\n orgSlug: string\n scanId: string\n includeLicensePolicy: boolean\n outputKind: 'json' | 'markdown' | 'text'\n filePath: string\n fold: 'pkg' | 'version' | 'file' | 'none'\n reportLevel: 'defer' | 'ignore' | 'monitor' | 'warn' | 'error'\n short: boolean\n }\n): Promise<void> {\n const scanReport = generateReport(scan, securityPolicy, {\n orgSlug,\n scanId,\n fold,\n reportLevel,\n short,\n // Lazily access constants.spinner.\n spinner: constants.spinner\n })\n\n if (!scanReport.healthy) {\n process.exitCode = 1\n }\n\n if (\n outputKind === 'json' ||\n (outputKind === 'text' && filePath && filePath.endsWith('.json'))\n ) {\n const json = short\n ? JSON.stringify(scanReport)\n : toJsonReport(scanReport as ScanReport, includeLicensePolicy)\n\n if (filePath && filePath !== '-') {\n logger.log('Writing json report to', filePath)\n return await fs.writeFile(filePath, json)\n }\n\n logger.log(json)\n return\n }\n\n if (outputKind === 'markdown' || (filePath && filePath.endsWith('.md'))) {\n const md = short\n ? `healthy = ${scanReport.healthy}`\n : toMarkdownReport(scanReport as ScanReport, includeLicensePolicy)\n\n if (filePath && filePath !== '-') {\n logger.log('Writing markdown report to', filePath)\n return await fs.writeFile(filePath, md)\n }\n\n logger.log(md)\n return\n }\n\n if (short) {\n logger.log(scanReport.healthy ? 'OK' : 'ERR')\n } else {\n logger.dir(scanReport, { depth: null })\n }\n}\n\nexport function toJsonReport(\n report: ScanReport,\n includeLicensePolicy: boolean\n): string {\n const obj = mapToObject(report.alerts)\n\n const json = JSON.stringify(\n {\n includeLicensePolicy,\n ...report,\n alerts: obj\n },\n null,\n 2\n )\n\n return json\n}\n\nexport function toMarkdownReport(\n report: ScanReport,\n includeLicensePolicy: boolean\n): string {\n const flatData = Array.from(walkNestedMap(report.alerts)).map(\n ({ keys, value }: { keys: string[]; value: ReportLeafNode }) => {\n const { manifest, policy, type, url } = value\n return {\n 'Alert Type': type,\n Package: keys[1] || '<unknown>',\n 'Introduced by': keys[2] || '<unknown>',\n url,\n 'Manifest file': manifest.join(', '),\n Policy: policy\n }\n }\n )\n\n const md =\n `\n# Scan Policy Report\n\nThis report tells you whether the results of a Socket scan results violate the\nsecurity${includeLicensePolicy ? ' or license' : ''} policy set by your organization.\n\n## Health status\n\n${\n report.healthy\n ? `The scan *PASSES* all requirements set by your security${includeLicensePolicy ? ' and license' : ''} policy.`\n : 'The scan *VIOLATES* one or more policies set to the \"error\" level.'\n}\n\n## Settings\n\nConfiguration used to generate this report:\n\n- Organization: ${report.orgSlug}\n- Scan ID: ${report.scanId}\n- Alert folding: ${report.options.fold === 'none' ? 'none' : `up to ${report.options.fold}`}\n- Minimal policy level for alert to be included in report: ${report.options.reportLevel === 'defer' ? 'everything' : report.options.reportLevel}\n- Include license alerts: ${includeLicensePolicy ? 'yes' : 'no'}\n\n## Alerts\n\n${\n report.alerts.size\n ? `All the alerts from the scan with a policy set to at least \"${report.options.reportLevel}\"}.`\n : `The scan contained no alerts for with a policy set to at least \"${report.options.reportLevel}\".`\n}\n\n${\n !report.alerts.size\n ? ''\n : mdTable(flatData, [\n 'Policy',\n 'Alert Type',\n 'Package',\n 'Introduced by',\n 'url',\n 'Manifest file'\n ])\n}\n `.trim() + '\\n'\n\n return md\n}\n","import { fetchReportData } from './fetch-report-data'\nimport { outputScanReport } from './output-scan-report'\n\nexport async function handleScanReport({\n filePath,\n fold,\n includeLicensePolicy,\n orgSlug,\n outputKind,\n reportLevel,\n scanId,\n short\n}: {\n orgSlug: string\n scanId: string\n includeLicensePolicy: boolean\n outputKind: 'json' | 'markdown' | 'text'\n filePath: string\n fold: 'pkg' | 'version' | 'file' | 'none'\n reportLevel: 'defer' | 'ignore' | 'monitor' | 'warn' | 'error'\n short: boolean\n}): Promise<void> {\n const { ok, scan, securityPolicy } = await fetchReportData(\n orgSlug,\n scanId,\n includeLicensePolicy\n )\n if (!ok) {\n return\n }\n\n await outputScanReport(scan, securityPolicy, {\n filePath,\n fold,\n scanId: scanId,\n includeLicensePolicy,\n orgSlug,\n outputKind,\n reportLevel,\n short\n })\n}\n","import open from 'open'\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { confirm } from '@socketsecurity/registry/lib/prompts'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputCreateNewScan(\n data: SocketSdkReturnType<'CreateOrgFullScan'>['data'],\n outputKind: 'json' | 'markdown' | 'text',\n interactive: boolean\n) {\n if (!data.id) {\n logger.fail('Did not receive a scan ID from the API...')\n process.exitCode = 1\n }\n\n if (outputKind === 'json') {\n const json = data.id\n ? { success: true, data }\n : { success: false, message: 'No scan ID received' }\n\n logger.log(JSON.stringify(json, null, 2))\n logger.log('')\n\n return\n }\n\n if (outputKind === 'markdown') {\n logger.log('# Create New Scan')\n logger.log('')\n if (data.id) {\n logger.log(\n `A [new Scan](${data.html_report_url}) was created with ID: ${data.id}`\n )\n logger.log('')\n } else {\n logger.log(\n `The server did not return a Scan ID while trying to create a new Scan. This could be an indication something went wrong.`\n )\n }\n logger.log('')\n return\n }\n\n const link = colors.underline(colors.cyan(`${data.html_report_url}`))\n logger.log(`Available at: ${link}`)\n\n if (\n interactive &&\n (await confirm({\n message: 'Would you like to open it in your browser?',\n default: false\n }))\n ) {\n await open(`${data.html_report_url}`)\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { fetchCreateOrgFullScan } from './fetch-create-org-full-scan'\nimport { fetchSupportedScanFileNames } from './fetch-supported-scan-file-names'\nimport { handleScanReport } from './handle-scan-report'\nimport { outputCreateNewScan } from './output-create-new-scan'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { getPackageFilesForScan } from '../../utils/path-resolve'\n\nexport async function handleCreateNewScan({\n branchName,\n commitHash,\n commitMessage,\n committers,\n cwd,\n defaultBranch,\n interactive,\n orgSlug,\n outputKind,\n pendingHead,\n pullRequest,\n readOnly,\n repoName,\n report,\n targets,\n tmp\n}: {\n branchName: string\n commitHash: string\n commitMessage: string\n committers: string\n cwd: string\n defaultBranch: boolean\n interactive: boolean\n orgSlug: string\n pendingHead: boolean\n pullRequest: number\n outputKind: 'json' | 'markdown' | 'text'\n readOnly: boolean\n repoName: string\n report: boolean\n targets: string[]\n tmp: boolean\n}): Promise<void> {\n const supportedFileNames = await fetchSupportedScanFileNames()\n if (!supportedFileNames) {\n return\n }\n\n const packagePaths = await getPackageFilesForScan(\n cwd,\n targets,\n supportedFileNames\n )\n\n if (\n handleBadInput({\n nook: true,\n test: packagePaths.length > 0,\n pass: 'ok',\n fail: 'found no eligible files to scan',\n message:\n 'TARGET (file/dir) must contain matching / supported file types for a scan'\n })\n ) {\n return\n }\n\n if (readOnly) {\n logger.log('[ReadOnly] Bailing now')\n return\n }\n\n const data = await fetchCreateOrgFullScan(\n packagePaths,\n orgSlug,\n defaultBranch,\n pendingHead,\n tmp,\n cwd,\n {\n commitHash,\n commitMessage,\n committers,\n pullRequest,\n repoName,\n branchName\n }\n )\n if (!data) {\n return\n }\n\n if (report) {\n if (data?.id) {\n await handleScanReport({\n filePath: '-',\n fold: 'version',\n includeLicensePolicy: true,\n orgSlug,\n outputKind,\n reportLevel: 'error',\n scanId: data.id,\n short: false\n })\n } else {\n logger.fail('Failure: Server did not respond with a scan ID')\n process.exitCode = 1\n }\n } else {\n await outputCreateNewScan(data, outputKind, interactive)\n }\n}\n","import { getDefaultOrgSlug } from './fetch-default-org-slug'\nimport { handleCreateNewScan } from '../scan/handle-create-new-scan'\n\nexport async function handleCI(): Promise<void> {\n // ci: {\n // description: 'Alias for \"report create --view --strict\"',\n // argv: ['report', 'create', '--view', '--strict']\n // }\n const orgSlug = await getDefaultOrgSlug()\n if (!orgSlug) {\n return\n }\n\n // TODO: does it make sense to discover the commit details from local git?\n // TODO: does it makes sense to use custom branch/repo names here? probably socket.yml, right\n await handleCreateNewScan({\n branchName: 'socket-default-branch',\n commitMessage: '',\n commitHash: '',\n committers: '',\n cwd: process.cwd(),\n defaultBranch: false,\n interactive: false,\n orgSlug,\n outputKind: 'json',\n pendingHead: true, // when true, requires branch name set, tmp false\n pullRequest: 0,\n repoName: 'socket-default-repository',\n readOnly: false,\n report: true,\n targets: ['.'],\n tmp: false // don't set when pendingHead is true\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleCI } from './handle-ci'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'ci',\n description:\n 'Create a new scan and report whether it passes your security policy',\n hidden: true,\n flags: {\n ...commonFlags\n },\n help: (parentName, _config) => `\n Usage\n $ ${parentName}\n\n This command is intended to use in CI runs to allow automated systems to\n accept or reject a current build. When the scan does not pass your security\n policy, the exit code will be non-zero.\n\n It will use the default org for the set API token.\n `\n}\n\nexport const cmdCI = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleCI()\n}\n","import { handleApiCall } from '../../utils/api'\nimport { supportedConfigKeys } from '../../utils/config'\nimport { getDefaultToken, setupSdk } from '../../utils/sdk'\n\nimport type { LocalConfig } from '../../utils/config'\n\nexport async function discoverConfigValue(\n key: string\n): Promise<{ success: boolean; value: unknown; message: string }> {\n // This will have to be a specific implementation per key because certain\n // keys should request information from particular API endpoints while\n // others should simply return their default value, like endpoint URL.\n\n if (!supportedConfigKeys.has(key as keyof LocalConfig)) {\n return {\n success: false,\n value: undefined,\n message: 'Requested key is not a valid config key.'\n }\n }\n\n if (key === 'apiBaseUrl') {\n // Return the default value\n return {\n success: false,\n value: undefined,\n message:\n \"If you're unsure about the base endpoint URL then simply unset it.\"\n }\n }\n\n if (key === 'apiProxy') {\n // I don't think we can auto-discover this with any order of reliability..?\n return {\n success: false,\n value: undefined,\n message:\n 'When uncertain, unset this key. Otherwise ask your network administrator'\n }\n }\n\n if (key === 'apiToken') {\n return {\n success: false,\n value: undefined,\n message:\n 'You can find/create your API token in your Socket dashboard > settings > API tokens.\\nYou should then use `socket login` to login instead of this command.'\n }\n }\n\n if (key === 'defaultOrg') {\n const apiToken = getDefaultToken()\n if (!apiToken) {\n return {\n success: false,\n value: undefined,\n message:\n 'No API token set, must have a token to resolve its default org.'\n }\n }\n\n const org = await getDefaultOrgFromToken()\n if (!org?.length) {\n return {\n success: false,\n value: undefined,\n message:\n 'Was unable to determine default org for the current API token.'\n }\n }\n\n if (Array.isArray(org)) {\n return {\n success: true,\n value: org,\n message: 'These are the orgs that the current API token can access.'\n }\n }\n\n return {\n success: true,\n value: org,\n message: 'This is the org that belongs to the current API token.'\n }\n }\n\n if (key === 'enforcedOrgs') {\n const apiToken = getDefaultToken()\n if (!apiToken) {\n return {\n success: false,\n value: undefined,\n message:\n 'No API token set, must have a token to resolve orgs to enforce.'\n }\n }\n\n const orgs = await getEnforceableOrgsFromToken()\n if (!orgs?.length) {\n return {\n success: false,\n value: undefined,\n message:\n 'Was unable to determine any orgs to enforce for the current API token.'\n }\n }\n\n return {\n success: true,\n value: orgs,\n message: 'These are the orgs whose security policy you can enforce.'\n }\n }\n\n if (key === 'test') {\n return {\n success: false,\n value: undefined,\n message: ''\n }\n }\n\n // Mostly to please TS, because we're not telling it `key` is keyof LocalConfig\n return {\n success: false,\n value: undefined,\n message: 'unreachable?'\n }\n}\n\nasync function getDefaultOrgFromToken(): Promise<\n string[] | string | undefined\n> {\n const sockSdk = await setupSdk()\n const result = await handleApiCall(\n sockSdk.getOrganizations(),\n 'looking up organizations'\n )\n\n if (result.success) {\n const arr = Array.from(Object.values(result.data.organizations)).map(\n ({ slug }) => slug\n )\n if (arr.length === 0) {\n return undefined\n }\n if (arr.length === 1) {\n return arr[0]\n }\n return arr\n }\n\n return undefined\n}\n\nasync function getEnforceableOrgsFromToken(): Promise<string[] | undefined> {\n const sockSdk = await setupSdk()\n const result = await handleApiCall(\n sockSdk.getOrganizations(),\n 'looking up organizations'\n )\n\n if (result.success) {\n const arr = Array.from(Object.values(result.data.organizations)).map(\n ({ slug }) => slug\n )\n if (arr.length === 0) {\n return undefined\n }\n return arr\n }\n\n return undefined\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\nimport { select } from '@socketsecurity/registry/lib/prompts'\n\nimport { LocalConfig, updateConfigValue } from '../../utils/config'\n\nexport async function outputConfigAuto(\n key: keyof LocalConfig,\n {\n message,\n success,\n value\n }: {\n success: boolean\n value: unknown\n message: string\n },\n outputKind: 'json' | 'markdown' | 'text'\n) {\n if (outputKind === 'json') {\n logger.log(JSON.stringify({ success, message, result: { key, value } }))\n } else if (outputKind === 'markdown') {\n logger.log(`# Auto discover config value`)\n logger.log('')\n logger.log(\n `Attempted to automatically discover the value for config key: \"${key}\"`\n )\n logger.log('')\n if (success) {\n logger.log(`The discovered value is: \"${value}\"`)\n if (message) {\n logger.log('')\n logger.log(message)\n }\n } else {\n logger.log(`The discovery failed: ${message}`)\n }\n logger.log('')\n } else {\n if (message) {\n logger.log(message)\n logger.log('')\n }\n logger.log(`- ${key}: ${value}`)\n logger.log('')\n\n if (success) {\n if (key === 'defaultOrg') {\n const proceed = await select<string>({\n message:\n 'Would you like to update the default org in local config to this value?',\n choices: (Array.isArray(value) ? value : [value])\n .map(slug => ({\n name: 'Yes [' + slug + ']',\n value: slug,\n description: `Use \"${slug}\" as the default organization`\n }))\n .concat({\n name: 'No',\n value: '',\n description: 'Do not use any of these organizations'\n })\n })\n if (proceed) {\n logger.log(\n `OK. Setting defaultOrg to \"${proceed}\".\\nYou should no longer need to add the org to commands that normally require it.`\n )\n updateConfigValue('defaultOrg', proceed)\n } else {\n logger.log('OK. No changes made.')\n }\n } else if (key === 'enforcedOrgs') {\n const proceed = await select<string>({\n message:\n 'Would you like to update the enforced orgs in local config to this value?',\n choices: (Array.isArray(value) ? value : [value])\n .map(slug => ({\n name: 'Yes [' + slug + ']',\n value: slug,\n description: `Enforce the security policy of \"${slug}\" on this machine`\n }))\n .concat({\n name: 'No',\n value: '',\n description: 'Do not use any of these organizations'\n })\n })\n if (proceed) {\n logger.log(`OK. Setting enforcedOrgs key to \"${proceed}\".`)\n updateConfigValue('defaultOrg', proceed)\n } else {\n logger.log('OK. No changes made.')\n }\n }\n }\n }\n}\n","import { discoverConfigValue } from './discover-config-value'\nimport { outputConfigAuto } from './output-config-auto'\n\nimport type { LocalConfig } from '../../utils/config'\n\nexport async function handleConfigAuto({\n key,\n outputKind\n}: {\n key: keyof LocalConfig\n outputKind: 'json' | 'markdown' | 'text'\n}) {\n const result = await discoverConfigValue(key)\n\n await outputConfigAuto(key, result, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleConfigAuto } from './handle-config-auto'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { supportedConfigKeys } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { LocalConfig } from '../../utils/config'\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'auto',\n description: 'Automatically discover and set the correct value config item',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug>\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Attempt to automatically discover the correct value for a certain config key.\n\n For certain keys it will request the value from server, for others it will\n reset the value to the default. For some keys this has no effect.\n\n Keys:\n\n${Array.from(supportedConfigKeys.entries())\n .map(([key, desc]) => ` - ${key} -- ${desc}`)\n .join('\\n')}\n\n Examples\n $ ${command} auto defaultOrg\n `\n}\n\nexport const cmdConfigAuto = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const [key = ''] = cli.input\n\n const wasBadInput = handleBadInput(\n {\n test: supportedConfigKeys.has(key as keyof LocalConfig) && key !== 'test',\n message: 'Config key should be the first arg',\n pass: 'ok',\n fail: key ? 'invalid config key' : 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleConfigAuto({\n key: key as keyof LocalConfig,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text'\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { LocalConfig } from '../../utils/config'\n\nexport async function outputConfigGet(\n key: keyof LocalConfig,\n value: unknown,\n readOnly: boolean, // Is config in read-only mode? (Overrides applied)\n outputKind: 'json' | 'markdown' | 'text'\n) {\n if (outputKind === 'json') {\n logger.log(\n JSON.stringify({ success: true, result: { key, value }, readOnly })\n )\n } else if (outputKind === 'markdown') {\n logger.log(`# Config Value`)\n logger.log('')\n logger.log(`Config key '${key}' has value '${value}`)\n if (readOnly) {\n logger.log('')\n logger.log(\n 'Note: the config is in read-only mode, meaning at least one key was temporarily\\n overridden from an env var or command flag.'\n )\n }\n } else {\n logger.log(`${key}: ${value}`)\n if (readOnly) {\n logger.log('')\n logger.log(\n 'Note: the config is in read-only mode, meaning at least one key was temporarily overridden from an env var or command flag.'\n )\n }\n }\n}\n","import { outputConfigGet } from './output-config-get'\nimport { getConfigValue, isReadOnlyConfig } from '../../utils/config'\n\nimport type { LocalConfig } from '../../utils/config'\n\nexport async function handleConfigGet({\n key,\n outputKind\n}: {\n key: keyof LocalConfig\n outputKind: 'json' | 'markdown' | 'text'\n}) {\n const value = getConfigValue(key)\n const readOnly = isReadOnlyConfig()\n\n await outputConfigGet(key, value, readOnly, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleConfigGet } from './handle-config-get'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { supportedConfigKeys } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { LocalConfig } from '../../utils/config'\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'get',\n description: 'Get the value of a local CLI config item',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug>\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Keys:\n\n${Array.from(supportedConfigKeys.entries())\n .map(([key, desc]) => ` - ${key} -- ${desc}`)\n .join('\\n')}\n\n Examples\n $ ${command} FakeOrg --repoName=test-repo\n `\n}\n\nexport const cmdConfigGet = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const [key = ''] = cli.input\n\n const wasBadInput = handleBadInput(\n {\n test: supportedConfigKeys.has(key as keyof LocalConfig) || key === 'test',\n message: 'Config key should be the first arg',\n pass: 'ok',\n fail: key ? 'invalid config key' : 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleConfigGet({\n key: key as keyof LocalConfig,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text'\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport {\n getConfigValue,\n isReadOnlyConfig,\n sensitiveConfigKeys,\n supportedConfigKeys\n} from '../../utils/config'\n\nexport async function outputConfigList({\n full,\n outputKind\n}: {\n full: boolean\n outputKind: 'json' | 'markdown' | 'text'\n}) {\n const readOnly = isReadOnlyConfig()\n if (outputKind === 'json') {\n const obj: Record<string, unknown> = {}\n for (const key of supportedConfigKeys.keys()) {\n let value = getConfigValue(key)\n if (!full && sensitiveConfigKeys.has(key)) {\n value = '********'\n }\n if (full || value !== undefined) {\n obj[key as any] = value ?? '<none>'\n }\n }\n logger.log(\n JSON.stringify(\n {\n success: true,\n full,\n config: obj,\n readOnly\n },\n null,\n 2\n )\n )\n } else {\n const maxWidth = Array.from(supportedConfigKeys.keys()).reduce(\n (a, b) => Math.max(a, b.length),\n 0\n )\n\n logger.log('# Local CLI Config')\n logger.log('')\n logger.log(`This is the local CLI config (full=${!!full}):`)\n logger.log('')\n for (const key of supportedConfigKeys.keys()) {\n let value = getConfigValue(key)\n if (!full && sensitiveConfigKeys.has(key)) {\n value = '********'\n }\n if (full || value !== undefined) {\n logger.log(\n `- ${key}:${' '.repeat(Math.max(0, maxWidth - key.length + 3))} ${Array.isArray(value) ? value.join(', ') || '<none>' : (value ?? '<none>')}`\n )\n }\n }\n if (readOnly) {\n logger.log('')\n logger.log(\n 'Note: the config is in read-only mode, meaning at least one key was temporarily\\n overridden from an env var or command flag.'\n )\n }\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { outputConfigList } from './output-config-list'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { supportedConfigKeys } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'list',\n description: 'Show all local CLI config items and their values',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n full: {\n type: 'boolean',\n default: false,\n description: 'Show full tokens in plaintext (unsafe)'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug>\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Keys:\n\n${Array.from(supportedConfigKeys.entries())\n .map(([key, desc]) => ` - ${key} -- ${desc}`)\n .join('\\n')}\n\n Examples\n $ ${command} FakeOrg --repoName=test-repo\n `\n}\n\nexport const cmdConfigList = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { full, json, markdown } = cli.flags\n\n const wasBadInput = handleBadInput({\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n })\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await outputConfigList({\n full: !!full,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text'\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { LocalConfig } from '../../utils/config'\n\nexport async function outputConfigSet(\n key: keyof LocalConfig,\n _value: string,\n readOnly: boolean,\n outputKind: 'json' | 'markdown' | 'text'\n) {\n if (outputKind === 'json') {\n logger.log(\n JSON.stringify({\n success: true,\n message: `Config key '${key}' was updated${readOnly ? ' (Note: since at least one value was overridden from flag/env, the config was not persisted)' : ''}`,\n readOnly\n })\n )\n } else if (outputKind === 'markdown') {\n logger.log(`# Update config`)\n logger.log('')\n logger.log(`Config key '${key}' was updated`)\n if (readOnly) {\n logger.log('')\n logger.log(\n 'Note: The change was not persisted because the config is in read-only mode,\\n meaning at least one key was temporarily overridden from an env var or\\n command flag.'\n )\n }\n } else {\n logger.log(`OK`)\n if (readOnly) {\n logger.log('')\n logger.log(\n 'Note: The change was not persisted because the config is in read-only mode, meaning at least one key was temporarily overridden from an env var or command flag.'\n )\n }\n }\n}\n","import { outputConfigSet } from './output-config-set'\nimport { isReadOnlyConfig, updateConfigValue } from '../../utils/config'\n\nimport type { LocalConfig } from '../../utils/config'\n\nexport async function handleConfigSet({\n key,\n outputKind,\n value\n}: {\n key: keyof LocalConfig\n outputKind: 'json' | 'markdown' | 'text'\n value: string\n}) {\n updateConfigValue(key, value)\n const readOnly = isReadOnlyConfig()\n\n await outputConfigSet(key, value, readOnly, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleConfigSet } from './handle-config-set'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { supportedConfigKeys } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { LocalConfig } from '../../utils/config'\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'set',\n description: 'Update the value of a local CLI config item',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <key> <value>\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n This is a crude way of updating the local configuration for this CLI tool.\n\n Note that updating a value here is nothing more than updating a key/value\n store entry. No validation is happening. The server may reject your config.\n\n Keys:\n\n${Array.from(supportedConfigKeys.entries())\n .map(([key, desc]) => ` - ${key} -- ${desc}`)\n .join('\\n')}\n\n Examples\n $ ${command} apiProxy https://example.com\n `\n}\n\nexport const cmdConfigSet = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const [key = '', ...rest] = cli.input\n const value = rest.join(' ')\n\n const wasBadInput = handleBadInput(\n {\n test: key === 'test' || supportedConfigKeys.has(key as keyof LocalConfig),\n message: 'Config key should be the first arg',\n pass: 'ok',\n fail: key ? 'invalid config key' : 'missing'\n },\n {\n test: !!value, // This is a string, empty string is not ok\n message:\n 'Key value should be the remaining args (use `unset` to unset a value)',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleConfigSet({\n key: key as keyof LocalConfig,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text',\n value\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { LocalConfig } from '../../utils/config'\n\nexport async function outputConfigUnset(\n key: keyof LocalConfig,\n outputKind: 'json' | 'markdown' | 'text'\n) {\n if (outputKind === 'json') {\n logger.log(\n JSON.stringify({\n success: true,\n message: `Config key '${key}' was unset`\n })\n )\n } else if (outputKind === 'markdown') {\n logger.log(`# Update config`)\n logger.log('')\n logger.log(`Config key '${key}' was unset`)\n } else {\n logger.log(`OK`)\n }\n}\n","import { outputConfigUnset } from './output-config-unset'\nimport { updateConfigValue } from '../../utils/config'\n\nimport type { LocalConfig } from '../../utils/config'\n\nexport async function handleConfigUnset({\n key,\n outputKind\n}: {\n key: keyof LocalConfig\n outputKind: 'json' | 'markdown' | 'text'\n}) {\n updateConfigValue(key, undefined)\n await outputConfigUnset(key, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleConfigUnset } from './handle-config-unset'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { supportedConfigKeys } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { LocalConfig } from '../../utils/config'\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'unset',\n description: 'Clear the value of a local CLI config item',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug>\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Keys:\n\n${Array.from(supportedConfigKeys.entries())\n .map(([key, desc]) => ` - ${key} -- ${desc}`)\n .join('\\n')}\n\n Examples\n $ ${command} FakeOrg --repoName=test-repo\n `\n}\n\nexport const cmdConfigUnset = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const [key = ''] = cli.input\n\n const wasBadInput = handleBadInput(\n {\n test: key === 'test' || supportedConfigKeys.has(key as keyof LocalConfig),\n message: 'Config key should be the first arg',\n pass: 'ok',\n fail: key ? 'invalid config key' : 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleConfigUnset({\n key: key as keyof LocalConfig,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text'\n })\n}\n","import { cmdConfigAuto } from './cmd-config-auto'\nimport { cmdConfigGet } from './cmd-config-get'\nimport { cmdConfigList } from './cmd-config-list'\nimport { cmdConfigSet } from './cmd-config-set'\nimport { cmdConfigUnset } from './cmd-config-unset'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\n\nimport type { CliSubcommand } from '../../utils/meow-with-subcommands'\n\nconst description = 'Commands related to the local CLI configuration'\n\nexport const cmdConfig: CliSubcommand = {\n description,\n hidden: true, // [beta]\n async run(argv, importMeta, { parentName }) {\n await meowWithSubcommands(\n {\n auto: cmdConfigAuto,\n get: cmdConfigGet,\n list: cmdConfigList,\n set: cmdConfigSet,\n unset: cmdConfigUnset\n },\n {\n argv,\n description,\n importMeta,\n name: `${parentName} config`\n }\n )\n }\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchDependencies({\n limit,\n offset\n}: {\n limit: number\n offset: number\n}): Promise<SocketSdkReturnType<'searchDependencies'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching organization dependencies...')\n\n const result = await handleApiCall(\n sockSdk.searchDependencies({ limit, offset }),\n 'Searching dependencies'\n )\n\n spinner.successAndStop('Received organization dependencies response.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('searchDependencies', result)\n }\n\n return result.data\n}\n","// @ts-ignore\nimport chalkTable from 'chalk-table'\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputDependencies(\n data: SocketSdkReturnType<'searchDependencies'>['data'],\n {\n limit,\n offset,\n outputKind\n }: {\n limit: number\n offset: number\n outputKind: 'json' | 'markdown' | 'text'\n }\n): Promise<void> {\n if (outputKind === 'json') {\n let json\n try {\n json = JSON.stringify(data, null, 2)\n } catch (e) {\n process.exitCode = 1\n logger.fail(\n 'There was a problem converting the data to JSON, please try without the `--json` flag'\n )\n return\n }\n\n logger.log(json)\n return\n }\n\n logger.log(\n 'Request details: Offset:',\n offset,\n ', limit:',\n limit,\n ', is there more data after this?',\n data.end ? 'no' : 'yes'\n )\n\n const options = {\n columns: [\n { field: 'namespace', name: colors.cyan('Namespace') },\n { field: 'name', name: colors.cyan('Name') },\n { field: 'version', name: colors.cyan('Version') },\n { field: 'repository', name: colors.cyan('Repository') },\n { field: 'branch', name: colors.cyan('Branch') },\n { field: 'type', name: colors.cyan('Type') },\n { field: 'direct', name: colors.cyan('Direct') }\n ]\n }\n\n logger.log(chalkTable(options, data.rows))\n}\n","import { fetchDependencies } from './fetch-dependencies'\nimport { outputDependencies } from './output-dependencies'\n\nexport async function handleDependencies({\n limit,\n offset,\n outputKind\n}: {\n limit: number\n offset: number\n outputKind: 'json' | 'markdown' | 'text'\n}): Promise<void> {\n const data = await fetchDependencies({ limit, offset })\n if (!data) {\n return\n }\n\n await outputDependencies(data, { limit, offset, outputKind })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleDependencies } from './handle-dependencies'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'dependencies',\n description:\n 'Search for any dependency that is being used in your organization',\n hidden: false,\n flags: {\n ...commonFlags,\n limit: {\n type: 'number',\n shortFlag: 'l',\n default: 50,\n description: 'Maximum number of dependencies returned'\n },\n offset: {\n type: 'number',\n shortFlag: 'o',\n default: 0,\n description: 'Page number'\n },\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n ${command}\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: none (does need token with access to target org)\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n ${command} --limit 20 --offset 10\n `\n}\n\nexport const cmdScanCreate = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, limit, markdown, offset } = cli.flags\n\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleDependencies({\n limit: Number(limit || 0) || 0,\n offset: Number(offset || 0) || 0,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text'\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { handleApiCall, handleApiError, queryApi } from '../../utils/api'\nimport { failMsgWithBadge } from '../../utils/fail-msg-with-badge'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchDiffScan({\n after,\n before,\n orgSlug\n}: {\n after: string\n before: string\n orgSlug: string\n}): Promise<SocketSdkReturnType<'GetOrgDiffScan'>['data'] | undefined> {\n const apiToken = getDefaultToken()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching diff-scan...')\n\n const response = await queryApi(\n `orgs/${orgSlug}/full-scans/diff?before=${encodeURIComponent(before)}&after=${encodeURIComponent(after)}`,\n apiToken || ''\n )\n\n spinner.successAndStop('Received diff-scan response')\n\n if (!response.ok) {\n const err = await handleApiError(response.status)\n logger.fail(failMsgWithBadge(response.statusText, err))\n return\n }\n\n const result = await handleApiCall(\n (await response.json()) as Promise<\n SocketSdkReturnType<'GetOrgDiffScan'>['data']\n >,\n 'Deserializing json'\n )\n\n return result\n}\n","import fs from 'node:fs'\nimport util from 'node:util'\n\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputDiffScan(\n result: SocketSdkReturnType<'GetOrgDiffScan'>['data'],\n {\n depth,\n file,\n outputKind\n }: {\n depth: number\n file: string\n outputKind: 'json' | 'markdown' | 'text'\n }\n): Promise<void> {\n const dashboardUrl = result.diff_report_url\n const dashboardMessage = dashboardUrl\n ? `\\n View this diff scan in the Socket dashboard: ${colors.cyan(dashboardUrl)}`\n : ''\n\n // When forcing json, or dumping to file, serialize to string such that it\n // won't get truncated. The only way to dump the full raw JSON to stdout is\n // to use `--json --file -` (the dash is a standard notation for stdout)\n if (outputKind === 'json' || file) {\n let json\n try {\n json = JSON.stringify(result, null, 2)\n } catch (e) {\n process.exitCode = 1\n // Most likely caused by a circular reference (or OOM)\n logger.fail('There was a problem converting the data to JSON')\n logger.error(e)\n return\n }\n\n if (file && file !== '-') {\n logger.log(`Writing json to \\`${file}\\``)\n fs.writeFile(file, JSON.stringify(result, null, 2), err => {\n if (err) {\n logger.fail(`Writing to \\`${file}\\` failed...`)\n logger.error(err)\n } else {\n logger.log(`Data successfully written to \\`${file}\\``)\n }\n logger.error(dashboardMessage)\n })\n } else {\n // TODO: expose different method for writing to stderr when simply dodging stdout\n logger.error(`\\n Diff scan result: \\n`)\n logger.log(json)\n logger.error(dashboardMessage)\n }\n\n return\n }\n\n // In this case neither the --json nor the --file flag was passed\n // Dump the JSON to CLI and let NodeJS deal with truncation\n\n logger.log('Diff scan result:')\n logger.log(\n util.inspect(result, {\n showHidden: false,\n depth: depth > 0 ? depth : null,\n colors: true,\n maxArrayLength: null\n })\n )\n logger.log(\n `\\n 📝 To display the detailed report in the terminal, use the --json flag \\n`\n )\n logger.log(dashboardMessage)\n}\n","import { fetchDiffScan } from './fetch-diff-scan'\nimport { outputDiffScan } from './output-diff-scan'\n\nexport async function handleDiffScan({\n after,\n before,\n depth,\n file,\n orgSlug,\n outputKind\n}: {\n after: string\n before: string\n depth: number\n file: string\n orgSlug: string\n outputKind: 'json' | 'markdown' | 'text'\n}): Promise<void> {\n const data = await fetchDiffScan({\n after,\n before,\n orgSlug\n })\n if (!data) {\n return\n }\n\n await outputDiffScan(data, {\n depth,\n file,\n outputKind\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleDiffScan } from './handle-diff-scan'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'get',\n description: 'Get a diff scan for an organization',\n hidden: false,\n flags: {\n ...commonFlags,\n after: {\n type: 'string',\n shortFlag: 'a',\n default: '',\n description: 'The scan ID of the head scan'\n },\n before: {\n type: 'string',\n shortFlag: 'b',\n default: '',\n description: 'The scan ID of the base scan'\n },\n depth: {\n type: 'number',\n default: 2,\n description:\n 'Max depth of JSON to display before truncating, use zero for no limit (without --json/--file)'\n },\n json: {\n type: 'boolean',\n shortFlag: 'j',\n default: false,\n description:\n 'Output result as json. This can be big. Use --file to store it to disk without truncation.'\n },\n file: {\n type: 'string',\n shortFlag: 'f',\n default: '',\n description:\n 'Path to a local file where the output should be saved. Use `-` to force stdout.'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> --before=<before> --after=<after>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: full-scans:list\n\n This command displays the package changes between two scans. The full output\n can be pretty large depending on the size of your repo and time range. It is\n best stored to disk to be further analyzed by other tools.\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeCorp --before=aaa0aa0a-aaaa-0000-0a0a-0000000a00a0 --after=aaa1aa1a-aaaa-1111-1a1a-1111111a11a1\n `\n}\n\nexport const cmdDiffScanGet = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { after, before, depth, file, json, markdown } = cli.flags\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n test: !!(before && after),\n message:\n 'Specify a before and after scan ID.\\nThe args are expecting a full `aaa0aa0a-aaaa-0000-0a0a-0000000a00a0` scan ID.',\n pass: 'ok',\n fail:\n !before && !after\n ? 'missing before and after'\n : !before\n ? 'missing before'\n : 'missing after'\n },\n {\n test: !!orgSlug,\n nook: true,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n logger.fail(\n 'Warning: this command is deprecated in favor of `socket scan diff` and will be removed in the next major bump.'\n )\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleDiffScan({\n before: String(before || ''),\n after: String(after || ''),\n depth: Number(depth),\n orgSlug,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text',\n file: String(file || '')\n })\n}\n","import { cmdDiffScanGet } from './cmd-diff-scan-get'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\n\nimport type { CliSubcommand } from '../../utils/meow-with-subcommands'\n\nconst description = 'Diff scans related commands'\n\nexport const cmdDiffScan: CliSubcommand = {\n description,\n // Hidden because it was broken all this time (nobody could be using it)\n // and we're not sure if it's useful to anyone in its current state.\n // Until we do, we'll hide this to keep the help tidier.\n // And later, we may simply move this under `scan`, anyways.\n hidden: true,\n async run(argv, importMeta, { parentName }) {\n await meowWithSubcommands(\n {\n get: cmdDiffScanGet\n },\n {\n argv,\n description,\n importMeta,\n name: parentName + ' diff-scan'\n }\n )\n }\n}\n","import path from 'node:path'\n\nimport { PackageURL } from '@socketregistry/packageurl-js'\nimport { debugLog } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { normalizePath } from '@socketsecurity/registry/lib/path'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport constants from '../../constants'\n\nconst { GITHUB_REF_NAME } = constants\n\nfunction formatBranchName(str: string): string {\n return str\n .replace(/[\\\\/-_.]+/g, '-')\n .replace(/[^-a-zA-Z0-9]+/g, '')\n .replace(/^-+|-+$/g, '')\n}\n\nfunction getPkgNameFromPurlObj(purlObj: PackageURL): string {\n return `${purlObj.namespace ? `${purlObj.namespace}/` : ''}${purlObj.name}`\n}\n\nexport function getBaseGitBranch() {\n // Lazily access constants.ENV[GITHUB_REF_NAME].\n return (\n constants.ENV[GITHUB_REF_NAME] ??\n // GitHub defaults to branch name \"main\"\n // https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-branches#about-the-default-branch\n 'main'\n )\n}\n\nexport function getSocketBranchName(\n purl: string,\n newVersion: string,\n workspaceName?: string | undefined\n): string {\n const purlObj = PackageURL.fromString(purl)\n const maybeWorkspaceName = workspaceName\n ? `${formatBranchName(workspaceName)}-`\n : ''\n const maybeNamespace = purlObj.namespace\n ? `${formatBranchName(purlObj.namespace)}-`\n : ''\n const fullName = `${maybeWorkspaceName}${maybeNamespace}${formatBranchName(purlObj.name)}`\n return `socket-fix-${fullName}-${formatBranchName(newVersion)}`\n}\n\nexport function getSocketPullRequestTitle(\n purl: string,\n newVersion: string,\n workspaceName?: string | undefined\n): string {\n const purlObj = PackageURL.fromString(purl)\n const pkgName = getPkgNameFromPurlObj(purlObj)\n const workspaceDetails = workspaceName ? ` in ${workspaceName}` : ''\n return `Bump ${pkgName} from ${purlObj.version} to ${newVersion}${workspaceDetails}`\n}\n\nexport function getSocketPullRequestBody(\n purl: string,\n newVersion: string,\n workspaceName?: string | undefined\n): string {\n const purlObj = PackageURL.fromString(purl)\n const pkgName = getPkgNameFromPurlObj(purlObj)\n const workspaceDetails = workspaceName ? ` in ${workspaceName}` : ''\n return `Bumps [${pkgName}](https://socket.dev/${purlObj.type}/package/${pkgName}) from ${purlObj.version} to ${newVersion}${workspaceDetails}.`\n}\n\nexport function getSocketCommitMessage(\n purl: string,\n newVersion: string,\n workspaceName?: string | undefined\n): string {\n const purlObj = PackageURL.fromString(purl)\n const pkgName = getPkgNameFromPurlObj(purlObj)\n const workspaceDetails = workspaceName ? ` in ${workspaceName}` : ''\n return `socket: Bump ${pkgName} from ${purlObj.version} to ${newVersion}${workspaceDetails}`\n}\n\nexport async function gitBranchExists(\n branch: string,\n cwd: string | undefined = process.cwd()\n): Promise<boolean> {\n try {\n await spawn(\n 'git',\n ['show-ref', '--verify', '--quiet', `refs/heads/${branch}`],\n {\n cwd,\n stdio: 'ignore'\n }\n )\n return true\n } catch {}\n return false\n}\n\nexport async function gitCheckoutBaseBranchIfAvailable(\n baseBranch: string,\n cwd = process.cwd()\n) {\n try {\n await gitHardReset()\n await spawn('git', ['fetch', '--depth=1', 'origin', baseBranch], { cwd })\n await spawn('git', ['checkout', baseBranch], { cwd })\n await spawn('git', ['reset', '--hard', `origin/${baseBranch}`], { cwd })\n logger.info(`Checked out and reset to ${baseBranch}`)\n } catch (e) {\n logger.warn(`Could not switch to ${baseBranch}. Proceeding with HEAD.`)\n debugLog(e)\n }\n}\n\nexport async function gitCreateAndPushBranchIfNeeded(\n branch: string,\n commitMsg: string,\n cwd = process.cwd()\n): Promise<boolean> {\n if (await gitBranchExists(branch, cwd)) {\n logger.warn(`Branch \"${branch}\" already exists. Skipping creation.`)\n return false\n }\n await spawn('git', ['checkout', '-b', branch], { cwd })\n const moddedFilepaths = (await gitUnstagedModifiedFiles(cwd)).filter(p => {\n const basename = path.basename(p)\n return (\n basename === 'package.json' ||\n basename === 'package-lock.json' ||\n basename === 'pnpm-lock.yaml'\n )\n })\n debugLog('branch', branch)\n debugLog('gitCreateAndPushBranchIfNeeded > moddedFilepaths', moddedFilepaths)\n if (moddedFilepaths.length) {\n await spawn('git', ['add', ...moddedFilepaths], { cwd })\n }\n await spawn('git', ['commit', '-m', commitMsg], { cwd })\n await spawn('git', ['push', '--set-upstream', 'origin', branch], { cwd })\n return true\n}\n\nexport async function gitHardReset(cwd = process.cwd()): Promise<void> {\n await spawn('git', ['reset', '--hard'], { cwd })\n}\n\nasync function gitUnstagedModifiedFiles(\n cwd = process.cwd()\n): Promise<string[]> {\n const { stdout } = await spawn('git', ['diff', '--name-only'], { cwd })\n const rawFiles = stdout?.trim().split('\\n') ?? []\n return rawFiles.map(relPath => normalizePath(relPath))\n}\n\nexport async function isInGitRepo(cwd = process.cwd()): Promise<boolean> {\n try {\n await spawn('git', ['rev-parse', '--is-inside-work-tree'], {\n cwd,\n stdio: 'ignore'\n })\n return true\n } catch {}\n return false\n}\n","import {\n GraphqlResponseError,\n graphql as OctokitGraphql\n} from '@octokit/graphql'\nimport { RequestError } from '@octokit/request-error'\nimport { Octokit } from '@octokit/rest'\nimport { codeBlock } from 'common-tags'\n\nimport { debugLog } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport { getSocketPullRequestBody, getSocketPullRequestTitle } from './git'\nimport constants from '../../constants'\n\nimport type { components } from '@octokit/openapi-types'\nimport type { OctokitResponse } from '@octokit/types'\n\ntype PullsCreateResponseData = components['schemas']['pull-request']\n\nconst { GITHUB_ACTIONS, GITHUB_REPOSITORY, SOCKET_SECURITY_GITHUB_PAT } =\n constants\n\ntype GitHubRepoInfo = {\n owner: string\n repo: string\n}\n\nlet _octokit: Octokit | undefined\nfunction getOctokit() {\n if (_octokit === undefined) {\n _octokit = new Octokit({\n // Lazily access constants.ENV[SOCKET_SECURITY_GITHUB_PAT].\n auth: constants.ENV[SOCKET_SECURITY_GITHUB_PAT]\n })\n }\n return _octokit\n}\n\nlet _octokitGraphql: typeof OctokitGraphql | undefined\nexport function getOctokitGraphql() {\n if (!_octokitGraphql) {\n _octokitGraphql = OctokitGraphql.defaults({\n headers: {\n // Lazily access constants.ENV[SOCKET_SECURITY_GITHUB_PAT].\n authorization: `token ${constants.ENV[SOCKET_SECURITY_GITHUB_PAT]}`\n }\n })\n }\n return _octokitGraphql\n}\n\nexport async function doesPullRequestExistForBranch(\n owner: string,\n repo: string,\n branch: string\n): Promise<boolean> {\n const octokit = getOctokit()\n try {\n const { data: prs } = await octokit.pulls.list({\n owner,\n repo,\n head: `${owner}:${branch}`,\n state: 'open'\n })\n debugLog('doesPullRequestExistForBranch > prs', prs)\n return prs.length > 0\n } catch {}\n return false\n}\n\nexport async function enableAutoMerge({\n node_id: prId,\n number: prNumber\n}: PullsCreateResponseData): Promise<boolean> {\n const octokitGraphql = getOctokitGraphql()\n try {\n await octokitGraphql(\n codeBlock`\n mutation EnableAutoMerge($pullRequestId: ID!) {\n enablePullRequestAutoMerge(input: {\n pullRequestId: $pullRequestId,\n mergeMethod: SQUASH\n }) {\n pullRequest {\n number\n autoMergeRequest {\n enabledAt\n }\n }\n }\n }\n `,\n {\n pullRequestId: prId\n }\n )\n logger.info(`Auto-merge enabled for PR #${prNumber}`)\n return true\n } catch (e) {\n let message = `Failed to enable auto-merge for PR #${prNumber}`\n if (e instanceof GraphqlResponseError && e.errors) {\n const details = e.errors\n .map(({ message }) => ` - ${message.trim()}`)\n .join('\\n')\n message += `:\\n${details}`\n }\n logger.error(message)\n return false\n }\n}\n\nexport function getGitHubEnvRepoInfo(): GitHubRepoInfo {\n // Lazily access constants.ENV[GITHUB_REPOSITORY].\n const ownerSlashRepo = constants.ENV[GITHUB_REPOSITORY]\n const slashIndex = ownerSlashRepo.indexOf('/')\n if (slashIndex === -1) {\n throw new Error('Missing GITHUB_REPOSITORY environment variable')\n }\n return {\n owner: ownerSlashRepo.slice(0, slashIndex),\n repo: ownerSlashRepo.slice(slashIndex + 1)\n }\n}\n\nexport type OpenGitHubPullRequestOptions = {\n cwd?: string | undefined\n workspaceName?: string | undefined\n}\n\nexport async function openGitHubPullRequest(\n owner: string,\n repo: string,\n baseBranch: string,\n branch: string,\n purl: string,\n newVersion: string,\n options?: OpenGitHubPullRequestOptions | undefined\n): Promise<OctokitResponse<PullsCreateResponseData> | null> {\n const { cwd = process.cwd(), workspaceName } = {\n __proto__: null,\n ...options\n } as OpenGitHubPullRequestOptions\n // Lazily access constants.ENV[GITHUB_ACTIONS].\n if (constants.ENV[GITHUB_ACTIONS]) {\n // Lazily access constants.ENV[SOCKET_SECURITY_GITHUB_PAT].\n const pat = constants.ENV[SOCKET_SECURITY_GITHUB_PAT]\n if (!pat) {\n throw new Error('Missing SOCKET_SECURITY_GITHUB_PAT environment variable')\n }\n const url = `https://x-access-token:${pat}@github.com/${owner}/${repo}`\n await spawn('git', ['remote', 'set-url', 'origin', url], {\n cwd\n })\n const octokit = getOctokit()\n try {\n return await octokit.pulls.create({\n owner,\n repo,\n title: getSocketPullRequestTitle(purl, newVersion, workspaceName),\n head: branch,\n base: baseBranch,\n body: getSocketPullRequestBody(purl, newVersion, workspaceName)\n })\n } catch (e) {\n let message = `Failed to open pull request`\n if (e instanceof RequestError) {\n const restErrors = (e.response?.data as any)?.['errors']\n if (Array.isArray(restErrors)) {\n const details = restErrors\n .map(\n restErr =>\n `- ${restErr.message?.trim() ?? `${restErr.resource}.${restErr.field} (${restErr.code})`}`\n )\n .join('\\n')\n message += `:\\n${details}`\n }\n }\n logger.error(message)\n return null\n }\n }\n throw new Error('Missing GITHUB_ACTIONS environment variable')\n}\n","import path from 'node:path'\n\nimport { getManifestData } from '@socketsecurity/registry'\nimport { arrayUnique } from '@socketsecurity/registry/lib/arrays'\nimport { runScript } from '@socketsecurity/registry/lib/npm'\nimport {\n fetchPackagePackument,\n readPackageJson\n} from '@socketsecurity/registry/lib/packages'\n\nimport {\n getBaseGitBranch,\n getSocketBranchName,\n getSocketCommitMessage,\n gitCheckoutBaseBranchIfAvailable,\n gitCreateAndPushBranchIfNeeded,\n gitHardReset,\n isInGitRepo\n} from './git'\nimport {\n doesPullRequestExistForBranch,\n enableAutoMerge,\n getGitHubEnvRepoInfo,\n openGitHubPullRequest\n} from './open-pr'\nimport { NormalizedFixOptions } from './types'\nimport constants from '../../constants'\nimport {\n Arborist,\n SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES,\n SafeArborist\n} from '../../shadow/npm/arborist/lib/arborist'\nimport {\n getAlertsMapFromArborist,\n getAlertsMapFromPurls\n} from '../../utils/alerts-map'\nimport {\n findPackageNode,\n findPackageNodes,\n updateNode,\n updatePackageJsonFromNode\n} from '../../utils/arborist-helpers'\nimport { globWorkspace } from '../../utils/glob'\nimport { applyRange } from '../../utils/semver'\nimport { getCveInfoByAlertsMap } from '../../utils/socket-package-alert'\n\nimport type { SafeNode } from '../../shadow/npm/arborist/lib/node'\nimport type { EnvDetails } from '../../utils/package-environment'\nimport type { PackageJson } from '@socketsecurity/registry/lib/packages'\n\nconst { CI, NPM } = constants\n\ntype InstallOptions = {\n cwd?: string | undefined\n}\n\nasync function install(\n idealTree: SafeNode,\n options: InstallOptions\n): Promise<void> {\n const { cwd = process.cwd() } = {\n __proto__: null,\n ...options\n } as InstallOptions\n const arb2 = new Arborist({ path: cwd })\n arb2.idealTree = idealTree\n await arb2.reify()\n}\n\nexport async function npmFix(\n pkgEnvDetails: EnvDetails,\n {\n autoMerge,\n cwd,\n purls,\n rangeStyle,\n spinner,\n test,\n testScript\n }: NormalizedFixOptions\n) {\n spinner?.start()\n\n const arb = new SafeArborist({\n path: pkgEnvDetails.pkgPath,\n ...SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES\n })\n // Calling arb.reify() creates the arb.diff object and nulls-out arb.idealTree.\n await arb.reify()\n\n const alertMapOptions = {\n consolidate: true,\n include: {\n existing: true,\n unfixable: false,\n upgradable: false\n },\n nothrow: true\n }\n\n const alertsMap = purls.length\n ? await getAlertsMapFromPurls(purls, alertMapOptions)\n : await getAlertsMapFromArborist(arb, alertMapOptions)\n\n const infoByPkg = getCveInfoByAlertsMap(alertsMap)\n if (!infoByPkg) {\n spinner?.stop()\n return\n }\n\n // Lazily access constants.ENV[CI].\n const isCi = constants.ENV[CI]\n const { pkgPath: rootPath } = pkgEnvDetails\n\n const { 0: isRepo, 1: workspacePkgJsonPaths } = await Promise.all([\n isInGitRepo(cwd),\n globWorkspace(pkgEnvDetails)\n ])\n const pkgJsonPaths = [\n pkgEnvDetails.editablePkgJson.filename!,\n ...workspacePkgJsonPaths\n ]\n\n await arb.buildIdealTree()\n\n for (const { 0: name, 1: infos } of infoByPkg) {\n const hasUpgrade = !!getManifestData(NPM, name)\n if (hasUpgrade) {\n spinner?.info(`Skipping ${name}. Socket Optimize package exists.`)\n continue\n }\n const oldVersions = arrayUnique(\n findPackageNodes(arb.idealTree!, name).map(n => n.version)\n )\n const packument =\n oldVersions.length && infos.length\n ? // eslint-disable-next-line no-await-in-loop\n await fetchPackagePackument(name)\n : null\n if (!packument) {\n continue\n }\n\n const failedSpecs = new Set<string>()\n const fixedSpecs = new Set<string>()\n const installedSpecs = new Set<string>()\n const testedSpecs = new Set<string>()\n const unavailableSpecs = new Set<string>()\n const revertedSpecs = new Set<string>()\n\n for (const oldVersion of oldVersions) {\n const oldSpec = `${name}@${oldVersion}`\n const oldPurl = `pkg:npm/${oldSpec}`\n for (const {\n firstPatchedVersionIdentifier,\n vulnerableVersionRange\n } of infos) {\n const revertTree = arb.idealTree!\n arb.idealTree = null\n // eslint-disable-next-line no-await-in-loop\n await arb.buildIdealTree()\n const node = findPackageNode(arb.idealTree!, name, oldVersion)\n if (!node) {\n continue\n }\n if (\n !updateNode(\n node,\n packument,\n vulnerableVersionRange,\n firstPatchedVersionIdentifier\n )\n ) {\n if (!unavailableSpecs.has(oldSpec)) {\n unavailableSpecs.add(oldSpec)\n spinner?.fail(`No update available for ${oldSpec}`)\n }\n continue\n }\n\n for (const pkgJsonPath of pkgJsonPaths) {\n const isWorkspaceRoot =\n pkgJsonPath === pkgEnvDetails.editablePkgJson.filename\n const workspaceName = isWorkspaceRoot\n ? ''\n : path.relative(rootPath, path.dirname(pkgJsonPath))\n const workspaceDetails = workspaceName ? ` in ${workspaceName}` : ''\n const editablePkgJson = isWorkspaceRoot\n ? pkgEnvDetails.editablePkgJson\n : // eslint-disable-next-line no-await-in-loop\n await readPackageJson(pkgJsonPath, { editable: true })\n\n const newVersion = node.package.version!\n const newVersionRange = applyRange(oldVersion, newVersion, rangeStyle)\n const newSpec = `${name}@${newVersionRange}`\n const newSpecKey = `${workspaceName ? `${workspaceName}>` : ''}${newSpec}`\n\n const revertData = {\n ...(editablePkgJson.content.dependencies\n ? { dependencies: editablePkgJson.content.dependencies }\n : undefined),\n ...(editablePkgJson.content.optionalDependencies\n ? {\n optionalDependencies:\n editablePkgJson.content.optionalDependencies\n }\n : undefined),\n ...(editablePkgJson.content.peerDependencies\n ? { peerDependencies: editablePkgJson.content.peerDependencies }\n : undefined)\n } as PackageJson\n\n const branch = isCi\n ? getSocketBranchName(oldPurl, newVersion, workspaceName)\n : ''\n const baseBranch = isCi ? getBaseGitBranch() : ''\n const { owner, repo } = isCi\n ? getGitHubEnvRepoInfo()\n : { owner: '', repo: '' }\n const shouldOpenPr = isCi\n ? // eslint-disable-next-line no-await-in-loop\n !(await doesPullRequestExistForBranch(owner, repo, branch))\n : false\n\n if (isCi) {\n // eslint-disable-next-line no-await-in-loop\n await gitCheckoutBaseBranchIfAvailable(baseBranch, cwd)\n }\n\n updatePackageJsonFromNode(\n editablePkgJson,\n arb.idealTree!,\n node,\n newVersion,\n rangeStyle\n )\n\n let error: unknown\n let errored = false\n let installed = false\n let saved = false\n\n // eslint-disable-next-line no-await-in-loop\n if (await editablePkgJson.save()) {\n saved = true\n }\n\n if (!installedSpecs.has(newSpecKey)) {\n testedSpecs.add(newSpecKey)\n spinner?.info(`Installing ${newSpec}${workspaceDetails}`)\n }\n\n try {\n // eslint-disable-next-line no-await-in-loop\n await install(arb.idealTree!, { cwd })\n installed = true\n\n if (test) {\n if (!testedSpecs.has(newSpecKey)) {\n testedSpecs.add(newSpecKey)\n spinner?.info(`Testing ${newSpec}${workspaceDetails}`)\n }\n // eslint-disable-next-line no-await-in-loop\n await runScript(testScript, [], { spinner, stdio: 'ignore' })\n }\n if (!fixedSpecs.has(newSpecKey)) {\n fixedSpecs.add(newSpecKey)\n spinner?.successAndStop(`Fixed ${name}${workspaceDetails}`)\n spinner?.start()\n }\n } catch (e) {\n error = e\n errored = true\n }\n\n if (!errored && shouldOpenPr) {\n // eslint-disable-next-line no-await-in-loop\n await gitCreateAndPushBranchIfNeeded(\n branch,\n getSocketCommitMessage(oldPurl, newVersion, workspaceName),\n cwd\n )\n // eslint-disable-next-line no-await-in-loop\n const prResponse = await openGitHubPullRequest(\n owner,\n repo,\n baseBranch,\n branch,\n oldPurl,\n newVersion,\n {\n cwd,\n workspaceName\n }\n )\n if (prResponse && autoMerge) {\n // eslint-disable-next-line no-await-in-loop\n await enableAutoMerge(prResponse.data)\n }\n }\n\n if (errored || isCi) {\n if (errored) {\n if (!revertedSpecs.has(newSpecKey)) {\n revertedSpecs.add(newSpecKey)\n spinner?.error(`Reverting ${newSpec}${workspaceDetails}`, error)\n }\n }\n if (isRepo) {\n // eslint-disable-next-line no-await-in-loop\n await gitHardReset(cwd)\n }\n if (saved) {\n editablePkgJson.update(revertData)\n if (!isRepo) {\n // eslint-disable-next-line no-await-in-loop\n await editablePkgJson.save()\n }\n }\n if (!isRepo && installed) {\n // eslint-disable-next-line no-await-in-loop\n await install(revertTree, { cwd })\n }\n if (errored) {\n if (!failedSpecs.has(newSpecKey)) {\n failedSpecs.add(newSpecKey)\n spinner?.failAndStop(\n `Update failed for ${oldSpec}${workspaceDetails}`\n )\n }\n }\n }\n }\n }\n }\n }\n spinner?.stop()\n}\n","import process from 'node:process'\n\nimport { isDebug } from '@socketsecurity/registry/lib/debug'\nimport {\n isAuditFlag,\n isFundFlag,\n isLoglevelFlag,\n isProgressFlag\n} from '@socketsecurity/registry/lib/npm'\nimport { isObject } from '@socketsecurity/registry/lib/objects'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport constants from '../constants'\nimport { getNpmBinPath } from '../shadow/npm/paths'\n\nimport type { Spinner } from '@socketsecurity/registry/lib/spinner'\n\nconst {\n NPM,\n SOCKET_CLI_SAFE_BIN,\n SOCKET_CLI_SAFE_PROGRESS,\n SOCKET_IPC_HANDSHAKE\n} = constants\n\ntype SpawnOption = Exclude<Parameters<typeof spawn>[2], undefined>\n\ntype SafeNpmInstallOptions = SpawnOption & {\n agentExecPath?: string | undefined\n args?: string[] | readonly string[] | undefined\n ipc?: object | undefined\n spinner?: Spinner | undefined\n}\n\nexport function safeNpmInstall(options?: SafeNpmInstallOptions) {\n const {\n agentExecPath = getNpmBinPath(),\n args = [],\n ipc,\n spinner,\n ...spawnOptions\n } = { __proto__: null, ...options } as SafeNpmInstallOptions\n let stdio = spawnOptions.stdio\n const useIpc = isObject(ipc)\n // Include 'ipc' in the spawnOptions.stdio when an options.ipc object is provided.\n // See https://github.com/nodejs/node/blob/v23.6.0/lib/child_process.js#L161-L166\n // and https://github.com/nodejs/node/blob/v23.6.0/lib/internal/child_process.js#L238.\n if (typeof stdio === 'string') {\n stdio = useIpc ? [stdio, stdio, stdio, 'ipc'] : [stdio, stdio, stdio]\n } else if (useIpc && Array.isArray(stdio) && !stdio.includes('ipc')) {\n stdio = stdio.concat('ipc')\n }\n const useDebug = isDebug()\n const terminatorPos = args.indexOf('--')\n const rawBinArgs = terminatorPos === -1 ? args : args.slice(0, terminatorPos)\n const progressArg = rawBinArgs.findLast(isProgressFlag) !== '--no-progress'\n const binArgs = rawBinArgs.filter(\n a => !isAuditFlag(a) && !isFundFlag(a) && !isProgressFlag(a)\n )\n const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos)\n const isSilent = !useDebug && !binArgs.some(isLoglevelFlag)\n const logLevelArgs = isSilent ? ['--loglevel', 'silent'] : []\n const spawnPromise = spawn(\n // Lazily access constants.execPath.\n constants.execPath,\n [\n // Lazily access constants.nodeHardenFlags.\n ...constants.nodeHardenFlags,\n // Lazily access constants.nodeNoWarningsFlags.\n ...constants.nodeNoWarningsFlags,\n // Lazily access process.env['INLINED_SOCKET_CLI_SENTRY_BUILD'].\n ...(process.env['INLINED_SOCKET_CLI_SENTRY_BUILD']\n ? [\n '--require',\n // Lazily access constants.distInstrumentWithSentryPath.\n constants.distInstrumentWithSentryPath\n ]\n : []),\n '--require',\n // Lazily access constants.distShadowNpmInjectPath.\n constants.distShadowNpmInjectPath,\n agentExecPath,\n 'install',\n // Avoid code paths for 'audit' and 'fund'.\n '--no-audit',\n '--no-fund',\n // Add '--no-progress' to fix input being swallowed by the npm spinner.\n '--no-progress',\n // Add '--loglevel=silent' if a loglevel flag is not provided and the\n // SOCKET_CLI_DEBUG environment variable is not truthy.\n ...logLevelArgs,\n ...binArgs,\n ...otherArgs\n ],\n {\n spinner,\n ...spawnOptions,\n stdio,\n env: {\n ...process.env,\n ...spawnOptions.env\n }\n }\n )\n if (useIpc) {\n spawnPromise.process.send({\n [SOCKET_IPC_HANDSHAKE]: {\n [SOCKET_CLI_SAFE_BIN]: NPM,\n [SOCKET_CLI_SAFE_PROGRESS]: progressArg,\n ...ipc\n }\n })\n }\n return spawnPromise\n}\n","import { spawn } from '@socketsecurity/registry/lib/spawn'\nimport { Spinner } from '@socketsecurity/registry/lib/spinner'\n\nimport constants from '../constants'\nimport { cmdFlagsToString } from './cmd'\nimport { safeNpmInstall } from './npm'\n\nimport type { EnvDetails } from './package-environment'\n\nconst { NPM, PNPM } = constants\n\ntype SpawnOption = Exclude<Parameters<typeof spawn>[2], undefined>\n\ntype SpawnResult = ReturnType<typeof spawn>\n\nexport type AgentInstallOptions = SpawnOption & {\n args?: string[] | readonly string[] | undefined\n spinner?: Spinner | undefined\n}\n\nexport function runAgentInstall(\n pkgEnvDetails: EnvDetails,\n options?: AgentInstallOptions | undefined\n): SpawnResult {\n const { agent, agentExecPath } = pkgEnvDetails\n // All package managers support the \"install\" command.\n if (agent === NPM) {\n return safeNpmInstall({\n agentExecPath,\n ...options\n })\n }\n const {\n args = [],\n spinner,\n ...spawnOptions\n } = { __proto__: null, ...options } as AgentInstallOptions\n const skipNodeHardenFlags =\n agent === PNPM && pkgEnvDetails.agentVersion.major < 11\n return spawn(agentExecPath, ['install', ...args], {\n spinner,\n stdio: 'inherit',\n ...spawnOptions,\n env: {\n ...process.env,\n NODE_OPTIONS: cmdFlagsToString([\n ...(skipNodeHardenFlags\n ? []\n : // Lazily access constants.nodeHardenFlags.\n constants.nodeHardenFlags),\n // Lazily access constants.nodeNoWarningsFlags.\n ...constants.nodeNoWarningsFlags\n ]),\n ...spawnOptions.env\n }\n })\n}\n","import path from 'node:path'\n\nimport { readWantedLockfile } from '@pnpm/lockfile.fs'\n\nimport { getManifestData } from '@socketsecurity/registry'\nimport { arrayUnique } from '@socketsecurity/registry/lib/arrays'\nimport { debugLog, isDebug } from '@socketsecurity/registry/lib/debug'\nimport { runScript } from '@socketsecurity/registry/lib/npm'\nimport {\n fetchPackagePackument,\n readPackageJson\n} from '@socketsecurity/registry/lib/packages'\n\nimport {\n getBaseGitBranch,\n getSocketBranchName,\n getSocketCommitMessage,\n gitCheckoutBaseBranchIfAvailable,\n gitCreateAndPushBranchIfNeeded,\n gitHardReset,\n isInGitRepo\n} from './git'\nimport {\n doesPullRequestExistForBranch,\n enableAutoMerge,\n getGitHubEnvRepoInfo,\n openGitHubPullRequest\n} from './open-pr'\nimport constants from '../../constants'\nimport {\n SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES,\n SafeArborist\n} from '../../shadow/npm/arborist/lib/arborist'\nimport { runAgentInstall } from '../../utils/agent'\nimport {\n getAlertsMapFromPnpmLockfile,\n getAlertsMapFromPurls\n} from '../../utils/alerts-map'\nimport {\n findBestPatchVersion,\n findPackageNode,\n findPackageNodes,\n updatePackageJsonFromNode\n} from '../../utils/arborist-helpers'\nimport { globWorkspace } from '../../utils/glob'\nimport { applyRange } from '../../utils/semver'\nimport { getCveInfoByAlertsMap } from '../../utils/socket-package-alert'\n\nimport type { NormalizedFixOptions } from './types'\nimport type { SafeNode } from '../../shadow/npm/arborist/lib/node'\nimport type { StringKeyValueObject } from '../../types'\nimport type { EnvDetails } from '../../utils/package-environment'\nimport type { PackageJson } from '@socketsecurity/registry/lib/packages'\nimport type { Spinner } from '@socketsecurity/registry/lib/spinner'\n\nconst { CI, NPM, OVERRIDES, PNPM } = constants\n\ntype InstallOptions = {\n cwd?: string | undefined\n spinner?: Spinner | undefined\n}\n\nasync function getActualTree(cwd: string = process.cwd()): Promise<SafeNode> {\n const arb = new SafeArborist({\n path: cwd,\n ...SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES\n })\n return await arb.loadActual()\n}\n\nasync function install(\n pkgEnvDetails: EnvDetails,\n options: InstallOptions\n): Promise<SafeNode> {\n const { cwd, spinner } = { __proto__: null, ...options } as InstallOptions\n await runAgentInstall(pkgEnvDetails, {\n args: ['--no-frozen-lockfile'],\n spinner,\n stdio: isDebug() ? 'inherit' : 'ignore'\n })\n return await getActualTree(cwd)\n}\n\nexport async function pnpmFix(\n pkgEnvDetails: EnvDetails,\n {\n autoMerge,\n cwd,\n purls,\n rangeStyle,\n spinner,\n test,\n testScript\n }: NormalizedFixOptions\n) {\n const lockfile = await readWantedLockfile(pkgEnvDetails.pkgPath, {\n ignoreIncompatible: false\n })\n if (!lockfile) {\n return\n }\n\n const alertMapOptions = {\n consolidate: true,\n include: { existing: true, unfixable: false, upgradable: false },\n nothrow: true\n }\n\n const alertsMap = purls.length\n ? await getAlertsMapFromPurls(purls, alertMapOptions)\n : await getAlertsMapFromPnpmLockfile(lockfile, alertMapOptions)\n\n const infoByPkg = getCveInfoByAlertsMap(alertsMap)\n if (!infoByPkg) {\n return\n }\n\n spinner?.start()\n\n // Lazily access constants.ENV[CI].\n const isCi = constants.ENV[CI]\n const { pkgPath: rootPath } = pkgEnvDetails\n\n const {\n 0: isRepo,\n 1: workspacePkgJsonPaths,\n 2: initialTree\n } = await Promise.all([\n isInGitRepo(cwd),\n globWorkspace(pkgEnvDetails),\n getActualTree(cwd)\n ])\n const pkgJsonPaths = [\n pkgEnvDetails.editablePkgJson.filename!,\n ...workspacePkgJsonPaths\n ]\n\n debugLog('workspacePkgJsonPaths', workspacePkgJsonPaths)\n\n let actualTree = initialTree\n\n for (const { 0: name, 1: infos } of infoByPkg) {\n if (getManifestData(NPM, name)) {\n spinner?.info(`Skipping ${name}. Socket Optimize package exists.`)\n continue\n }\n const oldVersions = arrayUnique(\n findPackageNodes(actualTree, name).map(n => n.version)\n )\n const packument =\n oldVersions.length && infos.length\n ? // eslint-disable-next-line no-await-in-loop\n await fetchPackagePackument(name)\n : null\n if (!packument) {\n continue\n }\n\n const failedSpecs = new Set<string>()\n const fixedSpecs = new Set<string>()\n const installedSpecs = new Set<string>()\n const testedSpecs = new Set<string>()\n const unavailableSpecs = new Set<string>()\n const revertedSpecs = new Set<string>()\n\n for (const oldVersion of oldVersions) {\n const oldSpec = `${name}@${oldVersion}`\n const oldPurl = `pkg:npm/${oldSpec}`\n\n for (const {\n firstPatchedVersionIdentifier,\n vulnerableVersionRange\n } of infos) {\n const node = findPackageNode(actualTree, name, oldVersion)\n if (!node) {\n continue\n }\n\n const availableVersions = Object.keys(packument.versions)\n const newVersion = findBestPatchVersion(\n node,\n availableVersions,\n vulnerableVersionRange,\n firstPatchedVersionIdentifier\n )\n const newVersionPackument = newVersion\n ? packument.versions[newVersion]\n : undefined\n\n if (!(newVersion && newVersionPackument)) {\n if (!unavailableSpecs.has(oldSpec)) {\n unavailableSpecs.add(oldSpec)\n spinner?.fail(`No update available for ${oldSpec}`)\n }\n continue\n }\n\n debugLog('pkgJsonPaths', pkgJsonPaths)\n for (const pkgJsonPath of pkgJsonPaths) {\n const isWorkspaceRoot =\n pkgJsonPath === pkgEnvDetails.editablePkgJson.filename\n const workspaceName = isWorkspaceRoot\n ? ''\n : path.relative(rootPath, path.dirname(pkgJsonPath))\n const workspaceDetails = workspaceName ? ` in ${workspaceName}` : ''\n const editablePkgJson = isWorkspaceRoot\n ? pkgEnvDetails.editablePkgJson\n : // eslint-disable-next-line no-await-in-loop\n await readPackageJson(pkgJsonPath, { editable: true })\n\n const oldPnpm = editablePkgJson.content[PNPM] as\n | StringKeyValueObject\n | undefined\n const oldPnpmKeyCount = oldPnpm ? Object.keys(oldPnpm).length : 0\n const oldOverrides = (oldPnpm as StringKeyValueObject)?.[OVERRIDES] as\n | Record<string, string>\n | undefined\n const oldOverridesCount = oldOverrides\n ? Object.keys(oldOverrides).length\n : 0\n\n const overrideKey = `${name}@${vulnerableVersionRange}`\n const newVersionRange = applyRange(\n oldOverrides?.[overrideKey] ?? oldVersion,\n newVersion,\n rangeStyle\n )\n const newSpec = `${name}@${newVersionRange}`\n const newSpecKey = `${workspaceName ? `${workspaceName}>` : ''}${newSpec}`\n\n const updateData = isWorkspaceRoot\n ? {\n [PNPM]: {\n ...oldPnpm,\n [OVERRIDES]: {\n [overrideKey]: newVersionRange,\n ...oldOverrides\n }\n }\n }\n : undefined\n\n const revertData = {\n ...(isWorkspaceRoot\n ? {\n [PNPM]: oldPnpmKeyCount\n ? {\n ...oldPnpm,\n [OVERRIDES]:\n oldOverridesCount === 1\n ? undefined\n : {\n [overrideKey]: undefined,\n ...oldOverrides\n }\n }\n : undefined\n }\n : {}),\n ...(editablePkgJson.content.dependencies\n ? { dependencies: editablePkgJson.content.dependencies }\n : undefined),\n ...(editablePkgJson.content.optionalDependencies\n ? {\n optionalDependencies:\n editablePkgJson.content.optionalDependencies\n }\n : undefined),\n ...(editablePkgJson.content.peerDependencies\n ? { peerDependencies: editablePkgJson.content.peerDependencies }\n : undefined)\n } as PackageJson\n\n const branch = isCi\n ? getSocketBranchName(oldPurl, newVersion, workspaceName)\n : ''\n const baseBranch = isCi ? getBaseGitBranch() : ''\n const { owner, repo } = isCi\n ? getGitHubEnvRepoInfo()\n : { owner: '', repo: '' }\n const shouldOpenPr = isCi\n ? // eslint-disable-next-line no-await-in-loop\n !(await doesPullRequestExistForBranch(owner, repo, branch))\n : false\n\n if (isCi) {\n // eslint-disable-next-line no-await-in-loop\n await gitCheckoutBaseBranchIfAvailable(baseBranch, cwd)\n }\n\n if (updateData) {\n editablePkgJson.update(updateData)\n }\n\n const modded = updatePackageJsonFromNode(\n editablePkgJson,\n actualTree,\n node,\n newVersion,\n rangeStyle\n )\n debugLog('updatePackageJsonFromNode', modded)\n debugLog(branch, editablePkgJson.filename)\n let error: unknown\n let errored = false\n let installed = false\n\n // eslint-disable-next-line no-await-in-loop\n if (!(await editablePkgJson.save())) {\n debugLog(`Skipping nothing changed in ${editablePkgJson.filename}`)\n continue\n }\n\n if (!installedSpecs.has(newSpecKey)) {\n installedSpecs.add(newSpecKey)\n spinner?.info(`Installing ${newSpec}${workspaceDetails}`)\n }\n\n try {\n // eslint-disable-next-line no-await-in-loop\n actualTree = await install(pkgEnvDetails, { spinner })\n installed = true\n\n if (test) {\n if (!testedSpecs.has(newSpecKey)) {\n testedSpecs.add(newSpecKey)\n spinner?.info(`Testing ${newSpec}${workspaceDetails}`)\n }\n // eslint-disable-next-line no-await-in-loop\n await runScript(testScript, [], { spinner, stdio: 'ignore' })\n }\n if (!fixedSpecs.has(newSpecKey)) {\n fixedSpecs.add(newSpecKey)\n spinner?.successAndStop(`Fixed ${name}${workspaceDetails}`)\n spinner?.start()\n }\n } catch (e) {\n error = e\n errored = true\n }\n\n debugLog('check \"shouldOpenPr\":', shouldOpenPr)\n debugLog('check \"errored\":', errored)\n if (!errored && shouldOpenPr) {\n debugLog('1: gitCreateAndPushBranchIfNeeded')\n // eslint-disable-next-line no-await-in-loop\n await gitCreateAndPushBranchIfNeeded(\n branch,\n getSocketCommitMessage(oldPurl, newVersion, workspaceName),\n cwd\n )\n debugLog('2: openGitHubPullRequest')\n // eslint-disable-next-line no-await-in-loop\n const prResponse = await openGitHubPullRequest(\n owner,\n repo,\n baseBranch,\n branch,\n oldPurl,\n newVersion,\n {\n cwd,\n workspaceName\n }\n )\n if (prResponse && autoMerge) {\n // eslint-disable-next-line no-await-in-loop\n await enableAutoMerge(prResponse.data)\n }\n }\n\n if (errored || isCi) {\n if (errored) {\n if (!revertedSpecs.has(newSpecKey)) {\n revertedSpecs.add(newSpecKey)\n spinner?.error(`Reverting ${newSpec}${workspaceDetails}`, error)\n }\n }\n editablePkgJson.update(revertData)\n if (isRepo) {\n // eslint-disable-next-line no-await-in-loop\n await gitHardReset(cwd)\n // eslint-disable-next-line no-await-in-loop\n actualTree = await getActualTree(cwd)\n } else if (installed) {\n // eslint-disable-next-line no-await-in-loop\n await editablePkgJson.save()\n // eslint-disable-next-line no-await-in-loop\n actualTree = await install(pkgEnvDetails, { spinner })\n }\n if (errored) {\n if (!failedSpecs.has(newSpecKey)) {\n failedSpecs.add(newSpecKey)\n spinner?.failAndStop(\n `Update failed for ${oldSpec}${workspaceDetails}`\n )\n }\n }\n }\n }\n }\n }\n }\n spinner?.stop()\n}\n","import type { FixOptions, NormalizedFixOptions } from './types'\n\nexport const CMD_NAME = 'socket fix'\n\nexport function assignDefaultFixOptions(\n options: FixOptions\n): NormalizedFixOptions {\n if (options.autoPilot === undefined) {\n options.autoPilot = false\n }\n if (options.autoMerge === undefined) {\n options.autoMerge = !!options.autoPilot\n }\n if (options.cwd === undefined) {\n options.cwd = process.cwd()\n }\n if (options.rangeStyle === undefined) {\n options.rangeStyle = 'preserve'\n }\n if (options.test === undefined) {\n options.test = !!options.autoPilot || !!options.testScript\n }\n if (options.testScript === undefined) {\n options.testScript = 'test'\n }\n return options as NormalizedFixOptions\n}\n","import { existsSync } from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\n\nimport browserslist from 'browserslist'\nimport semver from 'semver'\nimport which from 'which'\n\nimport { parse as parseBunLockb } from '@socketregistry/hyrious__bun.lockb/index.cjs'\nimport { Logger } from '@socketsecurity/registry/lib/logger'\nimport { readPackageJson } from '@socketsecurity/registry/lib/packages'\nimport { naturalCompare } from '@socketsecurity/registry/lib/sorts'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\nimport { isNonEmptyString } from '@socketsecurity/registry/lib/strings'\n\nimport { cmdPrefixMessage } from './cmd'\nimport { findUp, readFileBinary, readFileUtf8 } from './fs'\nimport constants from '../constants'\n\nimport type { Remap } from '@socketsecurity/registry/lib/objects'\nimport type { EditablePackageJson } from '@socketsecurity/registry/lib/packages'\nimport type { SemVer } from 'semver'\n\nconst {\n BINARY_LOCK_EXT,\n BUN,\n HIDDEN_PACKAGE_LOCK_JSON,\n LOCK_EXT,\n NPM,\n NPM_BUGGY_OVERRIDES_PATCHED_VERSION,\n PACKAGE_JSON,\n PNPM,\n VLT,\n YARN,\n YARN_BERRY,\n YARN_CLASSIC\n} = constants\n\nexport const AGENTS = [BUN, NPM, PNPM, YARN_BERRY, YARN_CLASSIC, VLT] as const\n\nexport type Agent = (typeof AGENTS)[number]\n\nconst binByAgent = new Map<Agent, string>([\n [BUN, BUN],\n [NPM, NPM],\n [PNPM, PNPM],\n [YARN_BERRY, YARN],\n [YARN_CLASSIC, YARN],\n [VLT, VLT]\n])\n\nasync function getAgentExecPath(agent: Agent): Promise<string> {\n const binName = binByAgent.get(agent)!\n return (await which(binName, { nothrow: true })) ?? binName\n}\n\nasync function getAgentVersion(\n agentExecPath: string,\n cwd: string\n): Promise<SemVer | undefined> {\n let result\n try {\n result =\n // Coerce version output into a valid semver version by passing it through\n // semver.coerce which strips leading v's, carets (^), comparators (<,<=,>,>=,=),\n // and tildes (~).\n semver.coerce(\n // All package managers support the \"--version\" flag.\n (await spawn(agentExecPath, ['--version'], { cwd })).stdout\n ) ?? undefined\n } catch {}\n return result\n}\n\n// The order of LOCKS properties IS significant as it affects iteration order.\nconst LOCKS: Record<string, Agent> = {\n [`bun${LOCK_EXT}`]: BUN,\n [`bun${BINARY_LOCK_EXT}`]: BUN,\n // If both package-lock.json and npm-shrinkwrap.json are present in the root\n // of a project, npm-shrinkwrap.json will take precedence and package-lock.json\n // will be ignored.\n // https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json#package-lockjson-vs-npm-shrinkwrapjson\n 'npm-shrinkwrap.json': NPM,\n 'package-lock.json': NPM,\n 'pnpm-lock.yaml': PNPM,\n 'pnpm-lock.yml': PNPM,\n [`yarn${LOCK_EXT}`]: YARN_CLASSIC,\n 'vlt-lock.json': VLT,\n // Lastly, look for a hidden lock file which is present if .npmrc has package-lock=false:\n // https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json#hidden-lockfiles\n //\n // Unlike the other LOCKS keys this key contains a directory AND filename so\n // it has to be handled differently.\n 'node_modules/.package-lock.json': NPM\n}\n\ntype ReadLockFile =\n | ((lockPath: string) => Promise<string | undefined>)\n | ((lockPath: string, agentExecPath: string) => Promise<string | undefined>)\n\nconst readLockFileByAgent: Map<Agent, ReadLockFile> = (() => {\n function wrapReader<T extends (...args: any[]) => Promise<any>>(\n reader: T\n ): (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>> | undefined> {\n return async (...args: any[]): Promise<any> => {\n try {\n return await reader(...args)\n } catch {}\n return undefined\n }\n }\n\n const binaryReader = wrapReader(readFileBinary)\n\n const defaultReader = wrapReader(\n async (lockPath: string) => await readFileUtf8(lockPath)\n )\n\n return new Map([\n [\n BUN,\n wrapReader(async (lockPath: string, agentExecPath: string) => {\n const ext = path.extname(lockPath)\n if (ext === LOCK_EXT) {\n return await defaultReader(lockPath)\n }\n if (ext === BINARY_LOCK_EXT) {\n const lockBuffer = await binaryReader(lockPath)\n if (lockBuffer) {\n try {\n return parseBunLockb(lockBuffer)\n } catch {}\n }\n // To print a Yarn lockfile to your console without writing it to disk\n // use `bun bun.lockb`.\n // https://bun.sh/guides/install/yarnlock\n return (await spawn(agentExecPath, [lockPath])).stdout.trim()\n }\n return undefined\n })\n ],\n [NPM, defaultReader],\n [PNPM, defaultReader],\n [VLT, defaultReader],\n [YARN_BERRY, defaultReader],\n [YARN_CLASSIC, defaultReader]\n ])\n})()\n\ntype EnvBase = {\n agent: Agent\n agentExecPath: string\n agentSupported: boolean\n features: {\n // Fixed by https://github.com/npm/cli/pull/8089.\n // Landed in npm v11.2.0.\n npmBuggyOverrides: boolean\n }\n nodeSupported: boolean\n nodeVersion: SemVer\n npmExecPath: string\n pkgRequirements: {\n agent: string\n node: string\n }\n pkgSupports: {\n agent: boolean\n node: boolean\n }\n}\n\nexport type EnvDetails = Readonly<\n Remap<\n EnvBase & {\n agentVersion: SemVer\n editablePkgJson: EditablePackageJson\n lockName: string\n lockPath: string\n lockSrc: string\n pkgPath: string\n }\n >\n>\n\nexport type PartialEnvDetails = Readonly<\n Remap<\n EnvBase & {\n agentVersion: SemVer | undefined\n editablePkgJson: EditablePackageJson | undefined\n lockName: string | undefined\n lockPath: string | undefined\n lockSrc: string | undefined\n pkgPath: string | undefined\n }\n >\n>\n\nexport type DetectOptions = {\n cwd?: string | undefined\n onUnknown?: (pkgManager: string | undefined) => void\n}\n\nexport async function detectPackageEnvironment({\n cwd = process.cwd(),\n onUnknown\n}: DetectOptions = {}): Promise<EnvDetails | PartialEnvDetails> {\n let lockPath = await findUp(Object.keys(LOCKS), { cwd })\n let lockName = lockPath ? path.basename(lockPath) : undefined\n const isHiddenLockFile = lockName === HIDDEN_PACKAGE_LOCK_JSON\n const pkgJsonPath = lockPath\n ? path.resolve(\n lockPath,\n `${isHiddenLockFile ? '../' : ''}../${PACKAGE_JSON}`\n )\n : await findUp(PACKAGE_JSON, { cwd })\n const pkgPath =\n pkgJsonPath && existsSync(pkgJsonPath)\n ? path.dirname(pkgJsonPath)\n : undefined\n const editablePkgJson = pkgPath\n ? await readPackageJson(pkgPath, { editable: true })\n : undefined\n // Read Corepack `packageManager` field in package.json:\n // https://nodejs.org/api/packages.html#packagemanager\n const pkgManager = isNonEmptyString(editablePkgJson?.content?.packageManager)\n ? editablePkgJson.content.packageManager\n : undefined\n\n let agent: Agent | undefined\n let agentVersion: SemVer | undefined\n if (pkgManager) {\n // A valid \"packageManager\" field value is \"<package manager name>@<version>\".\n // https://nodejs.org/api/packages.html#packagemanager\n const atSignIndex = pkgManager.lastIndexOf('@')\n if (atSignIndex !== -1) {\n const name = pkgManager.slice(0, atSignIndex) as Agent\n const version = pkgManager.slice(atSignIndex + 1)\n if (version && AGENTS.includes(name)) {\n agent = name\n }\n }\n }\n if (\n agent === undefined &&\n !isHiddenLockFile &&\n typeof pkgJsonPath === 'string' &&\n typeof lockName === 'string'\n ) {\n agent = LOCKS[lockName] as Agent\n }\n if (agent === undefined) {\n agent = NPM\n onUnknown?.(pkgManager)\n }\n const agentExecPath = await getAgentExecPath(agent)\n const npmExecPath =\n agent === NPM ? agentExecPath : await getAgentExecPath(NPM)\n if (agentVersion === undefined) {\n agentVersion = await getAgentVersion(agentExecPath, cwd)\n }\n if (agent === YARN_CLASSIC && (agentVersion?.major ?? 0) > 1) {\n agent = YARN_BERRY\n }\n // Lazily access constants.maintainedNodeVersions.\n const { maintainedNodeVersions } = constants\n // Lazily access constants.minimumVersionByAgent.\n const minSupportedAgentVersion = constants.minimumVersionByAgent.get(agent)!\n const minSupportedNodeVersion = maintainedNodeVersions.last\n const nodeVersion = semver.coerce(process.version)!\n let lockSrc: string | undefined\n let pkgAgentRange: string | undefined\n let pkgNodeRange: string | undefined\n let pkgMinAgentVersion = minSupportedAgentVersion\n let pkgMinNodeVersion = minSupportedNodeVersion\n if (editablePkgJson?.content) {\n const { engines } = editablePkgJson.content\n const engineAgentRange = engines?.[agent]\n const engineNodeRange = engines?.['node']\n if (isNonEmptyString(engineAgentRange)) {\n pkgAgentRange = engineAgentRange\n // Roughly check agent range as semver.coerce will strip leading\n // v's, carets (^), comparators (<,<=,>,>=,=), and tildes (~).\n const coerced = semver.coerce(pkgAgentRange)\n if (coerced && semver.lt(coerced, pkgMinAgentVersion)) {\n pkgMinAgentVersion = coerced.version\n }\n }\n if (isNonEmptyString(engineNodeRange)) {\n pkgNodeRange = engineNodeRange\n // Roughly check Node range as semver.coerce will strip leading\n // v's, carets (^), comparators (<,<=,>,>=,=), and tildes (~).\n const coerced = semver.coerce(pkgNodeRange)\n if (coerced && semver.lt(coerced, pkgMinNodeVersion)) {\n pkgMinNodeVersion = coerced.version\n }\n }\n const browserslistQuery = editablePkgJson.content['browserslist'] as\n | string[]\n | undefined\n if (Array.isArray(browserslistQuery)) {\n // List Node targets in ascending version order.\n const browserslistNodeTargets = browserslist(browserslistQuery)\n .filter(v => /^node /i.test(v))\n .map(v => v.slice(5 /*'node '.length*/))\n .sort(naturalCompare)\n if (browserslistNodeTargets.length) {\n // browserslistNodeTargets[0] is the lowest Node target version.\n const coerced = semver.coerce(browserslistNodeTargets[0])\n if (coerced && semver.lt(coerced, pkgMinNodeVersion)) {\n pkgMinNodeVersion = coerced.version\n }\n }\n }\n lockSrc =\n typeof lockPath === 'string'\n ? await readLockFileByAgent.get(agent)!(lockPath, agentExecPath)\n : undefined\n } else {\n lockName = undefined\n lockPath = undefined\n }\n // Does the system agent version meet our minimum supported agent version?\n const agentSupported =\n !!agentVersion &&\n semver.satisfies(agentVersion, `>=${minSupportedAgentVersion}`)\n\n // Does the system Node version meet our minimum supported Node version?\n const nodeSupported = semver.satisfies(\n nodeVersion,\n `>=${minSupportedNodeVersion}`\n )\n\n const npmBuggyOverrides =\n agent === NPM &&\n !!agentVersion &&\n semver.lt(agentVersion, NPM_BUGGY_OVERRIDES_PATCHED_VERSION)\n\n return {\n agent,\n agentExecPath,\n agentSupported,\n agentVersion,\n editablePkgJson,\n features: { npmBuggyOverrides },\n lockName,\n lockPath,\n lockSrc,\n nodeSupported,\n nodeVersion,\n npmExecPath,\n pkgPath,\n pkgRequirements: {\n agent: pkgAgentRange ?? `>=${pkgMinAgentVersion}`,\n node: pkgNodeRange ?? `>=${pkgMinNodeVersion}`\n },\n pkgSupports: {\n // Does our minimum supported agent version meet the package's requirements?\n agent: semver.satisfies(\n minSupportedAgentVersion,\n `>=${pkgMinAgentVersion}`\n ),\n // Does our supported Node versions meet the package's requirements?\n node: maintainedNodeVersions.some(v =>\n semver.satisfies(v, `>=${pkgMinNodeVersion}`)\n )\n }\n }\n}\n\nexport type DetectAndValidateOptions = {\n cmdName?: string | undefined\n logger?: Logger | undefined\n prod?: boolean | undefined\n}\n\nexport async function detectAndValidatePackageEnvironment(\n cwd: string,\n options?: DetectAndValidateOptions | undefined\n): Promise<void | EnvDetails> {\n const {\n cmdName = '',\n logger,\n prod\n } = {\n __proto__: null,\n ...options\n } as DetectAndValidateOptions\n const details = await detectPackageEnvironment({\n cwd,\n onUnknown(pkgManager: string | undefined) {\n logger?.warn(\n cmdPrefixMessage(\n cmdName,\n `Unknown package manager${pkgManager ? ` ${pkgManager}` : ''}, defaulting to npm`\n )\n )\n }\n })\n const { agent, nodeVersion, pkgRequirements } = details\n const agentVersion = details.agentVersion ?? 'unknown'\n if (!details.agentSupported) {\n const minVersion = constants.minimumVersionByAgent.get(agent)!\n logger?.fail(\n cmdPrefixMessage(\n cmdName,\n `Requires ${agent} >=${minVersion}. Current version: ${agentVersion}.`\n )\n )\n return\n }\n if (!details.nodeSupported) {\n const minVersion = constants.maintainedNodeVersions.last\n logger?.fail(\n cmdPrefixMessage(\n cmdName,\n `Requires Node >=${minVersion}. Current version: ${nodeVersion}.`\n )\n )\n return\n }\n if (!details.pkgSupports.agent) {\n logger?.fail(\n cmdPrefixMessage(\n cmdName,\n `Package engine \"${agent}\" requires ${pkgRequirements.agent}. Current version: ${agentVersion}`\n )\n )\n return\n }\n if (!details.pkgSupports.node) {\n logger?.fail(\n cmdPrefixMessage(\n cmdName,\n `Package engine \"node\" requires ${pkgRequirements.node}. Current version: ${nodeVersion}`\n )\n )\n return\n }\n if (agent === VLT) {\n logger?.fail(\n cmdPrefixMessage(\n cmdName,\n `${agent} does not support overrides. Soon, though ⚡`\n )\n )\n return\n }\n const lockName = details.lockName ?? 'lock file'\n if (details.lockName === undefined || details.lockSrc === undefined) {\n logger?.fail(cmdPrefixMessage(cmdName, `No ${lockName} found`))\n return\n }\n if (details.lockSrc.trim() === '') {\n logger?.fail(cmdPrefixMessage(cmdName, `${lockName} is empty`))\n return\n }\n if (details.pkgPath === undefined) {\n logger?.fail(cmdPrefixMessage(cmdName, `No ${PACKAGE_JSON} found`))\n return\n }\n if (prod && (agent === BUN || agent === YARN_BERRY)) {\n logger?.fail(\n cmdPrefixMessage(\n cmdName,\n `--prod not supported for ${agent}${agentVersion ? `@${agentVersion}` : ''}`\n )\n )\n return\n }\n if (\n details.lockPath &&\n path.relative(cwd, details.lockPath).startsWith('.')\n ) {\n logger?.warn(\n cmdPrefixMessage(\n cmdName,\n `Package ${lockName} found at ${details.lockPath}`\n )\n )\n }\n return details as EnvDetails\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { npmFix } from './npm-fix'\nimport { pnpmFix } from './pnpm-fix'\nimport { CMD_NAME, assignDefaultFixOptions } from './shared'\nimport constants from '../../constants'\nimport { detectAndValidatePackageEnvironment } from '../../utils/package-environment'\n\nimport type { FixOptions } from './types'\n\nconst { NPM, PNPM } = constants\n\nexport async function runFix(options_: FixOptions) {\n const options = assignDefaultFixOptions({\n __proto__: null,\n ...options_\n } as FixOptions)\n const pkgEnvDetails = await detectAndValidatePackageEnvironment(options.cwd, {\n cmdName: CMD_NAME,\n logger\n })\n if (!pkgEnvDetails) {\n return\n }\n logger.info(`Fixing packages for ${pkgEnvDetails.agent}`)\n const { agent } = pkgEnvDetails\n if (agent === NPM) {\n await npmFix(pkgEnvDetails, options)\n } else if (agent === PNPM) {\n await pnpmFix(pkgEnvDetails, options)\n }\n}\n","import { codeBlock } from 'common-tags'\nimport terminalLink from 'terminal-link'\n\nimport { joinOr } from '@socketsecurity/registry/lib/arrays'\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { runFix } from './run-fix'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { RangeStyles } from '../../utils/semver'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\nimport type { RangeStyle } from '../../utils/semver'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'fix',\n description: 'Fix \"fixable\" Socket alerts',\n hidden: true,\n flags: {\n ...commonFlags,\n autoPilot: {\n type: 'boolean',\n default: false,\n description: `Shorthand for --autoMerge --test`\n },\n autoMerge: {\n type: 'boolean',\n default: false,\n description: `Enable auto-merge for pull requests that Socket opens.\\n See ${terminalLink(\n 'GitHub documentation',\n 'https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-auto-merge-for-pull-requests-in-your-repository'\n )} for managing auto-merge for pull requests in your repository.`\n },\n purl: {\n type: 'string',\n default: [],\n description: `User provided PURL to fix`,\n isMultiple: true,\n shortFlag: 'p'\n },\n rangeStyle: {\n type: 'string',\n default: 'preserve',\n description: codeBlock`\n Define how updated dependency versions should be written in package.json.\n Available styles:\n *\tcaret - Use ^ range for compatible updates (e.g. ^1.2.3)\n *\tgt - Use >= to allow any newer version (e.g. >=1.2.3)\n *\tlt - Use < to allow only lower versions (e.g. <1.2.3)\n *\tpin - Use the exact version (e.g. 1.2.3)\n *\tpreserve - Retain the existing version range as-is\n *\ttilde - Use ~ range for patch/minor updates (e.g. ~1.2.3)\n `\n },\n test: {\n type: 'boolean',\n default: false,\n description: 'Verify the fix by running unit tests'\n },\n testScript: {\n type: 'string',\n default: 'test',\n description: 'The test script to run for each fix attempt'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command}\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n `\n}\n\nexport const cmdFix = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const wasBadInput = handleBadInput({\n test: RangeStyles.includes(cli.flags['rangeStyle'] as string),\n message: `Expecting range style of ${joinOr(RangeStyles)}`,\n pass: 'ok',\n fail: 'missing'\n })\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n await runFix({\n autoMerge: Boolean(cli.flags['autoMerge']),\n autoPilot: Boolean(cli.flags['autoPilot']),\n purls: Array.isArray(cli.flags['purl']) ? cli.flags['purl'] : [],\n spinner,\n rangeStyle: (cli.flags['rangeStyle'] ?? undefined) as\n | RangeStyle\n | undefined,\n test: Boolean(cli.flags['test']),\n testScript: cli.flags['testScript'] as string | undefined\n })\n}\n","import constants from '../../constants'\nimport { getSeverityCount } from '../../utils/alert/severity'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { getPublicToken, setupSdk } from '../../utils/sdk'\n\nimport type { PackageData } from './handle-package-info'\n\nexport async function fetchPackageInfo(\n pkgName: string,\n pkgVersion: string,\n includeAllIssues: boolean\n): Promise<void | PackageData> {\n const sockSdk = await setupSdk(getPublicToken())\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start(\n pkgVersion === 'latest'\n ? `Looking up data for the latest version of ${pkgName}`\n : `Looking up data for version ${pkgVersion} of ${pkgName}`\n )\n\n const result = await handleApiCall(\n sockSdk.getIssuesByNPMPackage(pkgName, pkgVersion),\n 'looking up package'\n )\n const scoreResult = await handleApiCall(\n sockSdk.getScoreByNPMPackage(pkgName, pkgVersion),\n 'looking up package score'\n )\n\n spinner.successAndStop('Data fetched')\n\n if (result.success === false) {\n handleUnsuccessfulApiResponse('getIssuesByNPMPackage', result)\n }\n\n if (scoreResult.success === false) {\n handleUnsuccessfulApiResponse('getScoreByNPMPackage', scoreResult)\n }\n\n const severityCount = getSeverityCount(\n result.data,\n includeAllIssues ? undefined : 'high'\n )\n\n return {\n data: result.data,\n severityCount,\n score: scoreResult.data\n }\n}\n","import { codeBlock } from 'common-tags'\nimport colors from 'yoctocolors-cjs'\n\nimport constants from '@socketsecurity/registry/lib/constants'\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { hasKeys } from '@socketsecurity/registry/lib/objects'\n\nimport { ALERT_SEVERITY, formatSeverityCount } from '../../utils/alert/severity'\nimport { ColorOrMarkdown } from '../../utils/color-or-markdown'\nimport {\n getSocketDevAlertUrl,\n getSocketDevPackageOverviewUrl\n} from '../../utils/socket-url'\n\nimport type { PackageData } from './handle-package-info'\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nconst { NPM } = constants\n\nfunction formatScore(score: number): string {\n if (score > 80) {\n return colors.green(`${score}`)\n } else if (score < 80 && score > 60) {\n return colors.yellow(`${score}`)\n }\n return colors.red(`${score}`)\n}\n\nfunction outputPackageIssuesDetails(\n packageData: SocketSdkReturnType<'getIssuesByNPMPackage'>['data'],\n outputMarkdown: boolean\n) {\n const issueDetails = packageData.filter(\n d =>\n d.value?.severity === ALERT_SEVERITY.critical ||\n d.value?.severity === ALERT_SEVERITY.high\n )\n const uniqueIssueDetails = issueDetails.reduce((acc, issue) => {\n const { type } = issue\n if (type) {\n const details = acc.get(type)\n if (details) {\n details.count += 1\n } else {\n acc.set(type, {\n label: issue.value?.label ?? '',\n count: 1\n })\n }\n }\n return acc\n }, new Map<string, { count: number; label: string }>())\n const format = new ColorOrMarkdown(outputMarkdown)\n for (const [type, details] of uniqueIssueDetails.entries()) {\n const issueWithLink = format.hyperlink(\n details.label,\n getSocketDevAlertUrl(type),\n { fallbackToUrl: true }\n )\n if (details.count === 1) {\n logger.log(`- ${issueWithLink}`)\n } else {\n logger.log(`- ${issueWithLink}: ${details.count}`)\n }\n }\n}\n\nexport function outputPackageInfo(\n { data, score, severityCount }: PackageData,\n {\n commandName,\n outputKind,\n pkgName,\n pkgVersion\n }: {\n commandName: string\n outputKind: 'json' | 'markdown' | 'print'\n pkgName: string\n pkgVersion: string\n includeAllIssues?: boolean | undefined\n }\n): void {\n if (outputKind === 'json') {\n logger.log(JSON.stringify(data, undefined, 2))\n return\n }\n if (outputKind === 'markdown') {\n logger.log(codeBlock`\n # Package report for ${pkgName}\n\n Package report card:\n `)\n } else {\n logger.log(`Package report card for ${pkgName}:`)\n }\n const scoreResult = {\n 'Supply Chain Risk': Math.floor(score.supplyChainRisk.score * 100),\n Maintenance: Math.floor(score.maintenance.score * 100),\n Quality: Math.floor(score.quality.score * 100),\n Vulnerabilities: Math.floor(score.vulnerability.score * 100),\n License: Math.floor(score.license.score * 100)\n }\n logger.log('\\n')\n Object.entries(scoreResult).map(score =>\n logger.log(`- ${score[0]}: ${formatScore(score[1])}`)\n )\n logger.log('\\n')\n if (hasKeys(severityCount)) {\n if (outputKind === 'markdown') {\n logger.log('# Issues\\n')\n }\n logger.log(\n `Package has these issues: ${formatSeverityCount(severityCount)}\\n`\n )\n outputPackageIssuesDetails(data, outputKind === 'markdown')\n } else {\n logger.log('Package has no issues')\n }\n\n const format = new ColorOrMarkdown(outputKind === 'markdown')\n const url = getSocketDevPackageOverviewUrl(NPM, pkgName, pkgVersion)\n\n logger.log('\\n')\n if (pkgVersion === 'latest') {\n logger.log(\n `Detailed info on socket.dev: ${format.hyperlink(`${pkgName}`, url, { fallbackToUrl: true })}`\n )\n } else {\n logger.log(\n `Detailed info on socket.dev: ${format.hyperlink(`${pkgName} v${pkgVersion}`, url, { fallbackToUrl: true })}`\n )\n }\n if (outputKind !== 'markdown') {\n logger.log(\n colors.dim(\n `\\nOr rerun ${colors.italic(commandName)} using the ${colors.italic('--json')} flag to get full JSON output`\n )\n )\n } else {\n logger.log('')\n }\n}\n","import process from 'node:process'\n\nimport { hasKeys } from '@socketsecurity/registry/lib/objects'\n\nimport { fetchPackageInfo } from './fetch-package-info'\nimport { outputPackageInfo } from './output-package-info'\n\nimport type { SocketSdkAlert } from '../../utils/alert/severity'\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport interface PackageData {\n data: SocketSdkReturnType<'getIssuesByNPMPackage'>['data']\n severityCount: Record<SocketSdkAlert['severity'], number>\n score: SocketSdkReturnType<'getScoreByNPMPackage'>['data']\n}\n\nexport async function handlePackageInfo({\n commandName,\n includeAllIssues,\n outputKind,\n pkgName,\n pkgVersion,\n strict\n}: {\n commandName: string\n includeAllIssues: boolean\n outputKind: 'json' | 'markdown' | 'print'\n pkgName: string\n pkgVersion: string\n strict: boolean\n}) {\n const packageData = await fetchPackageInfo(\n pkgName,\n pkgVersion,\n includeAllIssues\n )\n\n if (packageData) {\n outputPackageInfo(packageData, {\n commandName,\n includeAllIssues,\n outputKind,\n pkgName,\n pkgVersion\n })\n\n if (strict && hasKeys(packageData.severityCount)) {\n // Let NodeJS exit gracefully but with exit(1)\n process.exitCode = 1\n }\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handlePackageInfo } from './handle-package-info'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags, validationFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'info',\n description: 'Look up info regarding a package',\n hidden: true, // Deprecated\n flags: {\n ...commonFlags,\n ...outputFlags,\n ...validationFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <name>\n\n Note: this command will be deprecated in favor of \\`socket package score\\` soon\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} webtorrent\n $ ${command} webtorrent@1.9.1\n `\n}\n\nexport const cmdInfo = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { all, json, markdown, strict } = cli.flags\n const [rawPkgName = ''] = cli.input\n\n const wasBadInput = handleBadInput(\n {\n test: !!rawPkgName,\n message: 'Expecting a package name',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: cli.input.length === 1,\n message: 'Can only accept one package at a time',\n pass: 'ok',\n fail: 'got ' + cli.input.length\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n }\n )\n if (wasBadInput) {\n return\n }\n\n const versionSeparator = rawPkgName.lastIndexOf('@')\n const pkgName =\n versionSeparator < 1 ? rawPkgName : rawPkgName.slice(0, versionSeparator)\n const pkgVersion =\n versionSeparator < 1 ? 'latest' : rawPkgName.slice(versionSeparator + 1)\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handlePackageInfo({\n commandName: `${parentName} ${config.commandName}`,\n includeAllIssues: Boolean(all),\n outputKind: json ? 'json' : markdown ? 'markdown' : 'print',\n pkgName,\n pkgVersion,\n strict: Boolean(strict)\n })\n}\n","import { updateConfigValue } from '../../utils/config'\n\nexport function applyLogin(\n apiToken: string,\n enforcedOrgs: string[],\n apiBaseUrl: string | undefined,\n apiProxy: string | undefined\n) {\n updateConfigValue('enforcedOrgs', enforcedOrgs)\n updateConfigValue('apiToken', apiToken)\n updateConfigValue('apiBaseUrl', apiBaseUrl)\n updateConfigValue('apiProxy', apiProxy)\n}\n","import terminalLink from 'terminal-link'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { confirm, password, select } from '@socketsecurity/registry/lib/prompts'\n\nimport { applyLogin } from './apply-login'\nimport constants from '../../constants'\nimport { handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { getConfigValue, isReadOnlyConfig } from '../../utils/config'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { Choice, Separator } from '@socketsecurity/registry/lib/prompts'\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\ntype OrgChoice = Choice<string>\ntype OrgChoices = Array<Separator | OrgChoice>\nconst { SOCKET_PUBLIC_API_TOKEN } = constants\n\nexport async function attemptLogin(\n apiBaseUrl: string | undefined,\n apiProxy: string | undefined\n) {\n apiBaseUrl ??= getConfigValue('apiBaseUrl') ?? undefined\n apiProxy ??= getConfigValue('apiProxy') ?? undefined\n const apiToken =\n (await password({\n message: `Enter your ${terminalLink(\n 'Socket.dev API key',\n 'https://docs.socket.dev/docs/api-keys'\n )} (leave blank for a public key)`\n })) || SOCKET_PUBLIC_API_TOKEN\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n const sdk = await setupSdk(apiToken, apiBaseUrl, apiProxy)\n\n spinner.start('Verifying API key...')\n\n const result = await sdk.getOrganizations()\n\n spinner.successAndStop('Received response')\n\n if (!result.success) {\n logger.fail('Authentication failed...')\n handleUnsuccessfulApiResponse('getOrganizations', result)\n }\n\n logger.success('API key verified')\n\n const orgs: SocketSdkReturnType<'getOrganizations'>['data'] = result.data\n\n const enforcedChoices: OrgChoices = Object.values(orgs.organizations)\n .filter(org => org?.plan === 'enterprise')\n .map(org => ({\n name: org.name ?? 'undefined',\n value: org.id\n }))\n\n let enforcedOrgs: string[] = []\n if (enforcedChoices.length > 1) {\n const id = (await select({\n message:\n \"Which organization's policies should Socket enforce system-wide?\",\n choices: enforcedChoices.concat({\n name: 'None',\n value: '',\n description: 'Pick \"None\" if this is a personal device'\n })\n })) as string | null\n if (id) {\n enforcedOrgs = [id]\n }\n } else if (enforcedChoices.length) {\n if (\n await confirm({\n message: `Should Socket enforce ${(enforcedChoices[0] as OrgChoice)?.name}'s security policies system-wide?`,\n default: true\n })\n ) {\n const existing = enforcedChoices[0] as OrgChoice\n if (existing) {\n enforcedOrgs = [existing.value]\n }\n }\n }\n\n spinner.stop()\n\n const previousPersistedToken = getConfigValue('apiToken')\n try {\n applyLogin(apiToken, enforcedOrgs, apiBaseUrl, apiProxy)\n logger.success(\n `API credentials ${previousPersistedToken === apiToken ? 'refreshed' : previousPersistedToken ? 'updated' : 'set'}`\n )\n if (isReadOnlyConfig()) {\n logger.log('')\n logger.warn(\n 'Note: config is in read-only mode, at least one key was overridden through flag/env, so the login was not persisted!'\n )\n }\n } catch {\n logger.fail(`API login failed`)\n }\n}\n","import isInteractive from '@socketregistry/is-interactive/index.cjs'\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { attemptLogin } from './attempt-login'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { InputError } from '../../utils/errors'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'login',\n description: 'Socket API login',\n hidden: false,\n flags: {\n ...commonFlags,\n apiBaseUrl: {\n type: 'string',\n description: 'API server to connect to for login'\n },\n apiProxy: {\n type: 'string',\n description: 'Proxy to use when making connection to API server'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command}\n\n API Token Requirements\n - Quota: 1 unit\n\n Logs into the Socket API by prompting for an API key\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command}\n $ ${command} --api-proxy=http://localhost:1234\n `\n}\n\nexport const cmdLogin = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const apiBaseUrl = cli.flags['apiBaseUrl'] as string | undefined\n const apiProxy = cli.flags['apiProxy'] as string | undefined\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n if (!isInteractive()) {\n throw new InputError(\n 'Cannot prompt for credentials in a non-interactive shell'\n )\n }\n\n await attemptLogin(apiBaseUrl, apiProxy)\n}\n","import { updateConfigValue } from '../../utils/config'\n\nexport function applyLogout() {\n updateConfigValue('apiToken', null)\n updateConfigValue('apiBaseUrl', null)\n updateConfigValue('apiProxy', null)\n updateConfigValue('enforcedOrgs', null)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { applyLogout } from './apply-logout'\nimport { isReadOnlyConfig } from '../../utils/config'\n\nexport function attemptLogout() {\n try {\n applyLogout()\n logger.success('Successfully logged out')\n if (isReadOnlyConfig()) {\n logger.log('')\n logger.warn(\n 'Note: config is in read-only mode, at least one key was overridden through flag/env, so the logout was not persisted!'\n )\n }\n } catch {\n logger.fail('Failed to complete logout steps')\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { attemptLogout } from './attempt-logout'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'logout',\n description: 'Socket API logout',\n hidden: false,\n flags: {\n ...commonFlags\n },\n help: (command, _config) => `\n Usage\n $ ${command}\n\n Logs out of the Socket API and clears all Socket credentials from disk\n `\n}\n\nexport const cmdLogout = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n attemptLogout()\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nexport async function convertCondaToRequirements(\n target: string,\n cwd: string,\n verbose: boolean\n): Promise<\n | { ok: true; message: string; data: { contents: string; pip: string } }\n | { ok: false; message: string; data: undefined }\n> {\n let contents: string\n if (target === '-') {\n if (verbose) {\n logger.error(`[VERBOSE] reading input from stdin`)\n }\n\n const buf: string[] = []\n contents = await new Promise((resolve, reject) => {\n process.stdin.on('data', chunk => {\n const input = chunk.toString()\n buf.push(input)\n })\n process.stdin.on('end', () => {\n resolve(buf.join(''))\n })\n process.stdin.on('error', e => {\n if (verbose) {\n logger.error('Unexpected error while reading from stdin:', e)\n }\n reject(e)\n })\n process.stdin.on('close', () => {\n if (buf.length === 0) {\n if (verbose) {\n logger.error('stdin closed explicitly without data received')\n }\n reject(new Error('No data received from stdin'))\n } else {\n if (verbose) {\n logger.error(\n 'warning: stdin closed explicitly with some data received'\n )\n }\n resolve(buf.join(''))\n }\n })\n })\n\n if (!contents) {\n return {\n ok: false,\n message: 'No data received from stdin',\n data: undefined\n }\n }\n } else {\n const f = path.resolve(cwd, target)\n\n if (verbose) {\n logger.error(`[VERBOSE] target file: ${f}`)\n }\n\n if (!fs.existsSync(f)) {\n return {\n ok: false,\n message: `Input file not found at ${f}`,\n data: undefined\n }\n }\n\n contents = fs.readFileSync(target, 'utf8')\n\n if (!contents) {\n return { ok: false, message: 'File is empty', data: undefined }\n }\n }\n\n return {\n ok: true,\n message: '',\n data: {\n contents,\n pip: convertCondaToRequirementsFromInput(contents)\n }\n }\n}\n\n// Just extract the first pip block, if one exists at all.\nexport function convertCondaToRequirementsFromInput(input: string): string {\n const keeping: string[] = []\n let collecting = false\n let delim = '-'\n let indent = ''\n input.split('\\n').some(line => {\n if (!line) {\n // Ignore empty lines\n return\n }\n if (collecting) {\n if (line.startsWith('#')) {\n // Ignore comment lines (keep?)\n return\n }\n if (line.startsWith(delim)) {\n // In this case we have a line with the same indentation as the\n // `- pip:` line, so we have reached the end of the pip block.\n return true // the end\n } else {\n if (!indent) {\n // Store the indentation of the block\n if (line.trim().startsWith('-')) {\n indent = line.split('-')[0] + '-'\n if (indent.length <= delim.length) {\n // The first line after the `pip:` line does not indent further\n // than that so the block is empty?\n return true\n }\n }\n }\n if (line.startsWith(indent)) {\n keeping.push(line.slice(indent.length).trim())\n } else {\n // Unexpected input. bail.\n return true\n }\n }\n } else {\n // Note: the line may end with a line comment so don't === it.\n if (line.trim().startsWith('- pip:')) {\n delim = line.split('-')[0] + '-'\n collecting = true\n }\n }\n })\n\n return keeping.join('\\n')\n}\n","import fs from 'node:fs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nexport async function outputRequirements(\n data: { contents: string; pip: string },\n outputKind: 'json' | 'markdown' | 'text',\n out: string\n) {\n if (outputKind === 'json') {\n const json = JSON.stringify(\n {\n ok: true,\n data: {\n pip: data.pip\n }\n },\n undefined,\n 2\n )\n\n if (out === '-') {\n logger.log(json)\n } else {\n fs.writeFileSync(out, json, 'utf8')\n }\n\n return\n }\n\n if (outputKind === 'markdown') {\n const arr = []\n arr.push('# Converted Conda file')\n arr.push('')\n arr.push(\n 'This is the Conda `environment.yml` file converted to python `requirements.txt`:'\n )\n arr.push('')\n arr.push('```file=requirements.txt')\n arr.push(data.pip)\n arr.push('```')\n arr.push('')\n const md = arr.join('\\n')\n\n if (out === '-') {\n logger.log(md)\n } else {\n fs.writeFileSync(out, md, 'utf8')\n }\n return\n }\n\n if (out === '-') {\n logger.log(data.pip)\n logger.log('')\n } else {\n fs.writeFileSync(out, data.pip, 'utf8')\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { convertCondaToRequirements } from './convert-conda-to-requirements'\nimport { outputRequirements } from './output-requirements'\n\nexport async function handleManifestConda(\n target: string,\n out: string,\n outputKind: 'json' | 'markdown' | 'text',\n cwd: string,\n verbose: boolean\n): Promise<void> {\n const data = await convertCondaToRequirements(target, cwd, verbose)\n if (!data) {\n return\n }\n if (!data.ok) {\n logger.fail(data.message)\n return\n }\n\n await outputRequirements(data.data, outputKind, out)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleManifestConda } from './handle-manifest-conda'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'conda',\n description:\n '[beta] Convert a Conda environment.yml file to a python requirements.txt',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n cwd: {\n type: 'string',\n description: 'Set the cwd, defaults to process.cwd()'\n },\n out: {\n type: 'string',\n default: '-',\n description: 'Output target (use `-` or omit to print to stdout)'\n },\n verbose: {\n type: 'boolean',\n description: 'Print debug messages'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} FILE\n\n Note: FILE can be a dash (-) to indicate stdin. This way you can pipe the\n contents of a file to have it processed.\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n\n $ ${command} ./environment.yml\n `\n}\n\nexport const cmdManifestConda = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const {\n cwd = process.cwd(),\n json = false,\n markdown = false,\n out = '-',\n verbose = false\n } = cli.flags\n const [target = ''] = cli.input\n\n if (verbose) {\n logger.group('- ', parentName, config.commandName, ':')\n logger.group('- flags:', cli.flags)\n logger.groupEnd()\n logger.log('- target:', target)\n logger.log('- output:', out)\n logger.groupEnd()\n }\n\n const wasBadInput = handleBadInput(\n {\n test: !!target,\n message: 'The FILE arg is required',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: cli.input.length <= 1,\n message: 'Can only accept one DIR (make sure to escape spaces!)',\n pass: 'ok',\n fail: 'received ' + cli.input.length\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleManifestConda(\n target,\n String(out || ''),\n json ? 'json' : markdown ? 'markdown' : 'text',\n String(cwd),\n Boolean(verbose)\n )\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\n\nimport colors from 'yoctocolors-cjs'\n\nimport { isDebug } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport constants from '../../constants'\n\nexport async function convertGradleToMaven(\n target: string,\n bin: string,\n cwd: string,\n verbose: boolean,\n gradleOpts: string[]\n) {\n if (verbose) {\n logger.log('[VERBOSE] Resolving:', [cwd, bin])\n }\n const rbin = path.resolve(cwd, bin)\n if (verbose) {\n logger.log('[VERBOSE] Resolving:', [cwd, target])\n }\n const rtarget = path.resolve(cwd, target)\n\n const binExists = fs.existsSync(rbin)\n\n const targetExists = fs.existsSync(rtarget)\n\n logger.group('gradle2maven:')\n if (verbose || isDebug()) {\n logger.log(\n `[VERBOSE] - Absolute bin path: \\`${rbin}\\` (${binExists ? 'found' : colors.red('not found!')})`\n )\n logger.log(\n `[VERBOSE] - Absolute target path: \\`${rtarget}\\` (${targetExists ? 'found' : colors.red('not found!')})`\n )\n } else {\n logger.log(`- executing: \\`${rbin}\\``)\n if (!binExists) {\n logger.warn(\n 'Warning: It appears the executable could not be found at this location. An error might be printed later because of that.'\n )\n }\n logger.log(`- src dir: \\`${rtarget}\\``)\n if (!targetExists) {\n logger.warn(\n 'Warning: It appears the src dir could not be found at this location. An error might be printed later because of that.'\n )\n }\n }\n logger.groupEnd()\n\n try {\n // Run gradlew with the init script we provide which should yield zero or more\n // pom files. We have to figure out where to store those pom files such that\n // we can upload them and predict them through the GitHub API. We could do a\n // .socket folder. We could do a socket.pom.gz with all the poms, although\n // I'd prefer something plain-text if it is to be committed.\n\n // Note: init.gradle will be exported by .config/rollup.dist.config.mjs\n const initLocation = path.join(constants.rootDistPath, 'init.gradle')\n const commandArgs = ['--init-script', initLocation, ...gradleOpts, 'pom']\n\n if (verbose) {\n logger.log('[VERBOSE] Executing:', [bin], ', args:', commandArgs)\n }\n\n logger.log(\n `Converting gradle to maven from \\`${bin}\\` on \\`${target}\\` ...`\n )\n const output = await execGradleWithSpinner(rbin, commandArgs, rtarget, cwd)\n\n if (verbose) {\n logger.group('[VERBOSE] gradle stdout:')\n logger.log(output)\n logger.groupEnd()\n }\n if (output.code !== 0) {\n process.exitCode = 1\n logger.fail(`Gradle exited with exit code ${output.code}`)\n // (In verbose mode, stderr was printed above, no need to repeat it)\n if (!verbose) {\n logger.group('stderr:')\n logger.error(output.stderr)\n logger.groupEnd()\n }\n return\n }\n logger.success('Executed gradle successfully')\n logger.log('Reported exports:')\n output.stdout.replace(\n /^POM file copied to: (.*)/gm,\n (_all: string, fn: string) => {\n logger.log('- ', fn)\n return fn\n }\n )\n logger.log('')\n logger.log(\n 'Next step is to generate a Scan by running the `socket scan create` command on the same directory'\n )\n } catch (e) {\n process.exitCode = 1\n logger.fail(\n 'There was an unexpected error while generating manifests' +\n (verbose ? '' : ' (use --verbose for details)')\n )\n if (verbose) {\n logger.group('[VERBOSE] error:')\n logger.log(e)\n logger.groupEnd()\n }\n }\n}\n\nasync function execGradleWithSpinner(\n bin: string,\n commandArgs: string[],\n target: string,\n cwd: string\n): Promise<{ code: number; stdout: string; stderr: string }> {\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n let pass = false\n try {\n spinner.start(\n `Running gradlew... (this can take a while, it depends on how long gradlew has to run)`\n )\n const output = await spawn(bin, commandArgs, {\n // We can pipe the output through to have the user see the result\n // of running gradlew, but then we can't (easily) gather the output\n // to discover the generated files... probably a flag we should allow?\n // stdio: isDebug() ? 'inherit' : undefined,\n cwd: target || cwd\n })\n pass = true\n const { code, stderr, stdout } = output\n return { code, stdout, stderr }\n } finally {\n if (pass) {\n spinner.successAndStop('Completed gradlew execution')\n } else {\n spinner.failAndStop('There was an error while trying to run gradlew.')\n }\n }\n}\n","import path from 'node:path'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { convertGradleToMaven } from './convert_gradle_to_maven'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'gradle',\n description:\n '[beta] Use Gradle to generate a manifest file (`pom.xml`) for a Gradle/Java/Kotlin/etc project',\n hidden: false,\n flags: {\n ...commonFlags,\n bin: {\n type: 'string',\n description: 'Location of gradlew binary to use, default: CWD/gradlew'\n },\n cwd: {\n type: 'string',\n description: 'Set the cwd, defaults to process.cwd()'\n },\n gradleOpts: {\n type: 'string',\n default: '',\n description:\n 'Additional options to pass on to ./gradlew, see `./gradlew --help`'\n },\n task: {\n type: 'string',\n default: 'all',\n description: 'Task to target. By default targets all'\n },\n verbose: {\n type: 'boolean',\n description: 'Print debug messages'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} [--bin=path/to/gradle/binary] [--out=path/to/result] DIR\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Uses gradle, preferably through your local project \\`gradlew\\`, to generate a\n \\`pom.xml\\` file for each task. If you have no \\`gradlew\\` you can try the\n global \\`gradle\\` binary but that may not work (hard to predict).\n\n The \\`pom.xml\\` is a manifest file similar to \\`package.json\\` for npm or\n or requirements.txt for PyPi), but specifically for Maven, which is Java's\n dependency repository. Languages like Kotlin and Scala piggy back on it too.\n\n There are some caveats with the gradle to \\`pom.xml\\` conversion:\n\n - each task will generate its own xml file and by default it generates one xml\n for every task.\n\n - it's possible certain features don't translate well into the xml. If you\n think something is missing that could be supported please reach out.\n\n - it works with your \\`gradlew\\` from your repo and local settings and config\n\n Support is beta. Please report issues or give us feedback on what's missing.\n\n Examples\n\n $ ${command} .\n $ ${command} --bin=../gradlew .\n `\n}\n\nexport const cmdManifestGradle = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const verbose = Boolean(cli.flags['verbose'])\n\n if (verbose) {\n logger.group('- ', parentName, config.commandName, ':')\n logger.group('- flags:', cli.flags)\n logger.groupEnd()\n logger.log('- input:', cli.input)\n logger.groupEnd()\n }\n\n const [target = ''] = cli.input\n\n // TODO: I'm not sure it's feasible to parse source file from stdin. We could\n // try, store contents in a file in some folder, target that folder... what\n // would the file name be?\n\n const wasBadInput = handleBadInput(\n {\n test: !!target && target !== '-',\n message: 'The DIR arg is required',\n pass: 'ok',\n fail: target === '-' ? 'stdin is not supported' : 'missing'\n },\n {\n nook: true,\n test: cli.input.length <= 1,\n message: 'Can only accept one DIR (make sure to escape spaces!)',\n pass: 'ok',\n fail: 'received ' + cli.input.length\n }\n )\n if (wasBadInput) {\n return\n }\n\n const { bin = path.join(target, 'gradlew'), cwd = process.cwd() } = cli.flags\n\n if (verbose) {\n logger.group()\n logger.log('- target:', target)\n logger.log('- gradle bin:', bin)\n logger.groupEnd()\n }\n\n let gradleOpts: string[] = []\n if (cli.flags['gradleOpts']) {\n gradleOpts = (cli.flags['gradleOpts'] as string)\n .split(' ')\n .map(s => s.trim())\n .filter(Boolean)\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await convertGradleToMaven(\n target,\n String(bin),\n String(cwd),\n verbose,\n gradleOpts\n )\n}\n","import path from 'node:path'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport constants from '../../constants'\nimport { safeReadFile } from '../../utils/fs'\n\nexport async function convertSbtToMaven(\n target: string,\n bin: string,\n out: string,\n verbose: boolean,\n sbtOpts: string[]\n) {\n // Lazily access constants.spinner.\n const { spinner } = constants\n const rbin = path.resolve(bin)\n const rtarget = path.resolve(target)\n\n if (verbose) {\n logger.group('sbt2maven:')\n logger.log(`[VERBOSE] - Absolute bin path: \\`${rbin}\\``)\n logger.log(`[VERBOSE] - Absolute target path: \\`${rtarget}\\``)\n // logger.log(`[VERBOSE] - Absolute out path: \\`${rout}\\``)\n logger.groupEnd()\n } else {\n logger.group('sbt2maven:')\n logger.log(`- executing: \\`${bin}\\``)\n logger.log(`- src dir: \\`${target}\\``)\n // logger.log(`- dst dir: \\`${out}\\``)\n logger.groupEnd()\n }\n\n try {\n spinner.start(`Converting sbt to maven from \\`${bin}\\` on \\`${target}\\`...`)\n\n // Run sbt with the init script we provide which should yield zero or more\n // pom files. We have to figure out where to store those pom files such that\n // we can upload them and predict them through the GitHub API. We could do a\n // .socket folder. We could do a socket.pom.gz with all the poms, although\n // I'd prefer something plain-text if it is to be committed.\n const output = await spawn(bin, ['makePom'].concat(sbtOpts), {\n cwd: target || '.'\n })\n\n spinner.stop()\n\n if (verbose) {\n logger.group('[VERBOSE] sbt stdout:')\n logger.log(output)\n logger.groupEnd()\n }\n if (output.stderr) {\n process.exitCode = 1\n logger.fail('There were errors while running sbt')\n // (In verbose mode, stderr was printed above, no need to repeat it)\n if (!verbose) {\n logger.group('[VERBOSE] stderr:')\n logger.error(output.stderr)\n logger.groupEnd()\n }\n return\n }\n const poms: string[] = []\n output.stdout.replace(/Wrote (.*?.pom)\\n/g, (_all: string, fn: string) => {\n poms.push(fn)\n return fn\n })\n if (!poms.length) {\n process.exitCode = 1\n logger.fail(\n 'There were no errors from sbt but it seems to not have generated any poms either'\n )\n return\n }\n // Move the pom file to ...? initial cwd? loc will be an absolute path, or dump to stdout\n // TODO: what to do with multiple output files? Do we want to dump them to stdout? Raw or with separators or ?\n // TODO: maybe we can add an option to target a specific file to dump to stdout\n if (out === '-' && poms.length === 1) {\n logger.log('Result:\\n```')\n logger.log(await safeReadFile(poms[0]!))\n logger.log('```')\n logger.success(`OK`)\n } else if (out === '-') {\n process.exitCode = 1\n logger.fail(\n 'Requested out target was stdout but there are multiple generated files'\n )\n poms.forEach(fn => logger.error('-', fn))\n logger.error('Exiting now...')\n return\n } else {\n // if (verbose) {\n // logger.log(\n // `Moving manifest file from \\`${loc.replace(/^\\/home\\/[^/]*?\\//, '~/')}\\` to \\`${out}\\``\n // )\n // } else {\n // logger.log('Moving output pom file')\n // }\n // TODO: do we prefer fs-extra? renaming can be gnarly on windows and fs-extra's version is better\n // await renamep(loc, out)\n logger.success(`Generated ${poms.length} pom files`)\n poms.forEach(fn => logger.log('-', fn))\n logger.success(`OK`)\n }\n } catch (e) {\n process.exitCode = 1\n spinner.stop()\n logger.fail(\n 'There was an unexpected error while running this' +\n (verbose ? '' : ' (use --verbose for details)')\n )\n if (verbose) {\n logger.group('[VERBOSE] error:')\n logger.log(e)\n logger.groupEnd()\n }\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { convertSbtToMaven } from './convert_sbt_to_maven'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'scala',\n description:\n \"[beta] Generate a manifest file (`pom.xml`) from Scala's `build.sbt` file\",\n hidden: false,\n flags: {\n ...commonFlags,\n bin: {\n type: 'string',\n default: 'sbt',\n description: 'Location of sbt binary to use'\n },\n cwd: {\n type: 'string',\n description: 'Set the cwd, defaults to process.cwd()'\n },\n out: {\n type: 'string',\n default: './socket.pom.xml',\n description:\n 'Path of output file; where to store the resulting manifest, see also --stdout'\n },\n stdout: {\n type: 'boolean',\n description: 'Print resulting pom.xml to stdout (supersedes --out)'\n },\n sbtOpts: {\n type: 'string',\n default: '',\n description: 'Additional options to pass on to sbt, as per `sbt --help`'\n },\n verbose: {\n type: 'boolean',\n description: 'Print debug messages'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} [--bin=path/to/sbt/binary] [--out=path/to/result] FILE|DIR\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Uses \\`sbt makePom\\` to generate a \\`pom.xml\\` from your \\`build.sbt\\` file.\n This xml file is the dependency manifest (like a package.json\n for Node.js or requirements.txt for PyPi), but specifically for Scala.\n\n There are some caveats with \\`build.sbt\\` to \\`pom.xml\\` conversion:\n\n - the xml is exported as socket.pom.xml as to not confuse existing build tools\n but it will first hit your /target/sbt<version> folder (as a different name)\n\n - the pom.xml format (standard by Scala) does not support certain sbt features\n - \\`excludeAll()\\`, \\`dependencyOverrides\\`, \\`force()\\`, \\`relativePath\\`\n - For details: https://www.scala-sbt.org/1.x/docs/Library-Management.html\n\n - it uses your sbt settings and local configuration verbatim\n\n - it can only export one target per run, so if you have multiple targets like\n development and production, you must run them separately.\n\n You can optionally configure the path to the \\`sbt\\` bin to invoke.\n\n Support is beta. Please report issues or give us feedback on what's missing.\n\n This is only for SBT. If your Scala setup uses gradle, please see the help\n sections for \\`socket manifest gradle\\` or \\`socket cdxgen\\`.\n\n Examples\n\n $ ${command} ./build.sbt\n $ ${command} --bin=/usr/bin/sbt ./build.sbt\n `\n}\n\nexport const cmdManifestScala = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const verbose = Boolean(cli.flags['verbose'])\n\n if (verbose) {\n logger.group('- ', parentName, config.commandName, ':')\n logger.group('- flags:', cli.flags)\n logger.groupEnd()\n logger.log('- input:', cli.input)\n logger.groupEnd()\n }\n\n const [target = ''] = cli.input\n\n // TODO: I'm not sure it's feasible to parse source file from stdin. We could\n // try, store contents in a file in some folder, target that folder... what\n // would the file name be?\n\n const wasBadInput = handleBadInput(\n {\n test: !!target && target !== '-',\n message: 'The DIR arg is required',\n pass: 'ok',\n fail: target === '-' ? 'stdin is not supported' : 'missing'\n },\n {\n nook: true,\n test: cli.input.length <= 1,\n message: 'Can only accept one DIR (make sure to escape spaces!)',\n pass: 'ok',\n fail: 'received ' + cli.input.length\n }\n )\n if (wasBadInput) {\n return\n }\n\n let bin: string = 'sbt'\n if (cli.flags['bin']) {\n bin = cli.flags['bin'] as string\n }\n\n let out: string = './socket.pom.xml'\n if (cli.flags['out']) {\n out = cli.flags['out'] as string\n }\n if (cli.flags['stdout']) {\n out = '-'\n }\n\n if (verbose) {\n logger.group()\n logger.log('- target:', target)\n logger.log('- gradle bin:', bin)\n logger.log('- out:', out)\n logger.groupEnd()\n }\n\n let sbtOpts: string[] = []\n if (cli.flags['sbtOpts']) {\n sbtOpts = (cli.flags['sbtOpts'] as string)\n .split(' ')\n .map(s => s.trim())\n .filter(Boolean)\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await convertSbtToMaven(target, bin, out, verbose, sbtOpts)\n}\n","import { existsSync } from 'node:fs'\nimport path from 'node:path'\n\nimport meow from 'meow'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { cmdManifestConda } from './cmd-manifest-conda'\nimport { cmdManifestGradle } from './cmd-manifest-gradle'\nimport { cmdManifestScala } from './cmd-manifest-scala'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'auto',\n description: 'Auto-detect build and attempt to generate manifest file',\n hidden: false,\n flags: {\n ...commonFlags,\n cwd: {\n type: 'string',\n description: 'Set the cwd, defaults to process.cwd()'\n },\n verbose: {\n type: 'boolean',\n default: false,\n description: 'Enable debug output, may help when running into errors'\n }\n // TODO: support output flags\n },\n help: (command, config) => `\n Usage\n $ ${command}\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Tries to figure out what language your current repo uses. If it finds a\n supported case then it will try to generate the manifest file for that\n language with the default or detected settings.\n `\n}\n\nexport const cmdManifestAuto = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n const verbose = !!cli.flags['verbose']\n const cwd = (cli.flags['cwd'] as string) ?? process.cwd()\n\n if (verbose) {\n logger.group('- ', parentName, config.commandName, ':')\n logger.group('- flags:', cli.flags)\n logger.groupEnd()\n logger.log('- input:', cli.input)\n logger.log('- cwd:', cwd)\n logger.groupEnd()\n }\n\n const subArgs = []\n if (verbose) {\n subArgs.push('--verbose')\n }\n\n const dir = cwd\n\n if (existsSync(path.join(dir, 'build.sbt'))) {\n logger.log('Detected a Scala sbt build, running default Scala generator...')\n if (cwd) {\n subArgs.push('--cwd', cwd)\n }\n subArgs.push(dir)\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n await cmdManifestScala.run(subArgs, importMeta, { parentName })\n return\n }\n\n if (existsSync(path.join(dir, 'gradlew'))) {\n logger.log('Detected a gradle build, running default gradle generator...')\n if (cwd) {\n // This command takes the cwd as first arg.\n subArgs.push(cwd)\n }\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n await cmdManifestGradle.run(subArgs, importMeta, { parentName })\n return\n }\n\n const envyml = path.join(dir, 'environment.yml')\n const hasEnvyml = existsSync(envyml)\n const envyaml = path.join(dir, 'environment.yaml')\n const hasEnvyaml = !hasEnvyml && existsSync(envyaml)\n if (hasEnvyml || hasEnvyaml) {\n logger.log(\n 'Detected an environment.yml file, running default Conda generator...'\n )\n // This command takes the TARGET as first arg.\n subArgs.push(hasEnvyml ? envyml : hasEnvyaml ? envyaml : '')\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n await cmdManifestConda.run(subArgs, importMeta, { parentName })\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n // Show new help screen and exit.\n meow(\n `\n $ ${parentName} ${config.commandName}\n\n Unfortunately this script did not discover a supported language in the\n current folder.\n\n - Make sure this script would work with your target build\n - Make sure to run it from the correct folder\n - Make sure the necessary build tools are available (\\`PATH\\`)\n\n If that doesn't work, see \\`${parentName} <lang> --help\\` for config details for\n your target language.\n `,\n {\n argv: [],\n description: config.description,\n importMeta\n }\n ).showHelp()\n}\n","import path from 'node:path'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { convertGradleToMaven } from './convert_gradle_to_maven'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\n// TODO: we may want to dedupe some pieces for all gradle languages. I think it\n// makes sense to have separate commands for them and I think it makes\n// sense for the help panels to note the requested language, rather than\n// `socket manifest kotlin` to print help screens with `gradle` as the\n// command. Room for improvement.\nconst config: CliCommandConfig = {\n commandName: 'kotlin',\n description:\n '[beta] Use Gradle to generate a manifest file (`pom.xml`) for a Kotlin project',\n hidden: false,\n flags: {\n ...commonFlags,\n bin: {\n type: 'string',\n description: 'Location of gradlew binary to use, default: CWD/gradlew'\n },\n cwd: {\n type: 'string',\n description: 'Set the cwd, defaults to process.cwd()'\n },\n gradleOpts: {\n type: 'string',\n default: '',\n description:\n 'Additional options to pass on to ./gradlew, see `./gradlew --help`'\n },\n task: {\n type: 'string',\n default: 'all',\n description: 'Task to target. By default targets all'\n },\n verbose: {\n type: 'boolean',\n description: 'Print debug messages'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} [--bin=path/to/gradle/binary] [--out=path/to/result] DIR\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Uses gradle, preferably through your local project \\`gradlew\\`, to generate a\n \\`pom.xml\\` file for each task. If you have no \\`gradlew\\` you can try the\n global \\`gradle\\` binary but that may not work (hard to predict).\n\n The \\`pom.xml\\` is a manifest file similar to \\`package.json\\` for npm or\n or requirements.txt for PyPi), but specifically for Maven, which is Java's\n dependency repository. Languages like Kotlin and Scala piggy back on it too.\n\n There are some caveats with the gradle to \\`pom.xml\\` conversion:\n\n - each task will generate its own xml file and by default it generates one xml\n for every task. (This may be a good thing!)\n\n - it's possible certain features don't translate well into the xml. If you\n think something is missing that could be supported please reach out.\n\n - it works with your \\`gradlew\\` from your repo and local settings and config\n\n Support is beta. Please report issues or give us feedback on what's missing.\n\n Examples\n\n $ ${command} .\n $ ${command} --bin=../gradlew .\n `\n}\n\nexport const cmdManifestKotlin = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const verbose = Boolean(cli.flags['verbose'])\n\n if (verbose) {\n logger.group('- ', parentName, config.commandName, ':')\n logger.group('- flags:', cli.flags)\n logger.groupEnd()\n logger.log('- input:', cli.input)\n logger.groupEnd()\n }\n\n const [target = ''] = cli.input\n\n // TODO: I'm not sure it's feasible to parse source file from stdin. We could\n // try, store contents in a file in some folder, target that folder... what\n // would the file name be?\n\n const wasBadInput = handleBadInput(\n {\n test: !!target && target !== '-',\n message: 'The DIR arg is required',\n pass: 'ok',\n fail: target === '-' ? 'stdin is not supported' : 'missing'\n },\n {\n nook: true,\n test: cli.input.length <= 1,\n message: 'Can only accept one DIR (make sure to escape spaces!)',\n pass: 'ok',\n fail: 'received ' + cli.input.length\n }\n )\n if (wasBadInput) {\n return\n }\n\n const { bin = path.join(target, 'gradlew'), cwd = process.cwd() } = cli.flags\n\n if (verbose) {\n logger.group()\n logger.log('- target:', target)\n logger.log('- gradle bin:', bin)\n logger.groupEnd()\n }\n\n let gradleOpts: string[] = []\n if (cli.flags['gradleOpts']) {\n gradleOpts = (cli.flags['gradleOpts'] as string)\n .split(' ')\n .map(s => s.trim())\n .filter(Boolean)\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await convertGradleToMaven(\n target,\n String(bin),\n String(cwd),\n verbose,\n gradleOpts\n )\n}\n","import { cmdManifestAuto } from './cmd-manifest-auto'\nimport { cmdManifestConda } from './cmd-manifest-conda'\nimport { cmdManifestGradle } from './cmd-manifest-gradle'\nimport { cmdManifestKotlin } from './cmd-manifest-kotlin'\nimport { cmdManifestScala } from './cmd-manifest-scala'\nimport { commonFlags } from '../../flags'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst config: CliCommandConfig = {\n commandName: 'manifest',\n description: 'Generate a dependency manifest for given file or dir',\n hidden: false,\n flags: {\n ...commonFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <language> <target>\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Generates a declarative dependency manifest (like a package.json for Node.JS\n or requirements.txt for PyPi), but for certain supported ecosystems\n where it's common to use a dynamic manifest, like Scala's sbt.\n\n Only certain languages are supported and there may be language specific\n configurations available. See \\`manifest <language> --help\\` for usage details\n per language.\n\n Currently supported language: scala [beta], gradle [beta], kotlin (through\n gradle) [beta].\n\n Examples\n\n $ ${command} scala .\n\n To have it auto-detect and attempt to run:\n\n $ ${command} yolo\n `\n}\n\nexport const cmdManifest = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n await meowWithSubcommands(\n {\n auto: cmdManifestAuto,\n conda: cmdManifestConda,\n scala: cmdManifestScala,\n gradle: cmdManifestGradle,\n kotlin: cmdManifestKotlin\n },\n {\n argv,\n aliases: {\n yolo: {\n description: config.description,\n hidden: true,\n argv: ['auto']\n }\n },\n description: config.description,\n importMeta,\n flags: config.flags,\n name: `${parentName} ${config.commandName}`\n }\n )\n}\n","import constants from '../../constants'\n\nconst { NPM } = constants\n\nexport async function wrapNpm(argv: readonly string[]) {\n // Lazily access constants.distShadowNpmBinPath.\n const shadowBin = require(constants.distShadowNpmBinPath)\n await shadowBin(NPM, argv)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { wrapNpm } from './wrap-npm'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT, NPM } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'npm',\n description: `${NPM} wrapper functionality`,\n hidden: false,\n flags: {\n ...commonFlags\n },\n help: (command, _config) => `\n Usage\n $ ${command}\n `\n}\n\nexport const cmdNpm = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n allowUnknownFlags: true,\n argv,\n config,\n importMeta,\n parentName\n })\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await wrapNpm(argv)\n}\n","import constants from '../../constants'\n\nconst { NPX } = constants\n\nexport async function wrapNpx(argv: readonly string[]) {\n // Lazily access constants.distShadowNpmBinPath.\n const shadowBin = require(constants.distShadowNpmBinPath)\n await shadowBin(NPX, argv)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { wrapNpx } from './wrap-npx'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT, NPX } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'npx',\n description: `${NPX} wrapper functionality`,\n hidden: false,\n flags: {\n ...commonFlags\n },\n help: (command, _config) => `\n Usage\n $ ${command}\n `\n}\n\nexport const cmdNpx = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n allowUnknownFlags: true,\n argv,\n config,\n importMeta,\n parentName\n })\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await wrapNpx(argv)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'oops',\n description: 'Trigger an intentional error (for development)',\n hidden: true,\n flags: {\n ...commonFlags\n },\n help: (parentName, config) => `\n Usage\n $ ${parentName} ${config.commandName}\n\n Don't run me.\n `\n}\n\nexport const cmdOops = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n throw new Error('This error was intentionally left blank')\n}\n","import constants from '../../constants'\n\nimport type { Agent } from '../../utils/package-environment'\n\ntype AgentDepsIncludesFn = (stdout: string, name: string) => boolean\n\nconst { BUN, NPM, PNPM, VLT, YARN_BERRY, YARN_CLASSIC } = constants\n\nfunction matchLsCmdViewHumanStdout(stdout: string, name: string) {\n return stdout.includes(` ${name}@`)\n}\n\nfunction matchQueryCmdStdout(stdout: string, name: string) {\n return stdout.includes(`\"${name}\"`)\n}\n\nexport const depsIncludesByAgent = new Map<Agent, AgentDepsIncludesFn>([\n [BUN, matchLsCmdViewHumanStdout],\n [NPM, matchQueryCmdStdout],\n [PNPM, matchQueryCmdStdout],\n [VLT, matchQueryCmdStdout],\n [YARN_BERRY, matchLsCmdViewHumanStdout],\n [YARN_CLASSIC, matchLsCmdViewHumanStdout]\n])\n","import type { EnvDetails } from '../../utils/package-environment'\n\nexport function getDependencyEntries(pkgEnvDetails: EnvDetails) {\n const {\n dependencies,\n devDependencies,\n optionalDependencies,\n peerDependencies\n } = pkgEnvDetails.editablePkgJson.content\n return [\n [\n 'dependencies',\n dependencies ? { __proto__: null, ...dependencies } : undefined\n ],\n [\n 'devDependencies',\n devDependencies ? { __proto__: null, ...devDependencies } : undefined\n ],\n [\n 'peerDependencies',\n peerDependencies ? { __proto__: null, ...peerDependencies } : undefined\n ],\n [\n 'optionalDependencies',\n optionalDependencies\n ? { __proto__: null, ...optionalDependencies }\n : undefined\n ]\n ].filter(({ 1: o }) => o) as Array<[string, NonNullable<typeof dependencies>]>\n}\n","import constants from '../../constants'\n\nimport type { NpmOverrides, Overrides, PnpmOrYarnOverrides } from './types'\nimport type { Agent, EnvDetails } from '../../utils/package-environment'\n\nconst {\n BUN,\n NPM,\n OVERRIDES,\n PNPM,\n RESOLUTIONS,\n VLT,\n YARN_BERRY,\n YARN_CLASSIC\n} = constants\n\nfunction getOverridesDataBun(pkgEnvDetails: EnvDetails) {\n const overrides =\n pkgEnvDetails.editablePkgJson.content?.[RESOLUTIONS] ??\n ({} as PnpmOrYarnOverrides)\n return { type: YARN_BERRY, overrides }\n}\n\n// npm overrides documentation:\n// https://docs.npmjs.com/cli/v10/configuring-npm/package-json#overrides\nfunction getOverridesDataNpm(pkgEnvDetails: EnvDetails) {\n const overrides =\n pkgEnvDetails.editablePkgJson.content?.[OVERRIDES] ?? ({} as NpmOverrides)\n return { type: NPM, overrides }\n}\n\n// pnpm overrides documentation:\n// https://pnpm.io/package_json#pnpmoverrides\nfunction getOverridesDataPnpm(pkgEnvDetails: EnvDetails) {\n const overrides =\n (pkgEnvDetails.editablePkgJson.content as any)?.[PNPM]?.[OVERRIDES] ??\n ({} as PnpmOrYarnOverrides)\n return { type: PNPM, overrides }\n}\n\nfunction getOverridesDataVlt(pkgEnvDetails: EnvDetails) {\n const overrides =\n pkgEnvDetails.editablePkgJson.content?.[OVERRIDES] ?? ({} as NpmOverrides)\n return { type: VLT, overrides }\n}\n\n// Yarn resolutions documentation:\n// https://yarnpkg.com/configuration/manifest#resolutions\nfunction getOverridesDataYarn(pkgEnvDetails: EnvDetails) {\n const overrides =\n pkgEnvDetails.editablePkgJson.content?.[RESOLUTIONS] ??\n ({} as PnpmOrYarnOverrides)\n return { type: YARN_BERRY, overrides }\n}\n\n// Yarn resolutions documentation:\n// https://classic.yarnpkg.com/en/docs/selective-version-resolutions\nfunction getOverridesDataYarnClassic(pkgEnvDetails: EnvDetails) {\n const overrides =\n pkgEnvDetails.editablePkgJson.content?.[RESOLUTIONS] ??\n ({} as PnpmOrYarnOverrides)\n return { type: YARN_CLASSIC, overrides }\n}\n\nexport type GetOverrides = (pkgEnvDetails: EnvDetails) => GetOverridesResult\n\nexport type GetOverridesResult = { type: Agent; overrides: Overrides }\n\nexport const overridesDataByAgent = new Map<Agent, GetOverrides>([\n [BUN, getOverridesDataBun],\n [NPM, getOverridesDataNpm],\n [PNPM, getOverridesDataPnpm],\n [VLT, getOverridesDataVlt],\n [YARN_BERRY, getOverridesDataYarn],\n [YARN_CLASSIC, getOverridesDataYarnClassic]\n] as ReadonlyArray<[Agent, GetOverrides]>)\n","import { escapeRegExp } from '@socketsecurity/registry/lib/regexps'\n\nimport constants from '../../constants'\n\nimport type { Agent } from '../../utils/package-environment'\n\nexport type AgentLockIncludesFn = (\n lockSrc: string,\n name: string,\n ext?: string | undefined\n) => boolean\n\nconst { BUN, LOCK_EXT, NPM, PNPM, VLT, YARN_BERRY, YARN_CLASSIC } = constants\n\nfunction includesNpm(lockSrc: string, name: string) {\n // Detects the package name in the following cases:\n // \"name\":\n return lockSrc.includes(`\"${name}\":`)\n}\n\nfunction includesBun(lockSrc: string, name: string, lockName?: string) {\n // This is a bit counterintuitive. When lockName ends with a .lockb\n // we treat it as a yarn.lock. When lockName ends with a .lock we\n // treat it as a package-lock.json. The bun.lock format is not identical\n // package-lock.json, however it close enough for npmLockIncludes to work.\n const lockfileScanner = lockName?.endsWith(LOCK_EXT)\n ? includesNpm\n : includesYarn\n return lockfileScanner(lockSrc, name)\n}\n\nfunction includesPnpm(lockSrc: string, name: string) {\n const escapedName = escapeRegExp(name)\n return new RegExp(\n // Detects the package name in the following cases:\n // /name/\n // 'name'\n // name:\n // name@\n `(?<=^\\\\s*)(?:(['/])${escapedName}\\\\1|${escapedName}(?=[:@]))`,\n 'm'\n ).test(lockSrc)\n}\n\nfunction includesVlt(lockSrc: string, name: string) {\n // Detects the package name in the following cases:\n // \"name\"\n return lockSrc.includes(`\"${name}\"`)\n}\n\nfunction includesYarn(lockSrc: string, name: string) {\n const escapedName = escapeRegExp(name)\n return new RegExp(\n // Detects the package name in the following cases:\n // \"name@\n // , \"name@\n // name@\n // , name@\n `(?<=(?:^\\\\s*|,\\\\s*)\"?)${escapedName}(?=@)`,\n 'm'\n ).test(lockSrc)\n}\n\nexport const lockfileIncludesByAgent = new Map<Agent, AgentLockIncludesFn>([\n [BUN, includesBun],\n [NPM, includesNpm],\n [PNPM, includesPnpm],\n [VLT, includesVlt],\n [YARN_BERRY, includesYarn],\n [YARN_CLASSIC, includesYarn]\n])\n","import { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport constants from '../../constants'\n\nimport type { Agent, EnvDetails } from '../../utils/package-environment'\n\nconst { BUN, NPM, PNPM, VLT, YARN_BERRY, YARN_CLASSIC } = constants\n\nfunction cleanupQueryStdout(stdout: string): string {\n if (stdout === '') {\n return ''\n }\n let pkgs\n try {\n pkgs = JSON.parse(stdout)\n } catch {}\n if (!Array.isArray(pkgs)) {\n return ''\n }\n const names = new Set<string>()\n for (const { _id, name, pkgid } of pkgs) {\n // `npm query` results may not have a \"name\" property, in which case we\n // fallback to \"_id\" and then \"pkgid\".\n // `vlt ls --view json` results always have a \"name\" property.\n const fallback = _id ?? pkgid ?? ''\n const resolvedName = name ?? fallback.slice(0, fallback.indexOf('@', 1))\n // Add package names, except for those under the `@types` scope as those\n // are known to only be dev dependencies.\n if (resolvedName && !resolvedName.startsWith('@types/')) {\n names.add(resolvedName)\n }\n }\n return JSON.stringify([...names], null, 2)\n}\n\nfunction parsableToQueryStdout(stdout: string) {\n if (stdout === '') {\n return ''\n }\n // Convert the parsable stdout into a json array of unique names.\n // The matchAll regexp looks for a forward (posix) or backward (win32) slash\n // and matches one or more non-slashes until the newline.\n const names = new Set(stdout.matchAll(/(?<=[/\\\\])[^/\\\\]+(?=\\n)/g))\n return JSON.stringify([...names], null, 2)\n}\n\nasync function npmQuery(npmExecPath: string, cwd: string): Promise<string> {\n let stdout = ''\n try {\n stdout = (await spawn(npmExecPath, ['query', ':not(.dev)'], { cwd })).stdout\n } catch {}\n return cleanupQueryStdout(stdout)\n}\n\nasync function lsBun(pkgEnvDetails: EnvDetails, cwd: string): Promise<string> {\n try {\n // Bun does not support filtering by production packages yet.\n // https://github.com/oven-sh/bun/issues/8283\n return (\n await spawn(pkgEnvDetails.agentExecPath, ['pm', 'ls', '--all'], { cwd })\n ).stdout\n } catch {}\n return ''\n}\n\nasync function lsNpm(pkgEnvDetails: EnvDetails, cwd: string): Promise<string> {\n return await npmQuery(pkgEnvDetails.agentExecPath, cwd)\n}\n\nasync function lsPnpm(\n pkgEnvDetails: EnvDetails,\n cwd: string,\n options?: AgentListDepsOptions | undefined\n): Promise<string> {\n const npmExecPath = options?.npmExecPath\n if (npmExecPath && npmExecPath !== NPM) {\n const result = await npmQuery(npmExecPath, cwd)\n if (result) {\n return result\n }\n }\n let stdout = ''\n try {\n stdout = (\n await spawn(\n pkgEnvDetails.agentExecPath,\n // Pnpm uses the alternative spelling of parsable.\n // https://en.wiktionary.org/wiki/parsable\n ['ls', '--parseable', '--prod', '--depth', 'Infinity'],\n { cwd }\n )\n ).stdout\n } catch {}\n return parsableToQueryStdout(stdout)\n}\n\nasync function lsVlt(pkgEnvDetails: EnvDetails, cwd: string): Promise<string> {\n let stdout = ''\n try {\n // See https://docs.vlt.sh/cli/commands/list#options.\n stdout = (\n await spawn(\n pkgEnvDetails.agentExecPath,\n ['ls', '--view', 'human', ':not(.dev)'],\n {\n cwd\n }\n )\n ).stdout\n } catch {}\n return cleanupQueryStdout(stdout)\n}\n\nasync function lsYarnBerry(\n pkgEnvDetails: EnvDetails,\n cwd: string\n): Promise<string> {\n try {\n return (\n // Yarn Berry does not support filtering by production packages yet.\n // https://github.com/yarnpkg/berry/issues/5117\n (\n await spawn(\n pkgEnvDetails.agentExecPath,\n ['info', '--recursive', '--name-only'],\n {\n cwd\n }\n )\n ).stdout.trim()\n )\n } catch {}\n return ''\n}\n\nasync function lsYarnClassic(\n pkgEnvDetails: EnvDetails,\n cwd: string\n): Promise<string> {\n try {\n // However, Yarn Classic does support it.\n // https://github.com/yarnpkg/yarn/releases/tag/v1.0.0\n // > Fix: Excludes dev dependencies from the yarn list output when the\n // environment is production\n return (\n await spawn(pkgEnvDetails.agentExecPath, ['list', '--prod'], { cwd })\n ).stdout.trim()\n } catch {}\n return ''\n}\n\nexport type AgentListDepsOptions = { npmExecPath?: string }\n\nexport type AgentListDepsFn = (\n pkgEnvDetails: EnvDetails,\n cwd: string,\n options?: AgentListDepsOptions | undefined\n) => Promise<string>\n\nexport const lsByAgent = new Map<Agent, AgentListDepsFn>([\n [BUN, lsBun],\n [NPM, lsNpm],\n [PNPM, lsPnpm],\n [VLT, lsVlt],\n [YARN_BERRY, lsYarnBerry],\n [YARN_CLASSIC, lsYarnClassic]\n])\n","export const CMD_NAME = 'socket optimize'\n","import { hasKeys, isObject } from '@socketsecurity/registry/lib/objects'\n\nimport constants from '../../constants'\n\nimport type { Overrides } from './types'\nimport type { Agent, EnvDetails } from '../../utils/package-environment'\nimport type { EditablePackageJson } from '@socketsecurity/registry/lib/packages'\n\nconst {\n BUN,\n NPM,\n OVERRIDES,\n PNPM,\n RESOLUTIONS,\n VLT,\n YARN_BERRY,\n YARN_CLASSIC\n} = constants\n\nconst depFields = [\n 'dependencies',\n 'devDependencies',\n 'peerDependencies',\n 'peerDependenciesMeta',\n 'optionalDependencies',\n 'bundleDependencies'\n]\n\nfunction getEntryIndexes(\n entries: Array<[string | symbol, any]>,\n keys: Array<string | symbol>\n): number[] {\n return keys\n .map(n => entries.findIndex(p => p[0] === n))\n .filter(n => n !== -1)\n .sort((a, b) => a - b)\n}\n\nfunction getLowestEntryIndex(\n entries: Array<[string | symbol, any]>,\n keys: Array<string | symbol>\n) {\n return getEntryIndexes(entries, keys)?.[0] ?? -1\n}\n\nfunction getHighestEntryIndex(\n entries: Array<[string | symbol, any]>,\n keys: Array<string | symbol>\n) {\n return getEntryIndexes(entries, keys).at(-1) ?? -1\n}\n\nfunction updatePkgJsonField(\n editablePkgJson: EditablePackageJson,\n field: string,\n value: any\n) {\n const oldValue = editablePkgJson.content[field]\n if (oldValue) {\n // The field already exists so we simply update the field value.\n if (field === PNPM) {\n const isPnpmObj = isObject(oldValue)\n if (hasKeys(value)) {\n editablePkgJson.update({\n [field]: {\n ...(isPnpmObj ? oldValue : {}),\n overrides: {\n ...(isPnpmObj ? (oldValue as any)[OVERRIDES] : {}),\n ...value\n }\n }\n })\n } else {\n // Properties with undefined values are omitted when saved as JSON.\n editablePkgJson.update(\n (hasKeys(oldValue)\n ? {\n [field]: {\n ...(isPnpmObj ? oldValue : {}),\n overrides: undefined\n }\n }\n : { [field]: undefined }) as typeof editablePkgJson.content\n )\n }\n } else if (field === OVERRIDES || field === RESOLUTIONS) {\n // Properties with undefined values are omitted when saved as JSON.\n editablePkgJson.update({\n [field]: hasKeys(value) ? value : undefined\n } as typeof editablePkgJson.content)\n } else {\n editablePkgJson.update({ [field]: value })\n }\n return\n }\n if (\n (field === OVERRIDES || field === PNPM || field === RESOLUTIONS) &&\n !hasKeys(value)\n ) {\n return\n }\n // Since the field doesn't exist we want to insert it into the package.json\n // in a place that makes sense, e.g. close to the \"dependencies\" field. If\n // we can't find a place to insert the field we'll add it to the bottom.\n const entries = Object.entries(editablePkgJson.content)\n let insertIndex = -1\n let isPlacingHigher = false\n if (field === OVERRIDES) {\n insertIndex = getLowestEntryIndex(entries, [RESOLUTIONS])\n if (insertIndex === -1) {\n isPlacingHigher = true\n insertIndex = getHighestEntryIndex(entries, [...depFields, PNPM])\n }\n } else if (field === RESOLUTIONS) {\n isPlacingHigher = true\n insertIndex = getHighestEntryIndex(entries, [...depFields, OVERRIDES, PNPM])\n } else if (field === PNPM) {\n insertIndex = getLowestEntryIndex(entries, [OVERRIDES, RESOLUTIONS])\n if (insertIndex === -1) {\n isPlacingHigher = true\n insertIndex = getHighestEntryIndex(entries, depFields)\n }\n }\n if (insertIndex === -1) {\n insertIndex = getLowestEntryIndex(entries, ['engines', 'files'])\n }\n if (insertIndex === -1) {\n isPlacingHigher = true\n insertIndex = getHighestEntryIndex(entries, ['exports', 'imports', 'main'])\n }\n if (insertIndex === -1) {\n insertIndex = entries.length\n } else if (isPlacingHigher) {\n insertIndex += 1\n }\n entries.splice(insertIndex, 0, [\n field,\n field === PNPM ? { [OVERRIDES]: value } : value\n ])\n editablePkgJson.fromJSON(\n `${JSON.stringify(Object.fromEntries(entries), null, 2)}\\n`\n )\n}\n\nfunction updateOverridesField(pkgEnvDetails: EnvDetails, overrides: Overrides) {\n updatePkgJsonField(pkgEnvDetails.editablePkgJson, OVERRIDES, overrides)\n}\n\nfunction updateResolutionsField(\n pkgEnvDetails: EnvDetails,\n overrides: Overrides\n) {\n updatePkgJsonField(pkgEnvDetails.editablePkgJson, RESOLUTIONS, overrides)\n}\n\nfunction updatePnpmField(pkgEnvDetails: EnvDetails, overrides: Overrides) {\n updatePkgJsonField(pkgEnvDetails.editablePkgJson, PNPM, overrides)\n}\n\nexport type AgentModifyManifestFn = (\n pkgEnvDetails: EnvDetails,\n overrides: Overrides\n) => void\n\nexport const updateManifestByAgent = new Map<Agent, AgentModifyManifestFn>([\n [BUN, updateResolutionsField],\n [NPM, updateOverridesField],\n [PNPM, updatePnpmField],\n [VLT, updateOverridesField],\n [YARN_BERRY, updateResolutionsField],\n [YARN_CLASSIC, updateResolutionsField]\n])\n","import path from 'node:path'\n\nimport npa from 'npm-package-arg'\nimport semver from 'semver'\n\nimport { getManifestData } from '@socketsecurity/registry'\nimport { hasOwn, toSortedObject } from '@socketsecurity/registry/lib/objects'\nimport { fetchPackageManifest } from '@socketsecurity/registry/lib/packages'\nimport { pEach } from '@socketsecurity/registry/lib/promises'\nimport { Spinner } from '@socketsecurity/registry/lib/spinner'\n\nimport { depsIncludesByAgent } from './deps-includes-by-agent'\nimport { getDependencyEntries } from './get-dependency-entries'\nimport { overridesDataByAgent } from './get-overrides-by-agent'\nimport { lockfileIncludesByAgent } from './lockfile-includes-by-agent'\nimport { lsByAgent } from './ls-by-agent'\nimport { CMD_NAME } from './shared'\nimport { updateManifestByAgent } from './update-manifest-by-agent'\nimport constants from '../../constants'\nimport { cmdPrefixMessage } from '../../utils/cmd'\nimport { globWorkspace } from '../../utils/glob'\n\nimport type { GetOverridesResult } from './get-overrides-by-agent'\nimport type { AgentLockIncludesFn } from './lockfile-includes-by-agent'\nimport type { EnvDetails } from '../../utils/package-environment'\nimport type { Logger } from '@socketsecurity/registry/lib/logger'\nimport type { PackageJson } from '@socketsecurity/registry/lib/packages'\n\ntype AddOverridesOptions = {\n logger?: Logger | undefined\n pin?: boolean | undefined\n prod?: boolean | undefined\n spinner?: Spinner | undefined\n state?: AddOverridesState | undefined\n}\ntype AddOverridesState = {\n added: Set<string>\n addedInWorkspaces: Set<string>\n updated: Set<string>\n updatedInWorkspaces: Set<string>\n warnedPnpmWorkspaceRequiresNpm: boolean\n workspacePkgJsonPaths: string[]\n}\n\nconst { NPM, PNPM, YARN_CLASSIC } = constants\n\nconst manifestNpmOverrides = getManifestData(NPM)\n\nexport async function addOverrides(\n pkgEnvDetails: EnvDetails,\n pkgPath: string,\n options?: AddOverridesOptions | undefined\n): Promise<AddOverridesState> {\n const {\n agent,\n lockName,\n lockSrc,\n npmExecPath,\n pkgPath: rootPath\n } = pkgEnvDetails\n const {\n logger,\n pin,\n prod,\n spinner,\n state = {\n added: new Set(),\n addedInWorkspaces: new Set(),\n updated: new Set(),\n updatedInWorkspaces: new Set(),\n warnedPnpmWorkspaceRequiresNpm: false,\n workspacePkgJsonPaths: await globWorkspace(pkgEnvDetails)\n }\n } = { __proto__: null, ...options } as AddOverridesOptions\n const isWorkspace = state.workspacePkgJsonPaths.length > 0\n const isWorkspaceRoot = pkgPath === rootPath\n const isLockScanned = isWorkspaceRoot && !prod\n const workspaceName = isWorkspaceRoot ? '' : path.relative(rootPath, pkgPath)\n if (\n isWorkspace &&\n agent === PNPM &&\n // npmExecPath will === the agent name IF it CANNOT be resolved.\n npmExecPath === NPM &&\n !state.warnedPnpmWorkspaceRequiresNpm\n ) {\n state.warnedPnpmWorkspaceRequiresNpm = true\n logger?.warn(\n cmdPrefixMessage(\n CMD_NAME,\n `${agent} workspace support requires \\`npm ls\\`, falling back to \\`${agent} list\\``\n )\n )\n }\n\n const overridesDataObjects = [] as GetOverridesResult[]\n if (isWorkspace || pkgEnvDetails.editablePkgJson.content['private']) {\n overridesDataObjects.push(overridesDataByAgent.get(agent)!(pkgEnvDetails))\n } else {\n overridesDataObjects.push(\n overridesDataByAgent.get(NPM)!(pkgEnvDetails),\n overridesDataByAgent.get(YARN_CLASSIC)!(pkgEnvDetails)\n )\n }\n\n spinner?.setText(\n `Adding overrides${workspaceName ? ` to ${workspaceName}` : ''}...`\n )\n\n const depAliasMap = new Map<string, string>()\n const depEntries = getDependencyEntries(pkgEnvDetails)\n\n const manifestEntries = manifestNpmOverrides.filter(({ 1: data }) =>\n semver.satisfies(\n // Roughly check Node range as semver.coerce will strip leading\n // v's, carets (^), comparators (<,<=,>,>=,=), and tildes (~).\n semver.coerce(data.engines.node)!,\n pkgEnvDetails.pkgRequirements.node\n )\n )\n\n // Chunk package names to process them in parallel 3 at a time.\n await pEach(manifestEntries, 3, async ({ 1: data }) => {\n const { name: sockRegPkgName, package: origPkgName, version } = data\n const major = semver.major(version)\n const sockOverridePrefix = `${NPM}:${sockRegPkgName}@`\n const sockOverrideSpec = `${sockOverridePrefix}${pin ? version : `^${major}`}`\n for (const { 1: depObj } of depEntries) {\n const sockSpec = hasOwn(depObj, sockRegPkgName)\n ? depObj[sockRegPkgName]\n : undefined\n if (sockSpec) {\n depAliasMap.set(sockRegPkgName, sockSpec)\n }\n const origSpec = hasOwn(depObj, origPkgName)\n ? depObj[origPkgName]\n : undefined\n if (origSpec) {\n let thisSpec = origSpec\n // Add package aliases for direct dependencies to avoid npm EOVERRIDE\n // errors...\n // https://docs.npmjs.com/cli/v8/using-npm/package-spec#aliases\n if (\n // ...if the spec doesn't start with a valid Socket override.\n !(\n thisSpec.startsWith(sockOverridePrefix) &&\n // Check the validity of the spec by passing it through npa and\n // seeing if it will coerce to a version.\n semver.coerce(npa(thisSpec).rawSpec)?.version\n )\n ) {\n thisSpec = sockOverrideSpec\n depObj[origPkgName] = thisSpec\n state.added.add(sockRegPkgName)\n if (workspaceName) {\n state.addedInWorkspaces.add(workspaceName)\n }\n }\n depAliasMap.set(origPkgName, thisSpec)\n }\n }\n if (isWorkspaceRoot) {\n // The AgentDepsIncludesFn and AgentLockIncludesFn types overlap in their\n // first two parameters. AgentLockIncludesFn accepts an optional third\n // parameter which AgentDepsIncludesFn will ignore so we cast thingScanner\n // as an AgentLockIncludesFn type.\n const thingScanner = (\n isLockScanned\n ? lockfileIncludesByAgent.get(agent)\n : depsIncludesByAgent.get(agent)\n ) as AgentLockIncludesFn\n const thingToScan = isLockScanned\n ? lockSrc\n : await lsByAgent.get(agent)!(pkgEnvDetails, pkgPath, { npmExecPath })\n // Chunk package names to process them in parallel 3 at a time.\n await pEach(overridesDataObjects, 3, async ({ overrides, type }) => {\n const overrideExists = hasOwn(overrides, origPkgName)\n if (\n overrideExists ||\n thingScanner(thingToScan, origPkgName, lockName)\n ) {\n const oldSpec = overrideExists ? overrides[origPkgName]! : undefined\n const origDepAlias = depAliasMap.get(origPkgName)\n const sockRegDepAlias = depAliasMap.get(sockRegPkgName)\n const depAlias = sockRegDepAlias ?? origDepAlias\n let newSpec = sockOverrideSpec\n if (type === NPM && depAlias) {\n // With npm one may not set an override for a package that one directly\n // depends on unless both the dependency and the override itself share\n // the exact same spec. To make this limitation easier to deal with,\n // overrides may also be defined as a reference to a spec for a direct\n // dependency by prefixing the name of the package to match the version\n // of with a $.\n // https://docs.npmjs.com/cli/v8/configuring-npm/package-json#overrides\n newSpec = `$${sockRegDepAlias ? sockRegPkgName : origPkgName}`\n } else if (typeof oldSpec === 'string') {\n const thisSpec = oldSpec.startsWith('$')\n ? depAlias || newSpec\n : oldSpec || newSpec\n if (thisSpec.startsWith(sockOverridePrefix)) {\n if (\n pin &&\n semver.major(\n // Check the validity of the spec by passing it through npa\n // and seeing if it will coerce to a version. semver.coerce\n // will strip leading v's, carets (^), comparators (<,<=,>,>=,=),\n // and tildes (~). If not coerced to a valid version then\n // default to the manifest entry version.\n semver.coerce(npa(thisSpec).rawSpec)?.version ?? version\n ) !== major\n ) {\n const otherVersion = (await fetchPackageManifest(thisSpec))\n ?.version\n if (otherVersion && otherVersion !== version) {\n newSpec = `${sockOverridePrefix}${pin ? otherVersion : `^${semver.major(otherVersion)}`}`\n }\n }\n } else {\n newSpec = oldSpec\n }\n }\n if (newSpec !== oldSpec) {\n overrides[origPkgName] = newSpec\n const addedOrUpdated = overrideExists ? 'updated' : 'added'\n state[addedOrUpdated].add(sockRegPkgName)\n }\n }\n })\n }\n })\n\n if (isWorkspace) {\n // Chunk package names to process them in parallel 3 at a time.\n await pEach(state.workspacePkgJsonPaths, 3, async workspacePkgJsonPath => {\n const otherState = await addOverrides(\n pkgEnvDetails,\n path.dirname(workspacePkgJsonPath),\n {\n logger,\n pin,\n prod,\n spinner,\n state\n }\n )\n for (const key of [\n 'added',\n 'addedInWorkspaces',\n 'updated',\n 'updatedInWorkspaces'\n ] satisfies\n // Here we're just telling TS that we're looping over key names\n // of the type and that they're all Set<string> props. This allows\n // us to do the SetA.add(setB.get) pump type-safe without casts.\n Array<\n keyof Pick<\n AddOverridesState,\n 'added' | 'addedInWorkspaces' | 'updated' | 'updatedInWorkspaces'\n >\n >) {\n for (const value of otherState[key]) {\n state[key].add(value)\n }\n }\n })\n }\n\n if (state.added.size > 0 || state.updated.size > 0) {\n pkgEnvDetails.editablePkgJson.update(\n Object.fromEntries(depEntries) as PackageJson\n )\n for (const { overrides, type } of overridesDataObjects) {\n updateManifestByAgent.get(type)!(pkgEnvDetails, toSortedObject(overrides))\n }\n await pkgEnvDetails.editablePkgJson.save()\n }\n\n return state\n}\n","import { Spinner } from '@socketsecurity/registry/lib/spinner'\n\nimport constants from '../../constants'\nimport { runAgentInstall } from '../../utils/agent'\nimport { cmdPrefixMessage } from '../../utils/cmd'\n\nimport type { EnvDetails } from '../../utils/package-environment'\nimport type { Logger } from '@socketsecurity/registry/lib/logger'\n\nconst { NPM_BUGGY_OVERRIDES_PATCHED_VERSION } = constants\n\nexport type UpdateLockfileOptions = {\n cmdName?: string | undefined\n logger?: Logger | undefined\n spinner?: Spinner | undefined\n}\n\nexport async function updateLockfile(\n pkgEnvDetails: EnvDetails,\n options: UpdateLockfileOptions\n) {\n const {\n cmdName = '',\n logger,\n spinner\n } = {\n __proto__: null,\n ...options\n } as UpdateLockfileOptions\n const isSpinning = !!spinner?.['isSpinning']\n if (!isSpinning) {\n spinner?.start()\n }\n spinner?.setText(`Updating ${pkgEnvDetails.lockName}...`)\n try {\n await runAgentInstall(pkgEnvDetails, { spinner })\n if (pkgEnvDetails.features.npmBuggyOverrides) {\n logger?.log(\n `💡 Re-run ${cmdName ? `${cmdName} ` : ''}whenever ${pkgEnvDetails.lockName} changes.\\n This can be skipped for ${pkgEnvDetails.agent} >=${NPM_BUGGY_OVERRIDES_PATCHED_VERSION}.`\n )\n }\n } catch (e) {\n spinner?.stop()\n logger?.fail(\n cmdPrefixMessage(\n cmdName,\n `${pkgEnvDetails.agent} install failed to update ${pkgEnvDetails.lockName}`\n )\n )\n logger?.error(e)\n }\n if (isSpinning) {\n spinner?.start()\n } else {\n spinner?.stop()\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\nimport { pluralize } from '@socketsecurity/registry/lib/words'\n\nimport { addOverrides } from './add-overrides'\nimport { CMD_NAME } from './shared'\nimport { updateLockfile } from './update-lockfile'\nimport constants from '../../constants'\nimport { detectAndValidatePackageEnvironment } from '../../utils/package-environment'\n\nfunction createActionMessage(\n verb: string,\n overrideCount: number,\n workspaceCount: number\n): string {\n return `${verb} ${overrideCount} Socket.dev optimized ${pluralize('override', overrideCount)}${workspaceCount ? ` in ${workspaceCount} ${pluralize('workspace', workspaceCount)}` : ''}`\n}\n\nexport async function applyOptimization(\n cwd: string,\n pin: boolean,\n prod: boolean\n) {\n const pkgEnvDetails = await detectAndValidatePackageEnvironment(cwd, {\n cmdName: CMD_NAME,\n logger,\n prod\n })\n if (!pkgEnvDetails) {\n return\n }\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Socket optimizing...')\n\n const state = await addOverrides(pkgEnvDetails, pkgEnvDetails.pkgPath, {\n logger,\n pin,\n prod,\n spinner\n })\n\n const addedCount = state.added.size\n const updatedCount = state.updated.size\n const pkgJsonChanged = addedCount > 0 || updatedCount > 0\n\n if (pkgJsonChanged || pkgEnvDetails.features.npmBuggyOverrides) {\n await updateLockfile(pkgEnvDetails, { cmdName: CMD_NAME, logger, spinner })\n }\n\n spinner.stop()\n\n if (pkgJsonChanged) {\n if (updatedCount > 0) {\n logger?.log(\n `${createActionMessage('Updated', updatedCount, state.updatedInWorkspaces.size)}${addedCount ? '.' : '🚀'}`\n )\n }\n if (addedCount > 0) {\n logger?.log(\n `${createActionMessage('Added', addedCount, state.addedInWorkspaces.size)} 🚀`\n )\n }\n } else {\n logger?.log('Congratulations! Already Socket.dev optimized 🎉')\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { applyOptimization } from './apply-optimization'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'optimize',\n description: 'Optimize dependencies with @socketregistry overrides',\n hidden: false,\n flags: {\n ...commonFlags,\n pin: {\n type: 'boolean',\n default: false,\n description: 'Pin overrides to their latest version'\n },\n prod: {\n type: 'boolean',\n default: false,\n description: 'Only add overrides for production dependencies'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command}\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command}\n $ ${command} --pin\n `\n}\n\nexport const cmdOptimize = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const cwd = process.cwd()\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await applyOptimization(\n cwd,\n Boolean(cli.flags['pin']),\n Boolean(cli.flags['prod'])\n )\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchOrganization(): Promise<\n SocketSdkReturnType<'getOrganizations'>['data'] | undefined\n> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching organization list...')\n\n const result = await handleApiCall(\n sockSdk.getOrganizations(),\n 'looking up organizations'\n )\n\n spinner.successAndStop('Received organization list response.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getOrganizations', result)\n }\n\n return result.data\n}\n","import colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { getLastFiveOfApiToken } from '../../utils/api'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputOrganizationList(\n data: SocketSdkReturnType<'getOrganizations'>['data'],\n outputKind: 'text' | 'json' | 'markdown' = 'text'\n): Promise<void> {\n const organizations = Object.values(data.organizations)\n const apiToken = getDefaultToken()\n const lastFiveOfApiToken = getLastFiveOfApiToken(apiToken ?? '?????')\n\n switch (outputKind) {\n case 'json': {\n logger.log(\n JSON.stringify(\n organizations.map(o => ({\n name: o.name,\n id: o.id,\n plan: o.plan\n })),\n null,\n 2\n )\n )\n return\n }\n case 'markdown': {\n // | Syntax | Description |\n // | ----------- | ----------- |\n // | Header | Title |\n // | Paragraph | Text |\n let mw1 = 4\n let mw2 = 2\n let mw3 = 4\n for (const o of organizations) {\n mw1 = Math.max(mw1, o.name?.length ?? 0)\n mw2 = Math.max(mw2, o.id.length)\n mw3 = Math.max(mw3, o.plan.length)\n }\n logger.log('# Organizations\\n')\n logger.log(\n `List of organizations associated with your API key, ending with: ${colors.italic(lastFiveOfApiToken)}\\n`\n )\n logger.log(\n `| Name${' '.repeat(mw1 - 4)} | ID${' '.repeat(mw2 - 2)} | Plan${' '.repeat(mw3 - 4)} |`\n )\n logger.log(\n `| ${'-'.repeat(mw1)} | ${'-'.repeat(mw2)} | ${'-'.repeat(mw3)} |`\n )\n for (const o of organizations) {\n logger.log(\n `| ${(o.name || '').padEnd(mw1, ' ')} | ${(o.id || '').padEnd(mw2, ' ')} | ${(o.plan || '').padEnd(mw3, ' ')} |`\n )\n }\n logger.log(\n `| ${'-'.repeat(mw1)} | ${'-'.repeat(mw2)} | ${'-'.repeat(mw3)} |`\n )\n return\n }\n default: {\n logger.log(\n `List of organizations associated with your API key, ending with: ${colors.italic(lastFiveOfApiToken)}\\n`\n )\n // Just dump\n for (const o of organizations) {\n logger.log(\n `- Name: ${colors.bold(o.name ?? 'undefined')}, ID: ${colors.bold(o.id)}, Plan: ${colors.bold(o.plan)}`\n )\n }\n }\n }\n}\n","import { fetchOrganization } from './fetch-organization-list'\nimport { outputOrganizationList } from './output-organization-list'\n\nexport async function handleOrganizationList(\n outputKind: 'text' | 'json' | 'markdown' = 'text'\n): Promise<void> {\n const data = await fetchOrganization()\n if (!data) {\n return\n }\n\n await outputOrganizationList(data, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleOrganizationList } from './handle-organization-list'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'list',\n description: 'List organizations associated with the API key used',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, _config) => `\n Usage\n $ ${command}\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: none (does need a token)\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n `\n}\n\nexport const cmdOrganizationList = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleOrganizationList(json ? 'json' : markdown ? 'markdown' : 'text')\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchLicensePolicy(\n orgSlug: string\n): Promise<SocketSdkReturnType<'getOrgLicensePolicy'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching organization license policy...')\n\n const result = await handleApiCall(\n sockSdk.getOrgLicensePolicy(orgSlug),\n 'looking up organization quota'\n )\n\n spinner.successAndStop('Received organization license policy response.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getOrgLicensePolicy', result)\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { mdTableOfPairs } from '../../utils/markdown'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputLicensePolicy(\n data: SocketSdkReturnType<'getOrgLicensePolicy'>['data'],\n outputKind: 'text' | 'json' | 'markdown'\n): Promise<void> {\n if (outputKind === 'json') {\n let json\n try {\n json = JSON.stringify(data, null, 2)\n } catch {\n console.error(\n 'Failed to convert the server response to json, try running the same command without --json'\n )\n return\n }\n\n logger.log(json)\n logger.log('')\n return\n }\n\n logger.error('Use --json to get the full result')\n logger.log('# License policy')\n logger.log('')\n logger.log('This is the license policy for your organization:')\n logger.log('')\n const rules = data.license_policy!\n const entries = rules ? Object.entries(rules) : []\n const mapped: Array<[string, string]> = entries.map(\n ([key, value]) => [key, value.allowed ? ' yes' : ' no'] as const\n )\n mapped.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n logger.log(mdTableOfPairs(mapped, ['License Name', 'Allowed']))\n logger.log('')\n}\n","import { fetchLicensePolicy } from './fetch-license-policy'\nimport { outputLicensePolicy } from './output-license-policy'\n\nexport async function handleLicensePolicy(\n orgSlug: string,\n outputKind: 'text' | 'json' | 'markdown'\n): Promise<void> {\n const data = await fetchLicensePolicy(orgSlug)\n if (!data) {\n return\n }\n\n await outputLicensePolicy(data, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleLicensePolicy } from './handle-license-policy'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\n// TODO: secret toplevel alias `socket license policy`?\nconst config: CliCommandConfig = {\n commandName: 'license',\n description: 'Retrieve the license policy of an organization',\n hidden: true,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, _config) => `\n Usage\n $ ${command} <org slug>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: license-policy:read\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Your API token will need the \\`license-policy:read\\` permission otherwise\n the request will fail with an authentication error.\n\n Examples\n $ ${command} mycorp\n $ ${command} mycorp --json\n `\n}\n\nexport const cmdOrganizationPolicyLicense = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const json = Boolean(cli.flags['json'])\n const markdown = Boolean(cli.flags['markdown'])\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !!orgSlug,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleLicensePolicy(\n orgSlug,\n json ? 'json' : markdown ? 'markdown' : 'text'\n )\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchSecurityPolicy(\n orgSlug: string\n): Promise<SocketSdkReturnType<'getOrgSecurityPolicy'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching organization security policy...')\n\n const result = await handleApiCall(\n sockSdk.getOrgSecurityPolicy(orgSlug),\n 'looking up organization quota'\n )\n\n spinner.successAndStop('Received organization security policy response.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getOrgSecurityPolicy', result)\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { mdTableOfPairs } from '../../utils/markdown'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputSecurityPolicy(\n data: SocketSdkReturnType<'getOrgSecurityPolicy'>['data'],\n outputKind: 'text' | 'json' | 'markdown'\n): Promise<void> {\n if (outputKind === 'json') {\n let json\n try {\n json = JSON.stringify(data, null, 2)\n } catch {\n console.error(\n 'Failed to convert the server response to json, try running the same command without --json'\n )\n return\n }\n\n logger.log(json)\n logger.log('')\n return\n }\n\n logger.log('# Security policy')\n logger.log('')\n logger.log(\n `The default security policy setting is: \"${data.securityPolicyDefault}\"`\n )\n logger.log('')\n logger.log(\n 'These are the security policies per setting for your organization:'\n )\n logger.log('')\n const rules = data.securityPolicyRules\n const entries: Array<\n [string, { action: 'defer' | 'error' | 'warn' | 'monitor' | 'ignore' }]\n > = rules ? Object.entries(rules) : []\n const mapped: Array<[string, string]> = entries.map(([key, value]) => [\n key,\n value.action\n ])\n mapped.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n logger.log(mdTableOfPairs(mapped, ['name', 'action']))\n logger.log('')\n}\n","import { fetchSecurityPolicy } from './fetch-security-policy'\nimport { outputSecurityPolicy } from './output-security-policy'\n\nexport async function handleSecurityPolicy(\n orgSlug: string,\n outputKind: 'text' | 'json' | 'markdown'\n): Promise<void> {\n const data = await fetchSecurityPolicy(orgSlug)\n if (!data) {\n return\n }\n\n await outputSecurityPolicy(data, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleSecurityPolicy } from './handle-security-policy'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\n// TODO: secret toplevel alias `socket security policy`?\nconst config: CliCommandConfig = {\n commandName: 'security',\n description: 'Retrieve the security policy of an organization',\n hidden: true,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, _config) => `\n Usage\n $ ${command} <org slug>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: security-policy:read\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Your API token will need the \\`security-policy:read\\` permission otherwise\n the request will fail with an authentication error.\n\n Examples\n $ ${command} mycorp\n $ ${command} mycorp --json\n `\n}\n\nexport const cmdOrganizationPolicyPolicy = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const json = Boolean(cli.flags['json'])\n const markdown = Boolean(cli.flags['markdown'])\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !!orgSlug,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleSecurityPolicy(\n orgSlug,\n json ? 'json' : markdown ? 'markdown' : 'text'\n )\n}\n","import { cmdOrganizationPolicyLicense } from './cmd-organization-policy-license'\nimport { cmdOrganizationPolicyPolicy } from './cmd-organization-policy-security'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\n\nimport type { CliSubcommand } from '../../utils/meow-with-subcommands'\n\nconst description = 'Organization policy details'\n\nexport const cmdOrganizationPolicy: CliSubcommand = {\n description,\n // Hidden because it was broken all this time (nobody could be using it)\n // and we're not sure if it's useful to anyone in its current state.\n // Until we do, we'll hide this to keep the help tidier.\n // And later, we may simply move this under `scan`, anyways.\n hidden: true,\n async run(argv, importMeta, { parentName }) {\n await meowWithSubcommands(\n {\n security: cmdOrganizationPolicyPolicy,\n license: cmdOrganizationPolicyLicense\n },\n {\n argv,\n description,\n defaultSub: 'list', // Backwards compat\n importMeta,\n name: parentName + ' policy'\n }\n )\n }\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchQuota(): Promise<\n SocketSdkReturnType<'getQuota'>['data'] | undefined\n> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching organization quota...')\n\n const result = await handleApiCall(\n sockSdk.getQuota(),\n 'looking up organization quota'\n )\n\n spinner.successAndStop('Received organization quota response.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getQuota', result)\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputQuota(\n data: SocketSdkReturnType<'getQuota'>['data'],\n outputKind: 'text' | 'json' | 'markdown' = 'text'\n): Promise<void> {\n if (outputKind === 'json') {\n let json\n try {\n json = JSON.stringify(data, null, 2)\n } catch {\n console.error(\n 'Failed to convert the server response to json, try running the same command without --json'\n )\n return\n }\n\n logger.log(json)\n logger.log('')\n return\n }\n\n if (outputKind === 'markdown') {\n logger.log('# Quota')\n logger.log('')\n logger.log(`Quota left on the current API token: ${data.quota}`)\n logger.log('')\n return\n }\n\n logger.log(`Quota left on the current API token: ${data.quota}`)\n logger.log('')\n}\n","import { fetchQuota } from './fetch-quota'\nimport { outputQuota } from './output-quota'\n\nexport async function handleQuota(\n outputKind: 'text' | 'json' | 'markdown' = 'text'\n): Promise<void> {\n const data = await fetchQuota()\n if (!data) {\n return\n }\n\n await outputQuota(data, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleQuota } from './handle-quota'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'quota',\n description: 'List organizations associated with the API key used',\n hidden: true,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, _config) => `\n Usage\n $ ${command}\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n `\n}\n\nexport const cmdOrganizationQuota = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const json = Boolean(cli.flags['json'])\n const markdown = Boolean(cli.flags['markdown'])\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleQuota(json ? 'json' : markdown ? 'markdown' : 'text')\n}\n","import { cmdOrganizationList } from './cmd-organization-list'\nimport { cmdOrganizationPolicy } from './cmd-organization-policy'\nimport { cmdOrganizationQuota } from './cmd-organization-quota'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\n\nimport type { CliSubcommand } from '../../utils/meow-with-subcommands'\n\nconst description = 'Account details'\n\nexport const cmdOrganization: CliSubcommand = {\n description,\n // Hidden because it was broken all this time (nobody could be using it)\n // and we're not sure if it's useful to anyone in its current state.\n // Until we do, we'll hide this to keep the help tidier.\n // And later, we may simply move this under `scan`, anyways.\n hidden: true,\n async run(argv, importMeta, { parentName }) {\n await meowWithSubcommands(\n {\n list: cmdOrganizationList,\n quota: cmdOrganizationQuota,\n policy: cmdOrganizationPolicy\n },\n {\n argv,\n description,\n defaultSub: 'list', // Backwards compat\n importMeta,\n name: parentName + ' organization'\n }\n )\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { handleApiCall, handleApiError, queryApi } from '../../utils/api'\nimport { AuthError } from '../../utils/errors'\nimport { failMsgWithBadge } from '../../utils/fail-msg-with-badge'\nimport { getDefaultToken } from '../../utils/sdk'\n\nconst { SOCKET_CLI_ISSUES_URL } = constants\n\nexport async function fetchPurlDeepScore(purl: string) {\n logger.info(`Requesting deep score data for this purl: ${purl}`)\n\n const apiToken = getDefaultToken()\n if (!apiToken) {\n throw new AuthError(\n 'User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.'\n )\n }\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Getting deep package score...')\n\n let result\n try {\n result = await queryApi(`purl/score/${encodeURIComponent(purl)}`, apiToken)\n spinner.successAndStop('Received deep package score response.')\n } catch (e) {\n spinner.failAndStop('The request was unsuccessful.')\n const msg = (e as undefined | { message: string })?.message\n if (msg) {\n logger.fail(msg)\n logger.log(\n 'Please report this if the error persists or use the cli version that includes error reporting to automate that'\n )\n } else {\n logger.log(\n 'An error happened but no reason was given. If this persists please let us know about it and what you were trying to achieve. Thank you.'\n )\n }\n return\n }\n\n if (!result.ok) {\n const err = await handleApiError(result.status)\n logger.fail(failMsgWithBadge(result.statusText, err))\n process.exitCode = 1\n return\n }\n\n const data = await handleApiCall(await result.text(), 'Reading text')\n\n try {\n return JSON.parse(data)\n } catch (e) {\n throw new Error(\n `Unable to parse JSON response from the Socket API.\\nPlease report to ${SOCKET_CLI_ISSUES_URL}`\n )\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { mdTable } from '../../utils/markdown'\n\nexport async function outputPurlScore(\n purl: string,\n data: unknown,\n outputKind: 'json' | 'markdown' | 'text'\n) {\n if (outputKind === 'json') {\n let json\n try {\n json = JSON.stringify(data, null, 2)\n } catch {\n console.error(\n 'Failed to convert the server response to JSON... Please try again or reach out to customer support.'\n )\n process.exitCode = 1\n return\n }\n\n logger.error(`Score report for \"${purl}\":\\n`)\n logger.log(json)\n logger.log('')\n return\n }\n\n if (outputKind === 'markdown') {\n const {\n purl: requestedPurl,\n self: {\n alerts: selfAlerts,\n capabilities: selfCaps,\n purl,\n score: selfScore\n },\n transitively: {\n alerts,\n capabilities,\n dependencyCount,\n func,\n lowest,\n score\n }\n } = data as {\n purl: string\n self: {\n purl: string\n score: {\n license: number\n maintenance: number\n overall: number\n quality: number\n supplyChain: number\n vulnerability: number\n }\n capabilities: string[]\n alerts: Array<{\n name: string\n severity: string\n category: string\n example: string\n }>\n }\n transitively: {\n dependencyCount: number\n func: string\n score: {\n license: number\n maintenance: number\n overall: number\n quality: number\n supplyChain: number\n vulnerability: number\n }\n lowest: {\n license: string\n maintenance: string\n overall: string\n quality: string\n supplyChain: string\n vulnerability: string\n }\n capabilities: string[]\n alerts: Array<{\n name: string\n severity: string\n category: string\n example: string\n }>\n }\n }\n\n logger.error(`Score report for \"${requestedPurl}\" (\"${purl}\"):\\n`)\n logger.log('# Complete Package Score')\n logger.log('')\n if (dependencyCount) {\n logger.log(\n `This is a Socket report for the package *\"${purl}\"* and its *${dependencyCount}* direct/transitive dependencies.`\n )\n } else {\n logger.log(\n `This is a Socket report for the package *\"${purl}\"*. It has *no dependencies*.`\n )\n }\n logger.log('')\n if (dependencyCount) {\n logger.log(\n `It will show you the shallow score for just the package itself and a deep score for all the transitives combined. Additionally you can see which capabilities were found and the top alerts as well as a package that was responsible for it.`\n )\n } else {\n logger.log(\n `It will show you the shallow score for the package itself, which capabilities were found, and its top alerts.`\n )\n logger.log('')\n logger.log(\n 'Since it has no dependencies, the shallow score is also the deep score.'\n )\n }\n logger.log('')\n if (dependencyCount) {\n // This doesn't make much sense if there are no dependencies. Better to omit it.\n logger.log(\n 'The report should give you a good insight into the status of this package.'\n )\n logger.log('')\n logger.log('## Package itself')\n logger.log('')\n logger.log(\n 'Here are results for the package itself (excluding data from dependencies).'\n )\n } else {\n logger.log('## Report')\n logger.log('')\n logger.log(\n 'The report should give you a good insight into the status of this package.'\n )\n }\n logger.log('')\n logger.log('### Shallow Score')\n logger.log('')\n logger.log('This score is just for the package itself:')\n logger.log('')\n logger.log('- Overall: ' + selfScore.overall)\n logger.log('- Maintenance: ' + selfScore.maintenance)\n logger.log('- Quality: ' + selfScore.quality)\n logger.log('- Supply Chain: ' + selfScore.supplyChain)\n logger.log('- Vulnerability: ' + selfScore.vulnerability)\n logger.log('- License: ' + selfScore.license)\n logger.log('')\n logger.log('### Capabilities')\n logger.log('')\n if (selfCaps.length) {\n logger.log('These are the capabilities detected in the package itself:')\n logger.log('')\n selfCaps.forEach(cap => {\n logger.log(`- ${cap}`)\n })\n } else {\n logger.log('No capabilities were found in the package.')\n }\n logger.log('')\n logger.log('### Alerts for this package')\n logger.log('')\n if (selfAlerts.length) {\n if (dependencyCount) {\n logger.log('These are the alerts found for the package itself:')\n } else {\n logger.log('These are the alerts found for this package:')\n }\n logger.log('')\n logger.log(\n mdTable(selfAlerts, ['severity', 'name'], ['Severity', 'Alert Name'])\n )\n } else {\n logger.log('There are currently no alerts for this package.')\n }\n logger.log('')\n if (dependencyCount) {\n logger.log('## Transitive Package Results')\n logger.log('')\n logger.log(\n 'Here are results for the package and its direct/transitive dependencies.'\n )\n logger.log('')\n logger.log('### Deep Score')\n logger.log('')\n logger.log(\n 'This score represents the package and and its direct/transitive dependencies:'\n )\n logger.log(\n `The function used to calculate the values in aggregate is: *\"${func}\"*`\n )\n logger.log('')\n logger.log('- Overall: ' + score.overall)\n logger.log('- Maintenance: ' + score.maintenance)\n logger.log('- Quality: ' + score.quality)\n logger.log('- Supply Chain: ' + score.supplyChain)\n logger.log('- Vulnerability: ' + score.vulnerability)\n logger.log('- License: ' + score.license)\n logger.log('')\n logger.log('### Capabilities')\n logger.log('')\n logger.log(\n 'These are the packages with the lowest recorded score. If there is more than one with the lowest score, just one is shown here. This may help you figure out the source of low scores.'\n )\n logger.log('')\n logger.log('- Overall: ' + lowest.overall)\n logger.log('- Maintenance: ' + lowest.maintenance)\n logger.log('- Quality: ' + lowest.quality)\n logger.log('- Supply Chain: ' + lowest.supplyChain)\n logger.log('- Vulnerability: ' + lowest.vulnerability)\n logger.log('- License: ' + lowest.license)\n logger.log('')\n logger.log('### Capabilities')\n logger.log('')\n if (capabilities.length) {\n logger.log(\n 'These are the capabilities detected in at least one package:'\n )\n logger.log('')\n capabilities.forEach(cap => {\n logger.log(`- ${cap}`)\n })\n } else {\n logger.log(\n 'This package had no capabilities and neither did any of its direct/transitive dependencies.'\n )\n }\n logger.log('')\n logger.log('### Alerts')\n logger.log('')\n if (alerts.length) {\n logger.log('These are the alerts found:')\n logger.log('')\n\n logger.log(\n mdTable(\n alerts,\n ['severity', 'name', 'example'],\n ['Severity', 'Alert Name', 'Example package reporting it']\n )\n )\n } else {\n logger.log(\n 'This package had no alerts and neither did any of its direct/transitive dependencies'\n )\n }\n logger.log('')\n }\n return\n }\n\n logger.log(\n `Score report for \"${purl}\" (use --json for raw and --markdown for formatted reports):`\n )\n logger.log(data)\n logger.log('')\n}\n","import { fetchPurlDeepScore } from './fetch-purl-deep-score'\nimport { outputPurlScore } from './output-purl-score'\n\nexport async function handlePurlDeepScore(\n purl: string,\n outputKind: 'json' | 'markdown' | 'text'\n) {\n const data = await fetchPurlDeepScore(purl)\n if (!data) {\n return\n }\n\n await outputPurlScore(purl, data, outputKind)\n}\n","// Either an ecosystem was given or all args must be (namespaced) purls\n// The `pkg:` part is optional here. We'll scan for `eco/name@version`.\n// Not hardcoding the namespace since we don't know what the server accepts.\n// The ecosystem is considered as the first package if it is not an a-z string.\nexport function parsePackageSpecifiers(\n ecosystem: string,\n pkgs: string[]\n): { purls: string[]; valid: boolean } {\n let valid = true\n const purls = []\n if (!ecosystem) {\n valid = false\n } else if (/^[a-zA-Z]+$/.test(ecosystem)) {\n for (let i = 0; i < pkgs.length; ++i) {\n const pkg = pkgs[i] ?? ''\n if (!pkg) {\n valid = false\n break\n } else if (pkg.startsWith('pkg:')) {\n // keep\n purls.push(pkg)\n } else {\n purls.push('pkg:' + ecosystem + '/' + pkg)\n }\n }\n if (!purls.length) {\n valid = false\n }\n } else {\n // Assume ecosystem is a purl, too\n pkgs.unshift(ecosystem)\n\n for (let i = 0; i < pkgs.length; ++i) {\n const pkg = pkgs[i] ?? ''\n if (!/^(?:pkg:)?[a-zA-Z]+\\/./.test(pkg)) {\n // At least one purl did not start with `pkg:eco/x` or `eco/x`\n valid = false\n break\n } else if (pkg.startsWith('pkg:')) {\n purls.push(pkg)\n } else {\n purls.push('pkg:' + pkg)\n }\n }\n\n if (!purls.length) {\n valid = false\n }\n }\n\n return { purls, valid }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handlePurlDeepScore } from './handle-purl-deep-score'\nimport { parsePackageSpecifiers } from './parse-package-specifiers'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'score',\n description:\n '[beta] Look up score for one package which reflects all of its transitive dependencies as well',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <<ecosystem> <name> | <purl>>\n\n API Token Requirements\n - Quota: 100 units\n - Permissions: packages:list\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Show deep scoring details for one package. The score will reflect the package\n itself, any of its dependencies, and any of its transitive dependencies.\n\n When you want to know whether to trust a package, this is the command to run.\n\n See also the \\`socket package shallow\\` command, which returns the shallow\n score for any number of packages. That will not reflect the dependency scores.\n\n Only a few ecosystems are supported like npm, golang, and maven.\n\n A \"purl\" is a standard package name formatting: \\`pkg:eco/name@version\\`\n This command will automatically prepend \"pkg:\" when not present.\n\n The version is optional but when given should be a direct match.\n\n Examples\n $ ${command} npm babel-cli\n $ ${command} npm babel-cli@1.9.1\n $ ${command} npm/babel-cli@1.9.1\n $ ${command} pkg:npm/babel-cli@1.9.1\n `\n}\n\nexport const cmdPackageScore = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const [ecosystem = '', purl] = cli.input\n const apiToken = getDefaultToken()\n\n const { purls, valid } = parsePackageSpecifiers(ecosystem, purl ? [purl] : [])\n\n const wasBadInput = handleBadInput(\n {\n test: valid,\n message: 'First parameter must be an ecosystem or the whole purl',\n pass: 'ok',\n fail: 'bad'\n },\n {\n test: purls.length === 1,\n message: 'Expecting at least one package',\n pass: 'ok',\n fail: purls.length === 0 ? 'missing' : 'too many'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handlePurlDeepScore(\n purls[0] || '',\n json ? 'json' : markdown ? 'markdown' : 'text'\n )\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { getPublicToken, setupSdk } from '../../utils/sdk'\n\nimport type {\n SocketSdkResultType,\n SocketSdkReturnType\n} from '@socketsecurity/sdk'\n\nexport async function fetchPurlsShallowScore(\n purls: string[]\n): Promise<SocketSdkReturnType<'batchPackageFetch'> | undefined> {\n logger.info(\n `Requesting shallow score data for ${purls.length} package urls (purl): ${purls.join(', ')}`\n )\n\n const sockSdk = await setupSdk(getPublicToken())\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start(`Requesting data ...`)\n\n const result: Awaited<SocketSdkResultType<'batchPackageFetch'>> =\n await handleApiCall(\n sockSdk.batchPackageFetch(\n {\n alerts: 'true'\n },\n { components: purls.map(purl => ({ purl })) }\n ),\n 'looking up package'\n )\n\n spinner.successAndStop('Request completed')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('batchPackageFetch', result)\n }\n\n return result\n}\n","import { codeBlock } from 'common-tags'\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { components } from '@socketsecurity/sdk/types/api'\n\nexport function outputPurlsShallowScore(\n purls: string[],\n packageData: Array<components['schemas']['SocketArtifact']>,\n outputKind: 'json' | 'markdown' | 'text'\n): void {\n if (outputKind === 'json') {\n // In JSON simply return what the server responds with. Don't bother trying\n // to match the response with the requested packages/purls.\n logger.log(JSON.stringify(packageData, undefined, 2))\n return\n }\n\n // Make some effort to match the requested data with the response\n\n const set = new Set()\n packageData.forEach(data => {\n set.add('pkg:' + data.type + '/' + data.name + '@' + data.version)\n set.add('pkg:' + data.type + '/' + data.name)\n })\n const missing = purls.filter(purl => {\n if (set.has(purl)) {\n return false\n }\n if (purl.endsWith('@latest') && set.has(purl.slice(0, -'@latest'.length))) {\n return false\n }\n return true // not found\n })\n\n if (outputKind === 'markdown') {\n logger.log(codeBlock`\n # Shallow Package Report\n\n This report contains the response for requesting data on some package url(s).\n\n Please note: The listed scores are ONLY for the package itself. It does NOT\n reflect the scores of any dependencies, transitive or otherwise.\n\n ${missing.length ? `\\n## Missing response\\n\\nAt least one package had no response or the purl was not canonical:\\n\\n${missing.map(purl => '- ' + purl + '\\n').join('')}` : ''}\n\n ${packageData.map(data => '## ' + formatReportCard(data, false)).join('\\n\\n\\n')}\n `)\n return\n }\n\n logger.log('\\n' + colors.bold('Shallow Package Score') + '\\n')\n logger.log(\n 'Please note: The listed scores are ONLY for the package itself. It does NOT\\n' +\n ' reflect the scores of any dependencies, transitive or otherwise.'\n )\n\n if (missing.length) {\n logger.log(\n `\\nAt least one package had no response or the purl was not canonical:\\n${missing.map(purl => '\\n- ' + colors.bold(purl)).join('')}`\n )\n }\n\n packageData.forEach(data => {\n logger.log('\\n')\n logger.log(formatReportCard(data, true))\n })\n logger.log('')\n}\n\nfunction formatReportCard(\n data: components['schemas']['SocketArtifact'],\n color: boolean\n): string {\n const scoreResult = {\n 'Supply Chain Risk': Math.floor((data.score?.supplyChain ?? 0) * 100),\n Maintenance: Math.floor((data.score?.maintenance ?? 0) * 100),\n Quality: Math.floor((data.score?.quality ?? 0) * 100),\n Vulnerabilities: Math.floor((data.score?.vulnerability ?? 0) * 100),\n License: Math.floor((data.score?.license ?? 0) * 100)\n }\n const alertString = getAlertString(data.alerts, !color)\n const purl = 'pkg:' + data.type + '/' + data.name + '@' + data.version\n\n return [\n 'Package: ' + (color ? colors.bold(purl) : purl),\n '',\n ...Object.entries(scoreResult).map(\n score =>\n `- ${score[0]}:`.padEnd(20, ' ') +\n ` ${formatScore(score[1], !color, true)}`\n ),\n alertString\n ].join('\\n')\n}\n\nfunction formatScore(score: number, noColor = false, pad = false): string {\n const padded = String(score).padStart(pad ? 3 : 0, ' ')\n if (noColor) {\n return padded\n }\n if (score >= 80) {\n return colors.green(padded)\n }\n if (score >= 60) {\n return colors.yellow(padded)\n }\n return colors.red(padded)\n}\n\nfunction getAlertString(\n alerts: Array<components['schemas']['SocketAlert']> | undefined,\n noColor = false\n) {\n if (!alerts?.length) {\n return noColor ? `- Alerts: none!` : `- Alerts: ${colors.green('none')}!`\n }\n const bad = alerts\n .filter(alert => alert.severity !== 'low' && alert.severity !== 'middle')\n .sort((a, b) => (a.type < b.type ? -1 : a.type > b.type ? 1 : 0))\n const mid = alerts\n .filter(alert => alert.severity === 'middle')\n .sort((a, b) => (a.type < b.type ? -1 : a.type > b.type ? 1 : 0))\n const low = alerts\n .filter(alert => alert.severity === 'low')\n .sort((a, b) => (a.type < b.type ? -1 : a.type > b.type ? 1 : 0))\n\n // We need to create the no-color string regardless because the actual string\n // contains a bunch of invisible ANSI chars which would screw up length checks.\n const colorless = `- Alerts (${bad.length}/${mid.length.toString()}/${low.length}):`\n\n if (noColor) {\n return (\n colorless +\n ' '.repeat(Math.max(0, 20 - colorless.length)) +\n ' ' +\n [\n bad.map(alert => `[${alert.severity}] ` + alert.type).join(', '),\n mid.map(alert => `[${alert.severity}] ` + alert.type).join(', '),\n low.map(alert => `[${alert.severity}] ` + alert.type).join(', ')\n ]\n .filter(Boolean)\n .join(', ')\n )\n }\n return (\n `- Alerts (${colors.red(bad.length.toString())}/${colors.yellow(mid.length.toString())}/${low.length}):` +\n ' '.repeat(Math.max(0, 20 - colorless.length)) +\n ' ' +\n [\n bad\n .map(alert =>\n colors.red(colors.dim(`[${alert.severity}] `) + alert.type)\n )\n .join(', '),\n mid\n .map(alert =>\n colors.yellow(colors.dim(`[${alert.severity}] `) + alert.type)\n )\n .join(', '),\n low\n .map(alert => colors.dim(`[${alert.severity}] `) + alert.type)\n .join(', ')\n ]\n .filter(Boolean)\n .join(', ')\n )\n}\n","import { fetchPurlsShallowScore } from './fetch-purls-shallow-score'\nimport { outputPurlsShallowScore } from './output-purls-shallow-score'\n\nimport type { components } from '@socketsecurity/sdk/types/api'\n\nexport async function handlePurlsShallowScore({\n outputKind,\n purls\n}: {\n outputKind: 'json' | 'markdown' | 'text'\n purls: string[]\n}) {\n const packageData = await fetchPurlsShallowScore(purls)\n if (!packageData) {\n return\n }\n\n outputPurlsShallowScore(\n purls,\n packageData.data as Array<components['schemas']['SocketArtifact']>,\n outputKind\n )\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handlePurlsShallowScore } from './handle-purls-shallow-score'\nimport { parsePackageSpecifiers } from './parse-package-specifiers'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'shallow',\n description:\n '[beta] Look up info regarding one or more packages but not their transitives',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <<ecosystem> <name> [<name> ...] | <purl> [<purl> ...]>\n\n API Token Requirements\n - Quota: 100 units\n - Permissions: packages:list\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Show scoring details for one or more packages purely based on their own package.\n This means that any dependency scores are not reflected by the score. You can\n use the \\`socket package score <pkg>\\` command to get its full transitive score.\n\n Only a few ecosystems are supported like npm, golang, and maven.\n\n A \"purl\" is a standard package name formatting: \\`pkg:eco/name@version\\`\n This command will automatically prepend \"pkg:\" when not present.\n\n If the first arg is an ecosystem, remaining args that are not a purl are\n assumed to be scoped to that ecosystem.\n\n Examples\n $ ${command} npm webtorrent\n $ ${command} npm webtorrent@1.9.1\n $ ${command} npm/webtorrent@1.9.1\n $ ${command} pkg:npm/webtorrent@1.9.1\n $ ${command} maven webtorrent babel\n $ ${command} npm/webtorrent golang/babel\n $ ${command} npm npm/webtorrent@1.0.1 babel\n `\n}\n\nexport const cmdPackageShallow = {\n description: config.description,\n hidden: config.hidden,\n alias: {\n shallowScore: {\n description: config.description,\n hidden: true,\n argv: []\n }\n },\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const [ecosystem = '', ...pkgs] = cli.input\n\n const { purls, valid } = parsePackageSpecifiers(ecosystem, pkgs)\n\n const wasBadInput = handleBadInput(\n {\n test: valid,\n message:\n 'First parameter should be an ecosystem or all args must be purls',\n pass: 'ok',\n fail: 'bad'\n },\n {\n test: purls.length > 0,\n message: 'Expecting at least one package',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handlePurlsShallowScore({\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text',\n purls\n })\n}\n","import { cmdPackageScore } from './cmd-package-score'\nimport { cmdPackageShallow } from './cmd-package-shallow'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\n\nimport type { CliSubcommand } from '../../utils/meow-with-subcommands'\n\nconst description = 'Commands relating to looking up published packages'\n\nexport const cmdPackage: CliSubcommand = {\n description,\n hidden: false,\n async run(argv, importMeta, { parentName }) {\n await meowWithSubcommands(\n {\n score: cmdPackageScore,\n shallow: cmdPackageShallow\n },\n {\n aliases: {\n deep: {\n description,\n hidden: true,\n argv: ['score']\n }\n },\n argv,\n description,\n importMeta,\n name: parentName + ' package'\n }\n )\n }\n}\n","import process from 'node:process'\n\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport { getNpmBinPath } from '../../shadow/npm/paths'\n\nexport async function runRawNpm(\n argv: string[] | readonly string[]\n): Promise<void> {\n const spawnPromise = spawn(getNpmBinPath(), argv as string[], {\n stdio: 'inherit'\n })\n // See https://nodejs.org/api/all.html#all_child_process_event-exit.\n spawnPromise.process.on('exit', (code, signalName) => {\n if (signalName) {\n process.kill(process.pid, signalName)\n } else if (code !== null) {\n // eslint-disable-next-line n/no-process-exit\n process.exit(code)\n }\n })\n await spawnPromise\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { runRawNpm } from './run-raw-npm'\nimport constants from '../../constants'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT, NPM } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'raw-npm',\n description: `Temporarily disable the Socket ${NPM} wrapper`,\n hidden: false,\n flags: {},\n help: command => `\n Usage\n $ ${command} <command>\n\n Examples\n $ ${command} install\n `\n}\n\nexport const cmdRawNpm = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n allowUnknownFlags: true,\n argv,\n config,\n importMeta,\n parentName\n })\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await runRawNpm(argv)\n}\n","import process from 'node:process'\n\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport { getNpxBinPath } from '../../shadow/npm/paths'\n\nexport async function runRawNpx(\n argv: string[] | readonly string[]\n): Promise<void> {\n const spawnPromise = spawn(getNpxBinPath(), argv as string[], {\n stdio: 'inherit'\n })\n // See https://nodejs.org/api/all.html#all_child_process_event-exit.\n spawnPromise.process.on('exit', (code, signalName) => {\n if (signalName) {\n process.kill(process.pid, signalName)\n } else if (code !== null) {\n // eslint-disable-next-line n/no-process-exit\n process.exit(code)\n }\n })\n await spawnPromise\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { runRawNpx } from './run-raw-npx'\nimport constants from '../../constants'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT, NPX } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'raw-npx',\n description: `Temporarily disable the Socket ${NPX} wrapper`,\n hidden: false,\n flags: {},\n help: command => `\n Usage\n $ ${command} <command>\n\n Examples\n $ ${command} install\n `\n}\n\nexport const cmdRawNpx = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n allowUnknownFlags: true,\n argv,\n config,\n importMeta,\n parentName\n })\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await runRawNpx(argv)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { commonFlags, outputFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst config: CliCommandConfig = {\n commandName: 'create',\n description: '[Deprecated] Create a project report',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: () => `\n This command is deprecated in favor of \\`socket scan view\\`.\n It will be removed in the next major release of the CLI.\n `\n}\n\nexport const cmdReportCreate = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n logger.fail(\n 'This command has been sunset. Instead, please look at `socket scan create` to create scans and `socket scan report` to view a report of your scans.'\n )\n\n process.exitCode = 1\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { commonFlags, outputFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst config: CliCommandConfig = {\n commandName: 'view',\n description: '[Deprecated] View a project report',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: () => `\n This command is deprecated in favor of \\`socket scan view\\`.\n It will be removed in the next major release of the CLI.\n `\n}\n\nexport const cmdReportView = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n logger.fail(\n 'This command has been sunset. Instead, please look at `socket scan create` to create scans and `socket scan report` to view a report of your scans.'\n )\n\n process.exitCode = 1\n}\n","import { cmdReportCreate } from './cmd-report-create'\nimport { cmdReportView } from './cmd-report-view'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\n\nimport type { CliSubcommand } from '../../utils/meow-with-subcommands'\n\nconst description = '[Deprecated] Project report related commands'\n\nexport const cmdReport: CliSubcommand = {\n description,\n hidden: true, // Deprecated in favor of `scan`\n async run(argv, importMeta, { parentName }) {\n await meowWithSubcommands(\n {\n create: cmdReportCreate,\n view: cmdReportView\n },\n {\n argv,\n description,\n importMeta,\n name: parentName + ' report'\n }\n )\n }\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchCreateRepo({\n default_branch,\n description,\n homepage,\n orgSlug,\n repoName,\n visibility\n}: {\n orgSlug: string\n repoName: string\n description: string\n homepage: string\n default_branch: string\n visibility: string\n}): Promise<SocketSdkReturnType<'createOrgRepo'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Sending request ot create a repository...')\n\n const result = await handleApiCall(\n sockSdk.createOrgRepo(orgSlug, {\n name: repoName,\n description,\n homepage,\n default_branch,\n visibility\n }),\n 'creating repository'\n )\n\n spinner.successAndStop('Received response requesting to create a repository.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('createOrgRepo', result)\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\nexport async function outputCreateRepo(\n _data: SocketSdkReturnType<'createOrgRepo'>['data']\n): Promise<void> {\n logger.success('Repository created successfully')\n}\n","import { fetchCreateRepo } from './fetch-create-repo'\nimport { outputCreateRepo } from './output-create-repo'\n\nexport async function handleCreateRepo({\n default_branch,\n description,\n homepage,\n orgSlug,\n repoName,\n visibility\n}: {\n orgSlug: string\n repoName: string\n description: string\n homepage: string\n default_branch: string\n visibility: string\n}): Promise<void> {\n const data = await fetchCreateRepo({\n default_branch,\n description,\n homepage,\n orgSlug,\n repoName,\n visibility\n })\n if (!data) {\n return\n }\n\n await outputCreateRepo(data)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleCreateRepo } from './handle-create-repo'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'create',\n description: 'Create a repository in an organization',\n hidden: false,\n flags: {\n ...commonFlags,\n repoName: {\n type: 'string',\n shortFlag: 'n',\n default: '',\n description: 'Repository name'\n },\n repoDescription: {\n type: 'string',\n shortFlag: 'd',\n default: '',\n description: 'Repository description'\n },\n homepage: {\n type: 'string',\n shortFlag: 'h',\n default: '',\n description: 'Repository url'\n },\n defaultBranch: {\n type: 'string',\n shortFlag: 'b',\n default: 'main',\n description: 'Repository default branch'\n },\n visibility: {\n type: 'string',\n shortFlag: 'v',\n default: 'private',\n description: 'Repository visibility (Default Private)'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> --repo-name=<name>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: repo:create\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg --repoName=test-repo\n `\n}\n\nexport const cmdReposCreate = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const repoName = cli.flags['repoName']\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !!orgSlug,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n test: !!repoName,\n message: 'Repository name using --repoNam',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleCreateRepo({\n orgSlug,\n repoName: String(repoName),\n description: String(cli.flags['repoDescription'] || ''),\n homepage: String(cli.flags['homepage'] || ''),\n default_branch: String(cli.flags['defaultBranch'] || ''),\n visibility: String(cli.flags['visibility'] || 'private')\n })\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nexport async function handleDeleteRepo(\n orgSlug: string,\n repoName: string\n): Promise<void> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Deleting repository...')\n\n const result = await handleApiCall(\n sockSdk.deleteOrgRepo(orgSlug, repoName),\n 'deleting repository'\n )\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('deleteOrgRepo', result)\n }\n\n spinner.successAndStop('Repository deleted successfully')\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleDeleteRepo } from './handle-delete-repo'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'del',\n description: 'Delete a repository in an organization',\n hidden: false,\n flags: {\n ...commonFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> <repo slug>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: repo:delete\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg test-repo\n `\n}\n\nexport const cmdReposDel = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const repoName = (defaultOrgSlug ? cli.input[0] : cli.input[1]) || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !!orgSlug,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n test: !!repoName,\n message: 'Repository name argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleDeleteRepo(orgSlug, repoName)\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchListRepos({\n direction,\n orgSlug,\n page,\n per_page,\n sort\n}: {\n direction: string\n orgSlug: string\n page: number\n per_page: number\n sort: string\n}): Promise<SocketSdkReturnType<'getOrgRepoList'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching list of repositories...')\n\n const result = await handleApiCall(\n sockSdk.getOrgRepoList(orgSlug, {\n sort,\n direction,\n per_page: String(per_page),\n page: String(page)\n }),\n 'listing repositories'\n )\n\n spinner.successAndStop('Received response for repository list.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getOrgRepoList', result)\n }\n\n return result.data\n}\n","// @ts-ignore\nimport chalkTable from 'chalk-table'\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputListRepos(\n data: SocketSdkReturnType<'getOrgRepoList'>['data'],\n outputKind: 'json' | 'markdown' | 'print'\n): Promise<void> {\n if (outputKind === 'json') {\n const json = data.results.map(o => ({\n id: o.id,\n name: o.name,\n visibility: o.visibility,\n defaultBranch: o.default_branch,\n archived: o.archived\n }))\n logger.log(JSON.stringify(json, null, 2))\n return\n }\n\n const options = {\n columns: [\n { field: 'id', name: colors.magenta('ID') },\n { field: 'name', name: colors.magenta('Name') },\n { field: 'visibility', name: colors.magenta('Visibility') },\n { field: 'default_branch', name: colors.magenta('Default branch') },\n { field: 'archived', name: colors.magenta('Archived') }\n ]\n }\n\n logger.log(chalkTable(options, data.results))\n}\n","import { fetchListRepos } from './fetch-list-repos'\nimport { outputListRepos } from './output-list-repos'\n\nexport async function handleListRepos({\n direction,\n orgSlug,\n outputKind,\n page,\n per_page,\n sort\n}: {\n direction: string\n orgSlug: string\n outputKind: 'json' | 'markdown' | 'print'\n page: number\n per_page: number\n sort: string\n}): Promise<void> {\n const data = await fetchListRepos({\n direction,\n orgSlug,\n page,\n per_page,\n sort\n })\n if (!data) {\n return\n }\n\n await outputListRepos(data, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleListRepos } from './handle-list-repos'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'list',\n description: 'List repositories in an organization',\n hidden: false,\n flags: {\n ...commonFlags,\n sort: {\n type: 'string',\n shortFlag: 's',\n default: 'created_at',\n description: 'Sorting option'\n },\n direction: {\n type: 'string',\n default: 'desc',\n description: 'Direction option'\n },\n perPage: {\n type: 'number',\n shortFlag: 'pp',\n default: 30,\n description: 'Number of results per page'\n },\n page: {\n type: 'number',\n shortFlag: 'p',\n default: 1,\n description: 'Page number'\n },\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: repo:list\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg\n `\n}\n\nexport const cmdReposList = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !!orgSlug,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleListRepos({\n direction: cli.flags['direction'] === 'asc' ? 'asc' : 'desc',\n orgSlug,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'print',\n page: Number(cli.flags['page']) || 1,\n per_page: Number(cli.flags['perPage']) || 30,\n sort: String(cli.flags['sort'] || 'created_at')\n })\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchUpdateRepo({\n default_branch,\n description,\n homepage,\n orgSlug,\n repoName,\n visibility\n}: {\n orgSlug: string\n repoName: string\n description: string\n homepage: string\n default_branch: string\n visibility: string\n}): Promise<SocketSdkReturnType<'updateOrgRepo'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Sending request to update a repository...')\n\n const result = await handleApiCall(\n sockSdk.updateOrgRepo(orgSlug, repoName, {\n orgSlug,\n name: repoName,\n description,\n homepage,\n default_branch,\n visibility\n }),\n 'updating repository'\n )\n\n spinner.successAndStop('Received response trying to update a repository')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('updateOrgRepo', result)\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputUpdateRepo(\n _data: SocketSdkReturnType<'updateOrgRepo'>['data']\n): Promise<void> {\n logger.success('Repository updated successfully')\n}\n","import { fetchUpdateRepo } from './fetch-update-repo'\nimport { outputUpdateRepo } from './output-update-repo'\n\nexport async function handleUpdateRepo({\n default_branch,\n description,\n homepage,\n orgSlug,\n repoName,\n visibility\n}: {\n orgSlug: string\n repoName: string\n description: string\n homepage: string\n default_branch: string\n visibility: string\n}): Promise<void> {\n const data = await fetchUpdateRepo({\n default_branch,\n description,\n homepage,\n orgSlug,\n repoName,\n visibility\n })\n if (!data) {\n return\n }\n\n await outputUpdateRepo(data)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleUpdateRepo } from './handle-update-repo'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'update',\n description: 'Update a repository in an organization',\n hidden: false,\n flags: {\n ...commonFlags,\n repoName: {\n type: 'string',\n shortFlag: 'n',\n default: '',\n description: 'Repository name'\n },\n repoDescription: {\n type: 'string',\n shortFlag: 'd',\n default: '',\n description: 'Repository description'\n },\n homepage: {\n type: 'string',\n shortFlag: 'h',\n default: '',\n description: 'Repository url'\n },\n defaultBranch: {\n type: 'string',\n shortFlag: 'b',\n default: 'main',\n description: 'Repository default branch'\n },\n visibility: {\n type: 'string',\n shortFlag: 'v',\n default: 'private',\n description: 'Repository visibility (Default Private)'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> --repo-name=<name>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: repo:update\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg\n `\n}\n\nexport const cmdReposUpdate = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const repoName = cli.flags['repoName']\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !!orgSlug,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n test: !!repoName,\n message: 'Repository name using --repoName',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleUpdateRepo({\n orgSlug,\n repoName: String(repoName),\n description: String(cli.flags['repoDescription'] || ''),\n homepage: String(cli.flags['homepage'] || ''),\n default_branch: String(cli.flags['defaultBranch'] || ''),\n visibility: String(cli.flags['visibility'] || 'private')\n })\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchViewRepo(\n orgSlug: string,\n repoName: string\n): Promise<SocketSdkReturnType<'getOrgRepo'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching repository data...')\n\n const result = await handleApiCall(\n sockSdk.getOrgRepo(orgSlug, repoName),\n 'fetching repository'\n )\n\n spinner.successAndStop('Received response while fetched repository data.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getOrgRepo', result)\n }\n\n return result.data\n}\n","// @ts-ignore\nimport chalkTable from 'chalk-table'\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputViewRepo(\n data: SocketSdkReturnType<'createOrgRepo'>['data'],\n outputKind: 'json' | 'markdown' | 'text'\n): Promise<void> {\n if (outputKind === 'json') {\n const {\n archived,\n created_at,\n default_branch,\n homepage,\n id,\n name,\n visibility\n } = data\n logger.log(\n JSON.stringify(\n {\n id,\n name,\n visibility,\n default_branch,\n homepage,\n archived,\n created_at\n },\n null,\n 2\n )\n )\n return\n }\n\n const options = {\n columns: [\n { field: 'id', name: colors.magenta('ID') },\n { field: 'name', name: colors.magenta('Name') },\n { field: 'visibility', name: colors.magenta('Visibility') },\n { field: 'default_branch', name: colors.magenta('Default branch') },\n { field: 'homepage', name: colors.magenta('Homepage') },\n { field: 'archived', name: colors.magenta('Archived') },\n { field: 'created_at', name: colors.magenta('Created at') }\n ]\n }\n\n logger.log(chalkTable(options, [data]))\n}\n","import { fetchViewRepo } from './fetch-view-repo'\nimport { outputViewRepo } from './output-view-repo'\n\nexport async function handleViewRepo(\n orgSlug: string,\n repoName: string,\n outputKind: 'json' | 'markdown' | 'text'\n): Promise<void> {\n const data = await fetchViewRepo(orgSlug, repoName)\n if (!data) {\n return\n }\n\n await outputViewRepo(data, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleViewRepo } from './handle-view-repo'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'view',\n description: 'View repositories in an organization',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n repoName: {\n description: 'The repository to check',\n default: '',\n type: 'string'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> --repo-name=<name>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: repo:list\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg\n `\n}\n\nexport const cmdReposView = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown, repoName } = cli.flags\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !!orgSlug,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n test: !!repoName,\n message: 'Repository name using --repoName',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleViewRepo(\n orgSlug,\n String(repoName),\n json ? 'json' : markdown ? 'markdown' : 'text'\n )\n}\n","import { cmdReposCreate } from './cmd-repos-create'\nimport { cmdReposDel } from './cmd-repos-del'\nimport { cmdReposList } from './cmd-repos-list'\nimport { cmdReposUpdate } from './cmd-repos-update'\nimport { cmdReposView } from './cmd-repos-view'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\n\nimport type { CliSubcommand } from '../../utils/meow-with-subcommands'\n\nconst description = 'Repositories related commands'\n\nexport const cmdRepos: CliSubcommand = {\n description,\n async run(argv, importMeta, { parentName }) {\n await meowWithSubcommands(\n {\n create: cmdReposCreate,\n view: cmdReposView,\n list: cmdReposList,\n del: cmdReposDel,\n update: cmdReposUpdate\n },\n {\n argv,\n description,\n importMeta,\n name: `${parentName} repos`\n }\n )\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\nimport { select } from '@socketsecurity/registry/lib/prompts'\n\nimport { handleApiCall } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nexport async function suggestOrgSlug(): Promise<string | void> {\n const sockSdk = await setupSdk()\n const result = await handleApiCall(\n sockSdk.getOrganizations(),\n 'looking up organizations'\n )\n // Ignore a failed request here. It was not the primary goal of\n // running this command and reporting it only leads to end-user confusion.\n if (result.success) {\n const proceed = await select<string>({\n message:\n 'Missing org name; do you want to use any of these orgs for this scan?',\n choices: [\n ...Object.values(result.data.organizations).map(org => {\n const slug = org.name ?? 'undefined'\n return {\n name: `Yes [${slug}]`,\n value: slug,\n description: `Use \"${slug}\" as the organization`\n }\n }),\n {\n name: 'No',\n value: '',\n description:\n 'Do not use any of these organizations (will end in a no-op)'\n }\n ]\n })\n if (proceed) {\n return proceed\n }\n } else {\n logger.fail(\n 'Failed to lookup organization list from API, unable to suggest'\n )\n }\n}\n","import { select } from '@socketsecurity/registry/lib/prompts'\n\nexport async function suggestTarget(): Promise<string[] | void> {\n // We could prefill this with sub-dirs of the current\n // dir ... but is that going to be useful?\n const proceed = await select<boolean>({\n message: 'No TARGET given. Do you want to use the current directory?',\n choices: [\n {\n name: 'Yes',\n value: true,\n description: 'Target the current directory'\n },\n {\n name: 'No',\n value: false,\n description:\n 'Do not use the current directory (this will end in a no-op)'\n }\n ]\n })\n if (proceed) {\n return ['.']\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleCreateNewScan } from './handle-create-new-scan'\nimport { suggestOrgSlug } from './suggest-org-slug'\nimport { suggestTarget } from './suggest_target'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'create',\n description: 'Create a scan',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n branch: {\n type: 'string',\n shortFlag: 'b',\n default: 'socket-default-branch',\n description: 'Branch name'\n },\n commitMessage: {\n type: 'string',\n shortFlag: 'm',\n default: '',\n description: 'Commit message'\n },\n commitHash: {\n type: 'string',\n shortFlag: 'ch',\n default: '',\n description: 'Commit hash'\n },\n committers: {\n type: 'string',\n shortFlag: 'c',\n default: '',\n description: 'Committers'\n },\n cwd: {\n type: 'string',\n description: 'working directory, defaults to process.cwd()'\n },\n defaultBranch: {\n type: 'boolean',\n default: false,\n description:\n 'Set the default branch of the repository to the branch of this full-scan. Should only need to be done once, for example for the \"main\" or \"master\" branch.'\n },\n interactive: {\n type: 'boolean',\n default: true,\n description:\n 'Allow for interactive elements, asking for input. Use --no-interactive to prevent any input questions, defaulting them to cancel/no.'\n },\n pendingHead: {\n type: 'boolean',\n default: true,\n description:\n 'Designate this full-scan as the latest scan of a given branch. This must be set to have it show up in the dashboard.'\n },\n pullRequest: {\n type: 'number',\n shortFlag: 'pr',\n description: 'Commit hash'\n },\n readOnly: {\n type: 'boolean',\n default: false,\n description:\n 'Similar to --dry-run except it can read from remote, stops before it would create an actual report'\n },\n repo: {\n type: 'string',\n shortFlag: 'r',\n default: 'socket-default-repository',\n description: 'Repository name'\n },\n report: {\n type: 'boolean',\n default: false,\n description:\n 'Wait for the scan creation to complete, then basically run `socket scan report` on it'\n },\n tmp: {\n type: 'boolean',\n shortFlag: 't',\n default: false,\n description:\n 'Set the visibility (true/false) of the scan in your dashboard. Can not be used when --pendingHead is set.'\n }\n },\n // TODO: your project's \"socket.yml\" file's \"projectIgnorePaths\"\n help: (command, config) => `\n Usage\n $ ${command} [...options] <org> <TARGET> [TARGET...]\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: full-scans:create\n\n Uploads the specified \"package.json\" and lock files for JavaScript, Python,\n Go, Scala, Gradle, and Kotlin dependency manifests.\n If any folder is specified, the ones found in there recursively are uploaded.\n\n Supports globbing such as \"**/package.json\", \"**/requirements.txt\", etc.\n\n Ignores any file specified in your project's \".gitignore\" and also has a\n sensible set of default ignores from the \"ignore-by-default\" module.\n\n TARGET should be a FILE or DIR that _must_ be inside the CWD.\n\n When a FILE is given only that FILE is targeted. Otherwise any eligible\n files in the given DIR will be considered.\n\n The --repo and --branch flags tell Socket to associate this Scan with that\n repo/branch. The names will show up on your dashboard on the Socket website.\n\n Note: for a first run you probably want to set --defaultBranch to indicate\n the default branch name, like \"main\" or \"master\".\n\n Note: --pendingHead is enabled by default and makes a scan show up in your\n dashboard. You can use \\`--no-pendingHead\\` to have it not show up.\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} --repo=test-repo --branch=main FakeOrg ./package.json\n `\n}\n\nexport const cmdScanCreate = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const {\n branch: branchName = 'socket-default-branch',\n commitHash,\n commitMessage,\n committers,\n cwd: cwdOverride,\n defaultBranch,\n dryRun,\n interactive = true,\n json,\n markdown,\n pendingHead,\n pullRequest,\n readOnly,\n repo: repoName = 'socket-default-repository',\n report,\n tmp\n } = cli.flags as {\n branch: string\n cwd: string\n commitHash: string\n commitMessage: string\n committers: string\n defaultBranch: boolean\n dryRun: boolean\n interactive: boolean\n json: boolean\n markdown: boolean\n pendingHead: boolean\n pullRequest: number\n readOnly: boolean\n repo: string\n report: boolean\n tmp: boolean\n }\n const defaultOrgSlug = getConfigValue('defaultOrg')\n let orgSlug = defaultOrgSlug || cli.input[0] || ''\n let targets = cli.input.slice(defaultOrgSlug ? 0 : 1)\n\n const cwd =\n cwdOverride && cwdOverride !== 'process.cwd()'\n ? String(cwdOverride)\n : process.cwd()\n\n // We're going to need an api token to suggest data because those suggestions\n // must come from data we already know. Don't error on missing api token yet.\n // If the api-token is not set, ignore it for the sake of suggestions.\n const apiToken = getDefaultToken()\n\n // If we updated any inputs then we should print the command line to repeat\n // the command without requiring user input, as a suggestion.\n let updatedInput = false\n\n if (!targets.length && !dryRun && interactive) {\n const received = await suggestTarget()\n targets = received ?? []\n updatedInput = true\n }\n\n // If the current cwd is unknown and is used as a repo slug anyways, we will\n // first need to register the slug before we can use it.\n // Only do suggestions with an apiToken and when not in dryRun mode\n if (apiToken && !dryRun && interactive) {\n if (!orgSlug) {\n const suggestion = await suggestOrgSlug()\n if (suggestion) {\n orgSlug = suggestion\n }\n updatedInput = true\n }\n }\n\n if (updatedInput && orgSlug && targets?.length) {\n logger.error(\n 'Note: You can invoke this command next time to skip the interactive questions:'\n )\n logger.error('```')\n logger.error(\n ` socket scan create [other flags...] ${defaultOrgSlug ? '' : orgSlug} ${targets.join(' ')}`\n )\n logger.error('```\\n')\n }\n\n const wasBadInput = handleBadInput(\n {\n nook: !!defaultOrgSlug,\n test: !!orgSlug && orgSlug !== '.',\n message: 'Org name as the first argument',\n pass: 'ok',\n fail:\n orgSlug === '.'\n ? 'dot is an invalid org, most likely you forgot the org name here?'\n : 'missing'\n },\n {\n test: !!targets.length,\n message: 'At least one TARGET (e.g. `.` or `./package.json`)',\n pass: 'ok',\n fail: 'missing (or perhaps you forgot the org slug?)'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message: 'This command requires an API token for access',\n pass: 'ok',\n fail: 'missing (try `socket login`)'\n },\n {\n nook: true,\n test: !pendingHead || !tmp,\n message: 'Can not use --pendingHead and --tmp at the same time',\n pass: 'ok',\n fail: 'remove at least one flag'\n },\n {\n nook: true,\n test: !pendingHead || !!branchName,\n message: 'When --pendingHead is set, --branch is mandatory',\n pass: 'ok',\n fail: 'missing branch name'\n },\n {\n nook: true,\n test: !defaultBranch || !!branchName,\n message: 'When --defaultBranch is set, --branch is mandatory',\n pass: 'ok',\n fail: 'missing branch name'\n }\n )\n if (wasBadInput) {\n return\n }\n\n // Note exiting earlier to skirt a hidden auth requirement\n if (dryRun) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleCreateNewScan({\n branchName: branchName as string,\n commitHash: (commitHash && String(commitHash)) || '',\n commitMessage: (commitMessage && String(commitMessage)) || '',\n committers: (committers && String(committers)) || '',\n cwd,\n defaultBranch: Boolean(defaultBranch),\n interactive: Boolean(interactive),\n orgSlug,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text',\n pendingHead: Boolean(pendingHead),\n pullRequest: Number(pullRequest),\n readOnly: Boolean(readOnly),\n repoName: repoName,\n report,\n targets,\n tmp: Boolean(tmp)\n })\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchDeleteOrgFullScan(\n orgSlug: string,\n scanId: string\n): Promise<SocketSdkReturnType<'deleteOrgFullScan'>['data'] | void> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Requesting the scan to be deleted...')\n\n const result = await handleApiCall(\n sockSdk.deleteOrgFullScan(orgSlug, scanId),\n 'Deleting scan'\n )\n\n spinner.successAndStop('Received response for deleting a scan.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('deleteOrgFullScan', result)\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputDeleteScan(\n _data: SocketSdkReturnType<'deleteOrgFullScan'>['data']\n): Promise<void> {\n logger.success('Scan deleted successfully')\n}\n","import { fetchDeleteOrgFullScan } from './fetch-delete-org-full-scan'\nimport { outputDeleteScan } from './output-delete-scan'\n\nexport async function handleDeleteScan(\n orgSlug: string,\n scanId: string\n): Promise<void> {\n const data = await fetchDeleteOrgFullScan(orgSlug, scanId)\n if (!data) {\n return\n }\n\n await outputDeleteScan(data)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleDeleteScan } from './handle-delete-scan'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'del',\n description: 'Delete a scan',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> <scan ID>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: full-scans:delete\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg 000aaaa1-0000-0a0a-00a0-00a0000000a0\n `\n}\n\nexport const cmdScanDel = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const scanId = (defaultOrgSlug ? cli.input[0] : cli.input[1]) || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: !!defaultOrgSlug,\n test: !!orgSlug && orgSlug !== '.',\n message: 'Org name as the first argument',\n pass: 'ok',\n fail:\n orgSlug === '.'\n ? 'dot is an invalid org, most likely you forgot the org name here?'\n : 'missing'\n },\n {\n test: !!scanId,\n message: 'Scan ID to delete',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleDeleteScan(orgSlug, scanId)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { handleApiCall, handleApiError, queryApi } from '../../utils/api'\nimport { failMsgWithBadge } from '../../utils/fail-msg-with-badge'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchDiffScan({\n id1,\n id2,\n orgSlug\n}: {\n id1: string\n id2: string\n orgSlug: string\n}): Promise<SocketSdkReturnType<'GetOrgDiffScan'>['data'] | undefined> {\n const apiToken = getDefaultToken()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n logger.error('Scan ID 1:', id1)\n logger.error('Scan ID 2:', id2)\n\n spinner.start('Fetching scan diff... (this may take a while)')\n\n const response = await queryApi(\n `orgs/${orgSlug}/full-scans/diff?before=${encodeURIComponent(id1)}&after=${encodeURIComponent(id2)}`,\n apiToken || ''\n )\n\n spinner.successAndStop('Received scan diff response')\n\n if (!response.ok) {\n const err = await handleApiError(response.status)\n logger.fail(failMsgWithBadge(response.statusText, err))\n return\n }\n\n const result = await handleApiCall(\n (await response.json()) as Promise<\n SocketSdkReturnType<'GetOrgDiffScan'>['data']\n >,\n 'Deserializing json'\n )\n\n return result\n}\n","import fs from 'node:fs'\nimport util from 'node:util'\n\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nconst SOCKET_SBOM_URL_PREFIX =\n 'https://socket.dev/dashboard/org/SocketDev/sbom/'\n\nexport async function outputDiffScan(\n result: SocketSdkReturnType<'GetOrgDiffScan'>['data'],\n {\n depth,\n file,\n outputKind\n }: {\n depth: number\n file: string\n outputKind: 'json' | 'markdown' | 'text'\n }\n): Promise<void> {\n const dashboardUrl = result.diff_report_url\n const dashboardMessage = dashboardUrl\n ? `\\n View this diff scan in the Socket dashboard: ${colors.cyan(dashboardUrl)}`\n : ''\n\n // When forcing json, or dumping to file, serialize to string such that it\n // won't get truncated. The only way to dump the full raw JSON to stdout is\n // to use `--json --file -` (the dash is a standard notation for stdout)\n if (outputKind === 'json' || file) {\n let json\n try {\n json = JSON.stringify(result, null, 2)\n } catch (e) {\n process.exitCode = 1\n // Most likely caused by a circular reference (or OOM)\n logger.fail('There was a problem converting the data to JSON')\n logger.error(e)\n return\n }\n\n if (file && file !== '-') {\n logger.log(`Writing json to \\`${file}\\``)\n fs.writeFile(file, JSON.stringify(result, null, 2), err => {\n if (err) {\n logger.fail(`Writing to \\`${file}\\` failed...`)\n logger.error(err)\n } else {\n logger.log(`Data successfully written to \\`${file}\\``)\n }\n logger.error(dashboardMessage)\n })\n } else {\n // TODO: expose different method for writing to stderr when simply dodging stdout\n logger.error(`\\n Diff scan result: \\n`)\n logger.log(json)\n logger.error(dashboardMessage)\n }\n\n return\n }\n\n if (outputKind === 'markdown') {\n logger.log('# Scan diff result')\n logger.log('')\n logger.log('This Socket.dev report shows the changes between two scans:')\n logger.log(\n `- [${result.before.id}](${SOCKET_SBOM_URL_PREFIX}${result.before.id})`\n )\n logger.log(\n `- [${result.after.id}](${SOCKET_SBOM_URL_PREFIX}${result.after.id})`\n )\n logger.log('')\n logger.log(\n `You can [view this report in your dashboard](${result.diff_report_url})`\n )\n logger.log('')\n logger.log('## Changes')\n logger.log('')\n logger.log(\n `- directDependenciesChanged: ${result.directDependenciesChanged}`\n )\n logger.log(`- Added packages: ${result.artifacts.added.length}`)\n if (result.artifacts.added.length > 0) {\n result.artifacts.added.slice(0, 10).forEach(artifact => {\n logger.log(` - ${artifact.type} ${artifact.name}@${artifact.version}`)\n })\n if (result.artifacts.added.length > 10) {\n logger.log(` ... and ${result.artifacts.added.length - 10} more`)\n }\n }\n logger.log(`- Removed packages: ${result.artifacts.removed.length}`)\n if (result.artifacts.removed.length > 0) {\n result.artifacts.removed.slice(0, 10).forEach(artifact => {\n logger.log(` - ${artifact.type} ${artifact.name}@${artifact.version}`)\n })\n if (result.artifacts.removed.length > 10) {\n logger.log(` ... and ${result.artifacts.removed.length - 10} more`)\n }\n }\n logger.log(`- Replaced packages: ${result.artifacts.replaced.length}`)\n if (result.artifacts.replaced.length > 0) {\n result.artifacts.replaced.slice(0, 10).forEach(artifact => {\n logger.log(` - ${artifact.type} ${artifact.name}@${artifact.version}`)\n })\n if (result.artifacts.replaced.length > 10) {\n logger.log(` ... and ${result.artifacts.replaced.length - 10} more`)\n }\n }\n logger.log(`- Updated packages: ${result.artifacts.updated.length}`)\n if (result.artifacts.updated.length > 0) {\n result.artifacts.updated.slice(0, 10).forEach(artifact => {\n logger.log(` - ${artifact.type} ${artifact.name}@${artifact.version}`)\n })\n if (result.artifacts.updated.length > 10) {\n logger.log(` ... and ${result.artifacts.updated.length - 10} more`)\n }\n }\n logger.log(`- Unchanged packages: ${result.artifacts.unchanged.length}`)\n if (result.artifacts.unchanged.length > 0) {\n result.artifacts.unchanged.slice(0, 10).forEach(artifact => {\n logger.log(` - ${artifact.type} ${artifact.name}@${artifact.version}`)\n })\n if (result.artifacts.unchanged.length > 10) {\n logger.log(` ... and ${result.artifacts.unchanged.length - 10} more`)\n }\n }\n logger.log('')\n logger.log(`## Scan ${result.before.id}`)\n logger.log('')\n logger.log(\n 'This Scan was considered to be the \"base\" / \"from\" / \"before\" Scan.'\n )\n logger.log('')\n for (const [key, value] of Object.entries(result.before)) {\n if (key === 'pull_request' && !value) {\n continue\n }\n if (!['id', 'organization_id', 'repository_id'].includes(key)) {\n logger.group(\n `- ${key === 'repository_slug' ? 'repo' : key === 'organization_slug' ? 'org' : key}: ${value}`\n )\n logger.groupEnd()\n }\n }\n logger.log('')\n logger.log(`## Scan ${result.after.id}`)\n logger.log('')\n logger.log(\n 'This Scan was considered to be the \"head\" / \"to\" / \"after\" Scan.'\n )\n logger.log('')\n for (const [key, value] of Object.entries(result.after)) {\n if (key === 'pull_request' && !value) {\n continue\n }\n if (!['id', 'organization_id', 'repository_id'].includes(key)) {\n logger.group(\n `- ${key === 'repository_slug' ? 'repo' : key === 'organization_slug' ? 'org' : key}: ${value}`\n )\n logger.groupEnd()\n }\n }\n logger.log('')\n\n return\n }\n\n // In this case neither the --json nor the --file flag was passed\n // Dump the JSON to CLI and let NodeJS deal with truncation\n\n logger.log('Diff scan result:')\n logger.log(\n util.inspect(result, {\n showHidden: false,\n depth: depth > 0 ? depth : null,\n colors: true,\n maxArrayLength: null\n })\n )\n logger.error(\n `\\n 📝 To display the detailed report in the terminal, use the --json flag. For a friendlier report, use the --markdown flag.\\n`\n )\n logger.log(dashboardMessage)\n}\n","import { fetchDiffScan } from './fetch-diff-scan'\nimport { outputDiffScan } from './output-diff-scan'\n\nexport async function handleDiffScan({\n depth,\n file,\n id1,\n id2,\n orgSlug,\n outputKind\n}: {\n depth: number\n file: string\n id1: string\n id2: string\n orgSlug: string\n outputKind: 'json' | 'markdown' | 'text'\n}): Promise<void> {\n const data = await fetchDiffScan({\n id1,\n id2,\n orgSlug\n })\n if (!data) {\n return\n }\n\n await outputDiffScan(data, {\n depth,\n file,\n outputKind\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleDiffScan } from './handle-diff-scan'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst SOCKET_SBOM_URL_PREFIX =\n 'https://socket.dev/dashboard/org/SocketDev/sbom/'\n\nconst config: CliCommandConfig = {\n commandName: 'diff',\n description: 'See what changed between two Scans',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n depth: {\n type: 'number',\n default: 2,\n description:\n 'Max depth of JSON to display before truncating, use zero for no limit (without --json/--file)'\n },\n file: {\n type: 'string',\n shortFlag: 'f',\n default: '',\n description:\n 'Path to a local file where the output should be saved. Use `-` to force stdout.'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> <ID1> <ID2>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: full-scans:list\n\n This command displays the package changes between two scans. The full output\n can be pretty large depending on the size of your repo and time range. It is\n best stored to disk (with --json) to be further analyzed by other tools.\n\n Note: First Scan ID is assumed to be the older ID. This is only relevant for\n the added/removed list (similar to diffing two files with git).\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeCorp aaa0aa0a-aaaa-0000-0a0a-0000000a00a0 aaa1aa1a-aaaa-1111-1a1a-1111111a11a1\n $ ${command} FakeCorp aaa0aa0a-aaaa-0000-0a0a-0000000a00a0 aaa1aa1a-aaaa-1111-1a1a-1111111a11a1 --json\n `\n}\n\nexport const cmdScanDiff = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { depth, file, json, markdown } = cli.flags\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n\n let id1 = cli.input[defaultOrgSlug ? 0 : 1] || ''\n let id2 = cli.input[defaultOrgSlug ? 1 : 2] || ''\n if (id1.startsWith(SOCKET_SBOM_URL_PREFIX)) {\n id1 = id1.slice(SOCKET_SBOM_URL_PREFIX.length)\n }\n if (id2.startsWith(SOCKET_SBOM_URL_PREFIX)) {\n id2 = id2.slice(SOCKET_SBOM_URL_PREFIX.length)\n }\n\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n test: !!(id1 && id2),\n message:\n 'Specify two Scan IDs.\\nA Scan ID looks like `aaa0aa0a-aaaa-0000-0a0a-0000000a00a0`.',\n pass: 'ok',\n fail:\n !id1 && !id2\n ? 'missing both Scan IDs'\n : !id2\n ? 'missing second Scan ID'\n : 'missing first Scan ID' // Not sure how this can happen but ok.\n },\n {\n test: !!orgSlug,\n nook: true,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleDiffScan({\n id1: String(id1 || ''),\n id2: String(id2 || ''),\n depth: Number(depth),\n orgSlug,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text',\n file: String(file || '')\n })\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchListScans({\n branch,\n direction,\n from_time,\n orgSlug,\n page,\n per_page,\n repo,\n sort\n}: {\n branch: string\n direction: string\n from_time: string\n orgSlug: string\n page: number\n per_page: number\n repo: string\n sort: string\n}): Promise<SocketSdkReturnType<'getOrgFullScanList'>['data'] | void> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching list of scans...')\n\n const result = await handleApiCall(\n sockSdk.getOrgFullScanList(orgSlug, {\n ...(branch ? { branch } : {}),\n ...(repo ? { repo } : {}),\n sort,\n direction,\n per_page: String(per_page),\n page: String(page),\n from: from_time\n }),\n 'Listing scans'\n )\n\n spinner.successAndStop(`Received response for list of scans.`)\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getOrgFullScanList', result)\n }\n\n return result.data\n}\n","// @ts-ignore\nimport chalkTable from 'chalk-table'\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputListScans(\n data: SocketSdkReturnType<'getOrgFullScanList'>['data'],\n outputKind: 'json' | 'markdown' | 'print'\n): Promise<void> {\n if (outputKind === 'json') {\n logger.log(data)\n return\n }\n\n const options = {\n columns: [\n { field: 'id', name: colors.magenta('ID') },\n { field: 'report_url', name: colors.magenta('Scan URL') },\n { field: 'repo', name: colors.magenta('Repo') },\n { field: 'branch', name: colors.magenta('Branch') },\n { field: 'created_at', name: colors.magenta('Created at') }\n ]\n }\n\n const formattedResults = data.results.map(d => {\n return {\n id: d.id,\n report_url: colors.underline(`${d.html_report_url}`),\n created_at: d.created_at\n ? new Date(d.created_at).toLocaleDateString('en-us', {\n year: 'numeric',\n month: 'numeric',\n day: 'numeric'\n })\n : '',\n repo: d.repo,\n branch: d.branch\n }\n })\n\n logger.log(chalkTable(options, formattedResults))\n}\n","import { fetchListScans } from './fetch-list-scans'\nimport { outputListScans } from './output-list-scans'\n\nexport async function handleListScans({\n branch,\n direction,\n from_time,\n orgSlug,\n outputKind,\n page,\n per_page,\n repo,\n sort\n}: {\n branch: string\n direction: string\n from_time: string\n orgSlug: string\n outputKind: 'json' | 'markdown' | 'print'\n page: number\n per_page: number\n repo: string\n sort: string\n}): Promise<void> {\n const data = await fetchListScans({\n branch,\n direction,\n from_time,\n orgSlug,\n page,\n per_page,\n repo,\n sort\n })\n if (!data) {\n return\n }\n\n await outputListScans(data, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleListScans } from './handle-list-scans'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type {\n CliCommandConfig,\n CliSubcommand\n} from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'list',\n description: 'List the scans for an organization',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n branch: {\n type: 'string',\n description: 'Filter to show only scans with this branch name'\n },\n direction: {\n type: 'string',\n shortFlag: 'd',\n default: 'desc',\n description: 'Direction option (`desc` or `asc`) - Default is `desc`'\n },\n fromTime: {\n type: 'string',\n shortFlag: 'f',\n default: '',\n description: 'From time - as a unix timestamp'\n },\n page: {\n type: 'number',\n shortFlag: 'p',\n default: 1,\n description: 'Page number - Default is 1'\n },\n perPage: {\n type: 'number',\n shortFlag: 'pp',\n default: 30,\n description: 'Results per page - Default is 30'\n },\n repo: {\n type: 'string',\n description: 'Filter to show only scans with this repository name'\n },\n sort: {\n type: 'string',\n shortFlag: 's',\n default: 'created_at',\n description:\n 'Sorting option (`name` or `created_at`) - default is `created_at`'\n },\n untilTime: {\n type: 'string',\n shortFlag: 'u',\n default: '',\n description: 'Until time - as a unix timestamp'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: full-scans:list\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg\n `\n}\n\nexport const cmdScanList: CliSubcommand = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n) {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { branch, json, markdown, repo } = cli.flags\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: !!defaultOrgSlug,\n test: !!orgSlug && orgSlug !== '.',\n message: 'Org name as the first argument',\n pass: 'ok',\n fail:\n orgSlug === '.'\n ? 'dot is an invalid org, most likely you forgot the org name here?'\n : 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleListScans({\n branch: branch ? String(branch) : '',\n direction: String(cli.flags['direction'] || ''),\n from_time: String(cli.flags['fromTime'] || ''),\n orgSlug,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'print',\n page: Number(cli.flags['page'] || 1),\n per_page: Number(cli.flags['perPage'] || 30),\n repo: repo ? String(repo) : '',\n sort: String(cli.flags['sort'] || '')\n })\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchScanMetadata(\n orgSlug: string,\n scanId: string\n): Promise<SocketSdkReturnType<'getOrgFullScanMetadata'>['data'] | void> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching meta data for a full scan...')\n\n const result = await handleApiCall(\n sockSdk.getOrgFullScanMetadata(orgSlug, scanId),\n 'Listing scans'\n )\n\n spinner.successAndStop('Received response for scan meta data.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getOrgFullScanMetadata', result)\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputScanMetadata(\n data: SocketSdkReturnType<'getOrgFullScanMetadata'>['data'],\n scanId: string,\n outputKind: 'json' | 'markdown' | 'text'\n): Promise<void> {\n if (outputKind === 'json') {\n logger.log(data)\n } else {\n // Markdown = print\n if (outputKind === 'markdown') {\n logger.log('# Scan meta data\\n')\n }\n logger.log(`Scan ID: ${scanId}\\n`)\n for (const [key, value] of Object.entries(data)) {\n if (\n [\n 'id',\n 'updated_at',\n 'organization_id',\n 'repository_id',\n 'commit_hash',\n 'html_report_url'\n ].includes(key)\n ) {\n continue\n }\n logger.log(`- ${key}:`, value)\n }\n if (outputKind === 'markdown') {\n logger.log(\n `\\nYou can view this report at: [${data.html_report_url}](${data.html_report_url})\\n`\n )\n } else {\n logger.log(`\\nYou can view this report at: ${data.html_report_url}]\\n`)\n }\n }\n}\n","import { fetchScanMetadata } from './fetch-scan-metadata'\nimport { outputScanMetadata } from './output-scan-metadata'\n\nexport async function handleOrgScanMetadata(\n orgSlug: string,\n scanId: string,\n outputKind: 'json' | 'markdown' | 'text'\n): Promise<void> {\n const data = await fetchScanMetadata(orgSlug, scanId)\n if (!data) {\n return\n }\n\n await outputScanMetadata(data, scanId, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleOrgScanMetadata } from './handle-scan-metadata'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type {\n CliCommandConfig,\n CliSubcommand\n} from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'metadata',\n description: \"Get a scan's metadata\",\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> <scan ID>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: full-scans:list\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg 000aaaa1-0000-0a0a-00a0-00a0000000a0\n `\n}\n\nexport const cmdScanMetadata: CliSubcommand = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const scanId = (defaultOrgSlug ? cli.input[0] : cli.input[1]) || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: !!defaultOrgSlug,\n test: !!orgSlug && orgSlug !== '.',\n message: 'Org name as the first argument',\n pass: 'ok',\n fail:\n orgSlug === '.'\n ? 'dot is an invalid org, most likely you forgot the org name here?'\n : 'missing'\n },\n {\n test: !!scanId,\n message: 'Scan ID to inspect as argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleOrgScanMetadata(\n orgSlug,\n scanId,\n json ? 'json' : markdown ? 'markdown' : 'text'\n )\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleScanReport } from './handle-scan-report'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type {\n CliCommandConfig,\n CliSubcommand\n} from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'report',\n description:\n 'Check whether a scan result passes the organizational policies (security, license)',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n fold: {\n type: 'string',\n default: 'none',\n description: 'Fold reported alerts to some degree'\n },\n reportLevel: {\n type: 'string',\n default: 'warn',\n description: 'Which policy level alerts should be reported'\n },\n short: {\n type: 'boolean',\n default: false,\n description: 'Report only the healthy status'\n },\n license: {\n type: 'boolean',\n default: false,\n description: 'Also report the license policy status. Default: false'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> <scan ID> [path to output file]\n\n API Token Requirements\n - Quota: 2 units\n - Permissions: full-scans:list security-policy:read\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n By default the result is a nested object that looks like this:\n \\`{[ecosystem]: {[pkgName]: {[version]: {[file]: {[type:loc]: policy}}}}\\`\n You can fold this up to given level: 'pkg', 'version', 'file', and 'none'.\n\n By default only the warn and error policy level alerts are reported. You can\n override this and request more ('defer' < 'ignore' < 'monitor' < 'warn' < 'error')\n\n Short responses: JSON: \\`{healthy:bool}\\`, markdown: \\`healthy = bool\\`, text: \\`OK/ERR\\`\n\n Examples\n $ ${command} FakeOrg 000aaaa1-0000-0a0a-00a0-00a0000000a0 --json --fold=version\n $ ${command} FakeOrg 000aaaa1-0000-0a0a-00a0-00a0000000a0 --license --markdown --short\n `\n}\n\nexport const cmdScanReport: CliSubcommand = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const {\n fold = 'none',\n json,\n license,\n markdown,\n reportLevel = 'warn'\n } = cli.flags\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const scanId = (defaultOrgSlug ? cli.input[0] : cli.input[1]) || ''\n const file = (defaultOrgSlug ? cli.input[1] : cli.input[2]) || '-'\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: !!defaultOrgSlug,\n test: !!orgSlug && orgSlug !== '.',\n message: 'Org name as the first argument',\n pass: 'ok',\n fail:\n orgSlug === '.'\n ? 'dot is an invalid org, most likely you forgot the org name here?'\n : 'missing'\n },\n {\n test: !!scanId,\n message: 'Scan ID to fetch',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleScanReport({\n orgSlug,\n scanId: scanId,\n includeLicensePolicy: !!license,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text',\n filePath: file,\n fold: fold as 'none' | 'file' | 'pkg' | 'version',\n short: !!cli.flags['short'],\n reportLevel: reportLevel as\n | 'warn'\n | 'error'\n | 'defer'\n | 'ignore'\n | 'monitor'\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { handleApiError, queryApi } from '../../utils/api'\nimport { AuthError } from '../../utils/errors'\nimport { failMsgWithBadge } from '../../utils/fail-msg-with-badge'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { components } from '@socketsecurity/sdk/types/api'\n\nexport async function fetchScan(\n orgSlug: string,\n scanId: string\n): Promise<Array<components['schemas']['SocketArtifact']> | undefined> {\n const apiToken = getDefaultToken()\n if (!apiToken) {\n throw new AuthError(\n 'User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.'\n )\n }\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching scan data...')\n\n const response = await queryApi(\n `orgs/${orgSlug}/full-scans/${encodeURIComponent(scanId)}`,\n apiToken\n )\n\n spinner.successAndStop('Received response while fetching scan data.')\n\n if (!response.ok) {\n const err = await handleApiError(response.status)\n logger.fail(failMsgWithBadge(response.statusText, `Fetch error: ${err}`))\n return\n }\n\n // This is nd-json; each line is a json object\n const jsons = await response.text()\n const lines = jsons.split('\\n').filter(Boolean)\n const data = lines.map(line => {\n try {\n return JSON.parse(line)\n } catch {\n console.error(\n 'At least one line item was returned that could not be parsed as JSON...'\n )\n return {}\n }\n }) as unknown as Array<components['schemas']['SocketArtifact']>\n\n return data\n}\n","import fs from 'node:fs/promises'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { mdTable } from '../../utils/markdown'\n\nimport type { components } from '@socketsecurity/sdk/types/api'\n\nexport async function outputScanView(\n artifacts: Array<components['schemas']['SocketArtifact']>,\n orgSlug: string,\n scanId: string,\n filePath: string\n): Promise<void> {\n const display = artifacts.map(art => {\n const author = Array.isArray(art.author)\n ? `${art.author[0]}${art.author.length > 1 ? ' et.al.' : ''}`\n : art.author\n return {\n type: art.type,\n name: art.name,\n version: art.version,\n author,\n score: JSON.stringify(art.score)\n }\n })\n\n const md = mdTable<any>(display, [\n 'type',\n 'version',\n 'name',\n 'author',\n 'score'\n ])\n\n const report =\n `\n# Scan Details\n\nThese are the artifacts and their scores found.\n\nScan ID: ${scanId}\n\n${md}\n\nView this report at: https://socket.dev/dashboard/org/${orgSlug}/sbom/${scanId}\n `.trim() + '\\n'\n\n if (filePath && filePath !== '-') {\n try {\n await fs.writeFile(filePath, report, 'utf8')\n logger.log(`Data successfully written to ${filePath}`)\n } catch (e) {\n process.exitCode = 1\n logger.fail('There was an error trying to write the json to disk')\n logger.error(e)\n }\n } else {\n logger.log(report)\n }\n}\n","import { fetchScan } from './fetch-scan'\nimport { outputScanView } from './output-scan-view'\n\nexport async function handleScanView(\n orgSlug: string,\n scanId: string,\n filePath: string\n): Promise<void> {\n const data = await fetchScan(orgSlug, scanId)\n if (!data) {\n return\n }\n\n await outputScanView(data, orgSlug, scanId, filePath)\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkResultType } from '@socketsecurity/sdk'\n\nexport async function streamScan(\n orgSlug: string,\n scanId: string,\n file: string | undefined\n): Promise<SocketSdkResultType<'getOrgFullScan'> | undefined> {\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n const sockSdk = await setupSdk()\n\n spinner.start('Fetching scan...')\n\n const data = await handleApiCall(\n sockSdk.getOrgFullScan(orgSlug, scanId, file === '-' ? undefined : file),\n 'Fetching a scan'\n )\n\n spinner.successAndStop(\n file ? `Full scan details written to ${file}` : 'stdout'\n )\n\n if (!data?.success) {\n handleUnsuccessfulApiResponse('getOrgFullScan', data)\n }\n\n return data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleScanView } from './handle-scan-view'\nimport { streamScan } from './streamScan'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type {\n CliCommandConfig,\n CliSubcommand\n} from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'view',\n description: 'View the raw results of a scan',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> <scan ID> [path to output file]\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: full-scans:list\n\n When no output path is given the contents is sent to stdout.\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg 000aaaa1-0000-0a0a-00a0-00a0000000a0 ./stream.txt\n `\n}\n\nexport const cmdScanView: CliSubcommand = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const scanId = (defaultOrgSlug ? cli.input[0] : cli.input[1]) || ''\n const file = (defaultOrgSlug ? cli.input[1] : cli.input[2]) || '-'\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: !!defaultOrgSlug,\n test: !!orgSlug && orgSlug !== '.',\n message: 'Org name as the first argument',\n pass: 'ok',\n fail:\n orgSlug === '.'\n ? 'dot is an invalid org, most likely you forgot the org name here?'\n : 'missing'\n },\n {\n test: !!scanId,\n message: 'Scan ID to delete',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n if (json) {\n await streamScan(orgSlug, scanId, file)\n } else {\n await handleScanView(orgSlug, scanId, file)\n }\n}\n","import { cmdScanCreate } from './cmd-scan-create'\nimport { cmdScanDel } from './cmd-scan-del'\nimport { cmdScanDiff } from './cmd-scan-diff'\nimport { cmdScanList } from './cmd-scan-list'\nimport { cmdScanMetadata } from './cmd-scan-metadata'\nimport { cmdScanReport } from './cmd-scan-report'\nimport { cmdScanView } from './cmd-scan-view'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\n\nimport type { CliSubcommand } from '../../utils/meow-with-subcommands'\n\nconst description = 'Scan related commands'\n\nexport const cmdScan: CliSubcommand = {\n description,\n async run(argv, importMeta, { parentName }) {\n await meowWithSubcommands(\n {\n create: cmdScanCreate,\n list: cmdScanList,\n del: cmdScanDel,\n diff: cmdScanDiff,\n metadata: cmdScanMetadata,\n report: cmdScanReport,\n view: cmdScanView\n },\n {\n aliases: {\n // Backwards compat. TODO: Drop next major bump\n stream: {\n description: cmdScanView.description,\n hidden: true,\n argv: ['view'] // Original args will be appended (!)\n }\n },\n argv,\n description,\n importMeta,\n name: parentName + ' scan'\n }\n )\n }\n}\n","import constants from '../../constants'\nimport { queryApi } from '../../utils/api'\nimport { AuthError } from '../../utils/errors'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { ThreadFeedResponse } from './types'\n\nexport async function fetchThreatFeed({\n direction,\n ecosystem,\n filter,\n page,\n perPage\n}: {\n direction: string\n ecosystem: string\n filter: string\n page: string\n perPage: number\n}): Promise<ThreadFeedResponse | { error: { message: string } }> {\n const queryParams = new URLSearchParams([\n ['direction', direction],\n ['ecosystem', ecosystem],\n ['filter', filter],\n ['page', page],\n ['per_page', String(perPage)]\n ])\n\n const apiToken = getDefaultToken()\n if (!apiToken) {\n throw new AuthError(\n 'User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.'\n )\n }\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching Threat Feed data...')\n\n const response = await queryApi(`threat-feed?${queryParams}`, apiToken)\n\n spinner.successAndStop('Received response while fetching Threat Feed data.')\n\n const data = await response.json()\n\n return data as ThreadFeedResponse | { error: { message: string } }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\n\nimport type { ThreadFeedResponse, ThreatResult } from './types'\nimport type { Widgets } from 'blessed'\n\nexport async function outputThreatFeed(\n data: ThreadFeedResponse,\n {\n outputKind\n }: {\n outputKind: 'json' | 'markdown' | 'text'\n }\n) {\n if (outputKind === 'json') {\n logger.log(data)\n return\n }\n\n if (!data?.results?.length) {\n logger.error('Did not receive any data to display...')\n return\n }\n\n const formattedOutput = formatResults(data.results)\n const descriptions = data.results.map(d => d.description)\n\n // Note: this temporarily takes over the terminal (just like `man` does).\n const ScreenWidget = require('blessed/lib/widgets/screen')\n // Lazily access constants.blessedOptions.\n const screen: Widgets.Screen = new ScreenWidget({\n ...constants.blessedOptions\n })\n // Register these keys first so you can always exit, even when it gets stuck\n // If we don't do this and the code crashes, the user must hard-kill the\n // node process just to exit it. That's very bad UX.\n // eslint-disable-next-line n/no-process-exit\n screen.key(['escape', 'q', 'C-c'], () => process.exit(0))\n\n const TableWidget = require('blessed-contrib/lib/widget/table')\n const table: any = new TableWidget({\n keys: 'true',\n fg: 'white',\n selectedFg: 'white',\n selectedBg: 'magenta',\n interactive: 'true',\n label: 'Threat feed',\n width: '100%',\n height: '70%', // Changed from 100% to 70%\n border: {\n type: 'line',\n fg: 'cyan'\n },\n columnWidth: [10, 30, 20, 18, 15, 200],\n // TODO: the truncation doesn't seem to work too well yet but when we add\n // `pad` alignment fails, when we extend columnSpacing alignment fails\n columnSpacing: 1,\n truncate: '_'\n })\n\n // Create details box at the bottom\n const BoxWidget = require('blessed/lib/widgets/box')\n const detailsBox: Widgets.BoxElement = new BoxWidget({\n bottom: 0,\n height: '30%',\n width: '100%',\n border: {\n type: 'line',\n fg: 'cyan'\n },\n label: 'Details',\n content:\n 'Use arrow keys to navigate. Press Enter to select a threat. Press q to exit.',\n style: {\n fg: 'white'\n }\n })\n\n table.setData({\n headers: [\n ' Ecosystem',\n ' Name',\n ' Version',\n ' Threat type',\n ' Detected at',\n ' Details'\n ],\n data: formattedOutput\n })\n\n // allow control the table with the keyboard\n table.focus()\n\n screen.append(table)\n screen.append(detailsBox)\n\n // Update details box when selection changes\n table.rows.on('select item', () => {\n const selectedIndex = table.rows.selected\n if (selectedIndex !== undefined && selectedIndex >= 0) {\n const selectedRow = formattedOutput[selectedIndex]\n if (selectedRow) {\n // Note: the spacing works around issues with the table; it refuses to pad!\n detailsBox.setContent(\n `Ecosystem: ${selectedRow[0]}\\n` +\n `Name: ${selectedRow[1]}\\n` +\n `Version:${selectedRow[2]}\\n` +\n `Threat type:${selectedRow[3]}\\n` +\n `Detected at:${selectedRow[4]}\\n` +\n `Details: ${selectedRow[5]}\\n` +\n `Description: ${descriptions[selectedIndex]}`\n )\n screen.render()\n }\n }\n })\n\n screen.render()\n\n screen.key(['return'], () => {\n const selectedIndex = table.rows.selected\n screen.destroy()\n const selectedRow = formattedOutput[selectedIndex]\n logger.log('Last selection:\\n', selectedRow)\n })\n}\n\nfunction formatResults(data: ThreatResult[]) {\n return data.map(d => {\n const ecosystem = d.purl.split('pkg:')[1]!.split('/')[0]!\n const name = d.purl.split('/')[1]!.split('@')[0]!\n const version = d.purl.split('@')[1]!\n\n const timeDiff = msAtHome(d.createdAt)\n\n // Note: the spacing works around issues with the table; it refuses to pad!\n return [\n ecosystem,\n decodeURIComponent(name),\n ` ${version}`,\n ` ${d.threatType}`,\n ` ${timeDiff}`,\n d.locationHtmlUrl\n ]\n })\n}\n\nfunction msAtHome(isoTimeStamp: string): string {\n const timeStart = Date.parse(isoTimeStamp)\n const timeEnd = Date.now()\n\n const rtf = new Intl.RelativeTimeFormat('en', {\n numeric: 'always',\n style: 'short'\n })\n\n const delta = timeEnd - timeStart\n if (delta < 60 * 60 * 1000) {\n return rtf.format(-Math.round(delta / (60 * 1000)), 'minute')\n // return Math.round(delta / (60 * 1000)) + ' min ago'\n } else if (delta < 24 * 60 * 60 * 1000) {\n return rtf.format(-(delta / (60 * 60 * 1000)).toFixed(1), 'hour')\n // return (delta / (60 * 60 * 1000)).toFixed(1) + ' hr ago'\n } else if (delta < 7 * 24 * 60 * 60 * 1000) {\n return rtf.format(-(delta / (24 * 60 * 60 * 1000)).toFixed(1), 'day')\n // return (delta / (24 * 60 * 60 * 1000)).toFixed(1) + ' day ago'\n } else {\n return isoTimeStamp.slice(0, 10)\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { fetchThreatFeed } from './fetch-threat-feed'\nimport { outputThreatFeed } from './output-threat-feed'\nimport { failMsgWithBadge } from '../../utils/fail-msg-with-badge'\n\nimport type { ThreadFeedResponse } from './types'\n\nexport async function handleThreatFeed({\n direction,\n ecosystem,\n filter,\n outputKind,\n page,\n perPage\n}: {\n direction: string\n ecosystem: string\n filter: string\n outputKind: 'json' | 'markdown' | 'text'\n page: string\n perPage: number\n}): Promise<void> {\n const data = await fetchThreatFeed({\n direction,\n ecosystem,\n filter,\n page,\n perPage\n })\n if (!data) {\n return\n }\n\n if ('error' in data && data.error) {\n logger.fail(failMsgWithBadge('Server Error', data.error.message))\n return\n }\n\n await outputThreatFeed(data as ThreadFeedResponse, {\n outputKind\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleThreatFeed } from './handle-threat-feed'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'threat-feed',\n description: '[beta] View the threat feed',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n perPage: {\n type: 'number',\n shortFlag: 'pp',\n default: 30,\n description: 'Number of items per page'\n },\n page: {\n type: 'string',\n shortFlag: 'p',\n default: '1',\n description: 'Page token'\n },\n direction: {\n type: 'string',\n shortFlag: 'd',\n default: 'desc',\n description: 'Order asc or desc by the createdAt attribute'\n },\n eco: {\n type: 'string',\n shortFlag: 'e',\n default: '',\n description: 'Only show threats for a particular ecosystem'\n },\n filter: {\n type: 'string',\n shortFlag: 'f',\n default: 'mal',\n description: 'Filter what type of threats to return'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command}\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: threat-feed:list\n - Special access\n\n This feature requires a Threat Feed license. Please contact\n sales@socket.dev if you are interested in purchasing this access.\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Valid filters:\n\n - anom Anomaly\n - c Do not filter\n - fp False Positives\n - joke Joke / Fake\n - mal Malware and Possible Malware [default]\n - secret Secrets\n - spy Telemetry\n - tp False Positives and Unreviewed\n - typo Typo-squat\n - u Unreviewed\n - vuln Vulnerability\n\n Valid ecosystems:\n\n - gem\n - golang\n - maven\n - npm\n - nuget\n - pypi\n\n Examples\n $ ${command}\n $ ${command} --perPage=5 --page=2 --direction=asc --filter=joke\n `\n}\n\nexport const cmdThreatFeed = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !!orgSlug,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleThreatFeed({\n direction: String(cli.flags['direction'] || 'desc'),\n ecosystem: String(cli.flags['eco'] || ''),\n filter: String(cli.flags['filter'] || 'mal'),\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text',\n page: String(cli.flags['page'] || '1'),\n perPage: Number(cli.flags['perPage']) || 30\n })\n}\n","import fs from 'node:fs'\n\nimport { codeBlock } from 'common-tags'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nexport function addSocketWrapper(file: string): void {\n return fs.appendFile(\n file,\n 'alias npm=\"socket npm\"\\nalias npx=\"socket npx\"\\n',\n err => {\n if (err) {\n return new Error(`There was an error setting up the alias: ${err}`)\n }\n // TODO: pretty sure you need to source the file or restart\n // any terminal session before changes are reflected.\n logger.log(\n codeBlock`\nThe alias was added to ${file}. Running 'npm install' will now be wrapped in Socket's \"safe npm\" 🎉\nIf you want to disable it at any time, run \\`socket wrapper --disable\\`\n`\n )\n }\n )\n}\n","import fs from 'node:fs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nexport function checkSocketWrapperSetup(file: string): boolean {\n const fileContent = fs.readFileSync(file, 'utf8')\n const linesWithSocketAlias = fileContent\n .split('\\n')\n .filter(\n l => l === 'alias npm=\"socket npm\"' || l === 'alias npx=\"socket npx\"'\n )\n\n if (linesWithSocketAlias.length) {\n logger.log(\n `The Socket npm/npx wrapper is set up in your bash profile (${file})`\n )\n return true\n }\n return false\n}\n","import { existsSync } from 'node:fs'\n\nimport { codeBlock } from 'common-tags'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { confirm } from '@socketsecurity/registry/lib/prompts'\n\nimport { addSocketWrapper } from './add-socket-wrapper'\nimport { checkSocketWrapperSetup } from './check-socket-wrapper-setup'\nimport constants from '../../constants'\n\nexport async function postinstallWrapper() {\n // Lazily access constants.bashRcPath and constants.zshRcPath.\n const { bashRcPath, zshRcPath } = constants\n const socketWrapperEnabled =\n (existsSync(bashRcPath) && checkSocketWrapperSetup(bashRcPath)) ||\n (existsSync(zshRcPath) && checkSocketWrapperSetup(zshRcPath))\n\n if (!socketWrapperEnabled) {\n await installSafeNpm(codeBlock`\n The Socket CLI is now successfully installed! 🎉\n\n To better protect yourself against supply-chain attacks, our \"safe npm\" wrapper can warn you about malicious packages whenever you run 'npm install'.\n\n Do you want to install \"safe npm\" (this will create an alias to the socket-npm command)?`)\n }\n}\n\nasync function installSafeNpm(query: string): Promise<void> {\n logger.log(`\n _____ _ _\n| __|___ ___| |_ ___| |_\n|__ | . | _| '_| -_| _|\n|_____|___|___|_,_|___|_|\n\n`)\n if (\n await confirm({\n message: query,\n default: true\n })\n ) {\n // Lazily access constants.bashRcPath and constants.zshRcPath.\n const { bashRcPath, zshRcPath } = constants\n try {\n if (existsSync(bashRcPath)) {\n addSocketWrapper(bashRcPath)\n }\n if (existsSync(zshRcPath)) {\n addSocketWrapper(zshRcPath)\n }\n } catch (e) {\n throw new Error(\n `There was an issue setting up the alias: ${(e as any)?.['message']}`\n )\n }\n }\n}\n","import fs from 'node:fs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nexport function removeSocketWrapper(file: string): void {\n return fs.readFile(file, 'utf8', function (err, data) {\n if (err) {\n logger.fail('There was an error removing the alias:')\n logger.error(err)\n return\n }\n const linesWithoutSocketAlias = data\n .split('\\n')\n .filter(\n l => l !== 'alias npm=\"socket npm\"' && l !== 'alias npx=\"socket npx\"'\n )\n\n const updatedFileContent = linesWithoutSocketAlias.join('\\n')\n\n fs.writeFile(file, updatedFileContent, function (err) {\n if (err) {\n logger.error(err)\n return\n }\n // TODO: pretty sure you need to source the file or restart\n // any terminal session before changes are reflected.\n logger.log(\n `The alias was removed from ${file}. Running 'npm install' will now run the standard npm command.`\n )\n })\n })\n}\n","import { existsSync } from 'node:fs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { addSocketWrapper } from './add-socket-wrapper'\nimport { checkSocketWrapperSetup } from './check-socket-wrapper-setup'\nimport { postinstallWrapper } from './postinstall-wrapper'\nimport { removeSocketWrapper } from './remove-socket-wrapper'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'wrapper',\n description: 'Enable or disable the Socket npm/npx wrapper',\n hidden: false,\n flags: {\n ...commonFlags,\n enable: {\n type: 'boolean',\n default: false,\n description: 'Enables the Socket npm/npx wrapper'\n },\n disable: {\n type: 'boolean',\n default: false,\n description: 'Disables the Socket npm/npx wrapper'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <flag>\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} --enable\n $ ${command} --disable\n `\n}\n\nexport const cmdWrapper = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n // I don't think meow would mess with this but ...\n if (argv[0] === '--postinstall') {\n await postinstallWrapper()\n return\n }\n\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { disable, enable } = cli.flags\n\n const wasBadInput = handleBadInput(\n {\n test: !!(enable || disable),\n message: 'Must use --enabled or --disable',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !enable || !disable,\n message: 'Do not use both --enable and --disable',\n pass: 'ok',\n fail: 'missing'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n // Lazily access constants.bashRcPath and constants.zshRcPath.\n const { bashRcPath, zshRcPath } = constants\n if (enable) {\n if (existsSync(bashRcPath) && !checkSocketWrapperSetup(bashRcPath)) {\n addSocketWrapper(bashRcPath)\n }\n if (existsSync(zshRcPath) && !checkSocketWrapperSetup(zshRcPath)) {\n addSocketWrapper(zshRcPath)\n }\n } else {\n if (existsSync(bashRcPath)) {\n removeSocketWrapper(bashRcPath)\n }\n if (existsSync(zshRcPath)) {\n removeSocketWrapper(zshRcPath)\n }\n }\n if (!existsSync(bashRcPath) && !existsSync(zshRcPath)) {\n logger.fail('There was an issue setting up the alias in your bash profile')\n }\n}\n","#!/usr/bin/env node\n\nimport process from 'node:process'\nimport { pathToFileURL } from 'node:url'\n\nimport { messageWithCauses, stackWithCauses } from 'pony-cause'\nimport updateNotifier from 'tiny-updater'\n\nimport { debugLog } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { cmdAnalytics } from './commands/analytics/cmd-analytics'\nimport { cmdAuditLog } from './commands/audit-log/cmd-audit-log'\nimport { cmdCdxgen } from './commands/cdxgen/cmd-cdxgen'\nimport { cmdCI } from './commands/ci/cmd-ci'\nimport { cmdConfig } from './commands/config/cmd-config'\nimport { cmdScanCreate } from './commands/dependencies/cmd-dependencies'\nimport { cmdDiffScan } from './commands/diff-scan/cmd-diff-scan'\nimport { cmdFix } from './commands/fix/cmd-fix'\nimport { cmdInfo } from './commands/info/cmd-info'\nimport { cmdLogin } from './commands/login/cmd-login'\nimport { cmdLogout } from './commands/logout/cmd-logout'\nimport { cmdManifest } from './commands/manifest/cmd-manifest'\nimport { cmdNpm } from './commands/npm/cmd-npm'\nimport { cmdNpx } from './commands/npx/cmd-npx'\nimport { cmdOops } from './commands/oops/cmd-oops'\nimport { cmdOptimize } from './commands/optimize/cmd-optimize'\nimport { cmdOrganization } from './commands/organization/cmd-organization'\nimport { cmdPackage } from './commands/package/cmd-package'\nimport { cmdRawNpm } from './commands/raw-npm/cmd-raw-npm'\nimport { cmdRawNpx } from './commands/raw-npx/cmd-raw-npx'\nimport { cmdReport } from './commands/report/cmd-report'\nimport { cmdRepos } from './commands/repos/cmd-repos'\nimport { cmdScan } from './commands/scan/cmd-scan'\nimport { cmdThreatFeed } from './commands/threat-feed/cmd-threat-feed'\nimport { cmdWrapper } from './commands/wrapper/cmd-wrapper'\nimport constants from './constants'\nimport { AuthError, InputError, captureException } from './utils/errors'\nimport { failMsgWithBadge } from './utils/fail-msg-with-badge'\nimport { meowWithSubcommands } from './utils/meow-with-subcommands'\n\nconst { SOCKET_CLI_BIN_NAME } = constants\n\n// TODO: Add autocompletion using https://socket.dev/npm/package/omelette\nvoid (async () => {\n await updateNotifier({\n name: SOCKET_CLI_BIN_NAME,\n // The '@rollup/plugin-replace' will replace \"process.env['INLINED_SOCKET_CLI_VERSION']\".\n version: process.env['INLINED_SOCKET_CLI_VERSION']!,\n ttl: 86_400_000 /* 24 hours in milliseconds */\n })\n\n try {\n await meowWithSubcommands(\n {\n cdxgen: cmdCdxgen,\n ci: cmdCI,\n config: cmdConfig,\n fix: cmdFix,\n info: cmdInfo,\n login: cmdLogin,\n logout: cmdLogout,\n npm: cmdNpm,\n npx: cmdNpx,\n oops: cmdOops,\n optimize: cmdOptimize,\n organization: cmdOrganization,\n package: cmdPackage,\n 'raw-npm': cmdRawNpm,\n 'raw-npx': cmdRawNpx,\n report: cmdReport,\n wrapper: cmdWrapper,\n scan: cmdScan,\n 'audit-log': cmdAuditLog,\n repos: cmdRepos,\n dependencies: cmdScanCreate,\n analytics: cmdAnalytics,\n 'diff-scan': cmdDiffScan,\n 'threat-feed': cmdThreatFeed,\n manifest: cmdManifest\n },\n {\n aliases: {},\n argv: process.argv.slice(2),\n name: SOCKET_CLI_BIN_NAME,\n importMeta: { url: `${pathToFileURL(__filename)}` } as ImportMeta\n }\n )\n } catch (e) {\n process.exitCode = 1\n let errorBody: string | undefined\n let errorTitle: string\n let errorMessage = ''\n if (e instanceof AuthError) {\n errorTitle = 'Authentication error'\n errorMessage = e.message\n } else if (e instanceof InputError) {\n errorTitle = 'Invalid input'\n errorMessage = e.message\n errorBody = e.body\n } else if (e instanceof Error) {\n errorTitle = 'Unexpected error'\n errorMessage = messageWithCauses(e)\n errorBody = stackWithCauses(e)\n } else {\n errorTitle = 'Unexpected error with no details'\n }\n logger.error('\\n') // Any-spinner-newline\n logger.fail(failMsgWithBadge(errorTitle, errorMessage))\n if (errorBody) {\n debugLog(`${errorBody}`)\n }\n await captureException(e)\n }\n})()\n"],"names":["status","spinner","process","debugLog","cause","logger","method","headers","Authorization","handleUnsuccessfulApiResponse","mw2","lines","cols","length","cws","body","time","data","rows","screen","label","barWidth","barSpacing","xOffset","maxHeight","barBgColor","formattedData","totalTopAlerts","sortedTopFiveAlerts","top_five_alert_types","formatted","style","line","text","baseline","xLabelPadding","xPadding","wholeNumbersOnly","legend","width","x","y","config","type","default","hidden","description","dryRun","help","shortFlag","silent","json","markdown","all","strict","msg","keyPrefix","padName","REDACTED","__proto__","commandOrAliasName","allowUnknownFlags","autoHelp","configOverrideResult","parentName","DRY_RUN_BAIL_TEXT","commandName","flags","file","repo","scope","run","test","message","pass","fail","nook","assert","filePath","perPage","outputJson","outputMarkdown","page","desc","generated","org","logs","user_email","logType","YARN_LOCK","cleanupPackageLock","result","i","configuration","coerce","author","filter","only","profile","standard","lifecycle","alias","array","key","boolean","argv","defaultOrg","repoName","branch","commit_hash","commit_message","committers","make_default_branch","set_as_pending_head","scanStatus","updateProgress","policyStatus","updateScan","finishedFetching","ok","scan","securityPolicy","version","alerts","healthy","addAlert","options","reportLevel","policy","url","manifest","ecomap","pkgmap","vermap","filemap","keys","value","short","depth","Package","Policy","scanId","success","tmp","branchName","fold","includeLicensePolicy","commitMessage","commitHash","cwd","defaultBranch","interactive","outputKind","pendingHead","pullRequest","readOnly","report","slug","choices","name","updateConfigValue","obj","full","auto","get","list","set","unset","offset","columns","field","limit","orgSlug","fs","showHidden","colors","maxArrayLength","after","before","GITHUB_REF_NAME","stdio","stdout","SOCKET_SECURITY_GITHUB_PAT","auth","_octokitGraphql","authorization","head","state","node_id","number","pullRequestId","workspaceName","base","NPM","path","testScript","consolidate","include","existing","unfixable","upgradable","nothrow","pkgPath","vulnerableVersionRange","unavailableSpecs","editable","dependencies","optionalDependencies","peerDependencies","owner","updatePackageJsonFromNode","saved","testedSpecs","installed","fixedSpecs","error","errored","revertedSpecs","editablePkgJson","failedSpecs","SOCKET_IPC_HANDSHAKE","args","constants","env","spawnPromise","PNPM","agentExecPath","NODE_OPTIONS","ignoreIncompatible","installedSpecs","actualTree","YARN_CLASSIC","semver","onUnknown","agent","agentVersion","maintainedNodeVersions","engines","pkgAgentRange","pkgNodeRange","lockSrc","lockName","lockPath","features","npmBuggyOverrides","pkgRequirements","node","pkgSupports","cmdName","prod","autoPilot","autoMerge","purl","isMultiple","rangeStyle","acc","count","fallbackToUrl","severityCount","pkgVersion","Maintenance","Quality","Vulnerabilities","Object","outputPackageIssuesDetails","includeAllIssues","SOCKET_PUBLIC_API_TOKEN","apiBaseUrl","apiProxy","enforcedOrgs","applyLogout","attemptLogout","buf","resolve","reject","keeping","collecting","arr","out","verbose","stderr","bin","gradleOpts","task","poms","sbtOpts","subArgs","meow","importMeta","conda","scala","gradle","kotlin","aliases","yolo","NPX","overrides","pkgs","pkgid","names","isPlacingHigher","insertIndex","entries","added","addedInWorkspaces","updated","updatedInWorkspaces","warnedPnpmWorkspaceRequiresNpm","workspacePkgJsonPaths","npmExecPath","overridesDataObjects","package","depAliasMap","thisSpec","depObj","newSpec","updateManifestByAgent","NPM_BUGGY_OVERRIDES_PATCHED_VERSION","pin","mw1","mw3","console","security","license","defaultSub","quota","SOCKET_CLI_ISSUES_URL","self","capabilities","score","transitively","selfCaps","valid","purls","components","packageData","License","shallowScore","shallow","deep","meowOrExit","create","view","visibility","repoDescription","homepage","sort","per_page","direction","created_at","del","update","updatedInput","id1","id2","from","year","month","day","fromTime","untilTime","diff","metadata","stream","fg","selectedFg","selectedBg","height","border","columnWidth","columnSpacing","truncate","bottom","content","table","numeric","eco","zshRcPath","enable","disable","SOCKET_CLI_BIN_NAME","cdxgen","ci","fix","info","login","logout","npm","npx","oops","optimize","organization","wrapper","repos","analytics","errorTitle","errorMessage","errorBody"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEO;;AAEP;;ACYO;AAIL;;AACQA;AAAO;AACf;AACE;;AACQC;AAAQ;;AAIhB;AACF;;AAEA;AACAC;AACF;AAEO;AAIL;;;;AAIEC;AACA;AAA2CC;AAAS;AACtD;AACA;AACF;AAEO;;AAEH;AACF;;AAEE;AACF;;AAEE;AACF;;AAEF;AAEO;AACL;;AAEF;;AAEA;AACO;AACL;AAEA;AACE;AACF;AACA;AACA;AACA;AACF;AAEO;AACL;;AAEEC;AAGF;AACA;AAGIC;AACAC;AACEC;AACF;AACF;AAEJ;;ACvFO;AAIL;AACA;AAKA;AACEC;AACF;;AAIA;AACEJ;AACA;AACF;;AAGF;;ACtBO;AAKL;AACA;AAKA;AACEI;AACF;;AAIA;AACEJ;AACA;AACF;;AAGF;;AC/BO;AAKL;AACA;AACA;AACA;AACA;AACA;AACA;;AAEEK;AACF;;;AAIAC;AACA;;AAIA;AACAA;AAEA;AACF;AAEO;AAEL;AACA;AACAC;AAGA;;AAGA;AACE;AAAkBC;;AAChB;AACA;AACAC;AAKF;AACF;;AAGA;;AAEA;;AAGA;AAAkBD;;;AAElB;;AAGA;AACEE;AACA;AAAkBF;;AAChB;AACA;;AAEF;AACAE;AACF;AAEA;AACF;AAEO;AAEL;AACA;AACAH;AAEA;;;;;AAMA;;AAGA;;AAEA;;AAGA;AAAkBC;;;AAElB;;;AAIEE;;;AAGAA;AACF;AAEA;AACF;;AChGuC;;AAmBvC;;AAeA;AACA;AAeO;;;;;AAKLC;AAOF;AACE;;AACQf;AAAQ;AAEhBA;AAEA;;AAKEgB;;;AAGF;;AAEA;;AAEE;AACF;;AAGE;;AAEE;AACF;AAEA;;;AAGIZ;;;AAGAA;AACAA;AACF;AACF;AACEA;AACF;AACF;AACE;;;AAKE;;;AAGIA;;AAEAA;AACF;AACF;AACEA;AACF;AACF;;AAEA;AACF;AACF;AAEA;;;;;AAKI;AACAA;AAGA;AACF;AACF;AAEA;AAKE;AACF;;AAEA;;AAEA;AAqCA;;AAEA;AACA;;AAIA;;AAEA;AACA;AACA;AAEA;AACE;AACA;AACA;AACE;AACF;AACA;AACA;AAAgCa;AAASN;AAASO;AAAO;;;;;;;;;AA2DzD;AACEC;AACAC;AACAC;AACAC;AACAC;AACAC;AACF;AAEAN;;;;AAIEF;AACF;;AAGA;AACAE;AACF;AAEA;;;;AAOE;AACEO;AACF;AAEA;AACE;;AAEE;AACA;AACEC;;AAEAA;AACF;AACF;AACF;AACA;AACE;AACED;AACF;AACF;AAEA;;AAIEE;AACF;;AAGE;AACAC;;AAEJ;AAEA;;;;AAOE;AACEH;AACF;AAEA;AACE;;AAEE;AACA;AACEC;AACF;AACEA;AACF;AACF;AACF;AAEA;AACE;AACA;;AAEE;AACEG;AACF;AACEA;AACF;AACF;AACF;AAEA;;AAIEF;AACF;;AAGE;AACAC;;AAEJ;AAEA;;AAEA;AAEA;AAOE;AACA;AACEE;AAASC;AAAcC;AAAcC;;AACrCC;AACAC;AACAb;AACAc;AACAC;AACEC;;AAEFnB;AACF;AAEAD;AAEA;AACEqB;AACAC;;AAGFT;AACF;;AC9ZA;;AAMA;;AAMO;AACLU;AACEC;AACAC;AACAC;AACAC;;AAEFC;AACEJ;AACAC;AACAC;AAAc;AACdC;;AAEFE;AACEL;AACAC;AACAK;AACAH;;AAEFI;AACEP;AACAC;AACAC;AACAI;AACAH;AACF;AACF;AAEO;AACLK;AACER;AACAM;AACAL;AACAE;;AAEFM;AACET;AACAM;AACAL;AACAE;AACF;AACF;AAEO;AACLO;AACEV;AACAC;AACAE;;AAEFQ;AACEX;AACAC;AACAE;AACF;AACF;;AC9DO;;AAUH;AACF;;AASA;AACE;AACA;AACE;AACF;;;AAGA;AACA;AACAS;AAGA;AACEA;AACF;AACAA;AACF;;;AAIA;AACA;AACA;;AAGA;AACF;;ACzCO;AAGHC;AAAkBC;AAAQ;AAE5B;;;;AAKeA;AAAQ;AAEzB;AAEO;AAGHD;AAAgBC;AAAa;;;AAI/B;AACE;;AAEE;AACF;AACA;;AAOF;AACA;AACF;;ACtBA;;AAAuBC;AAAS;AAiDzB;;;;;;;;AAWL;AAAMC;;;AACN;;AAEA;AACEC;AACF;AAEA;AACE;AACA;;;AAGF;AACA;;AAKIjB;AACAC;AACAC;AAAe;AACfC;;AAGJ;;AAIF;AACA;;AAEA;AACA;AAEU;AAGS;AAAc;AAIvB;AAEsC;AAAS;;AACjCD;AAAO;;;AAGf;AACF;;;AAOd;AACA;;AAEA;AACA;AACA;;;AAIM;;AAEA;AACAgB;AACA;AACA;AACAC;AACF;;AAGF;AACA;AACA;AACA;AACA;;;AAKEC;AAGF;AAEA;AACE;AACA;;AAEF;AACE;AACA;AACA;AACA;AACA;AACA;AAKA;AACE;AACA;;AAEF;AACF;AAEA;;AAEE1D;;AAEA;AACF;;AAEA;AACA;AACE;AACA;;AAIA;;AAEA;AACA;;AAEI2D;AACF;AACF;AACF;;AAEA;AACA;;AAEA;AACA;;AAEE3D;AACF;;AAEA;AACF;;AAEA;AACA;AACA;AACO;;AACc;;;;AAInB2D;AAOF;;;AAIE;;;;;;;AAOEH;;AAEF;AAEA;;AAEA;AACA;;AAEA;AACA;AACF;AAEO;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACAxD;AACF;AAEA;AAIE;AAGIH;;AAEJ;AACA;;AAEA;AAKA;AAaA;AACF;AACA;AACA;AACA;;AAEA;;AC/SA;AAAQ+D;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;AACA;AACAC;AACEzB;AACAM;AACAL;AACAE;;AAGFuB;AACE1B;AACAM;AACAL;AACAE;;AAEFwB;AACE3B;AACAM;AACAL;AACAE;;AAGF9B;AACE2B;AACAM;AACAL;AACAE;AACF;;;AAEgBqB;AAAM;AAC1B;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEO;;;AAGLI;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;;;;;AAE2ChD;;AAE3C;;AAIIwD;AACAC;AACAC;AACAC;AACF;;AAGEF;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEEC;;AAEAH;AAEAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AAEAC;AACAC;AACF;AAEEC;;AAEAH;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEAwE;AACAA;;;;AAKER;;AAEAS;AACF;AACF;AAEA;AACE;AACF;AAEA;;AAEA;;AC/JO;;;;;AAKLC;AAOF;AACE;;AAEA;;AACQ9E;AAAQ;AAEhBA;;AAII;AACA+E;AACA;AACAC;;AAEAtC;AACAuC;;AAEF;AAIF;AACEzE;AACF;;;AAKF;;ACrCA;AAAQiD;AAAS;AAEV;;;;;AAOHqB;AAOF;;;;;;AAQMA;AACF;AAEJ;;;;;AAMMA;AACF;AAEJ;AACF;AAEO;;;;AAMHA;AAMF;AAEA;;AAEE5B;AAEIgC;AACAC;AACAC;;;;AAIAC;AACE;;;;;;;AAOEC;AACF;;;;;;;AAOEA;;;AAGN;;;AAMFlF;;AAIEF;AACF;AACA;AACF;AAEA;AACF;AAEO;;;;AAMH4E;AAMF;;AAGE;;AAUJ;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;;AAGI1E;;AAIEF;AACF;AACA;AACA;AACF;AACF;;AC1JO;;;;;AAKL4E;AAOF;AACE;;;;;AAKES;AACF;;AAEE;AACF;;;;;;AAOET;AACF;AACF;;ACrBA;AAAQd;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACExB;AACEA;AACAM;AACAL;AACAE;;AAEFiC;AACEpC;AACAM;AACAL;AACAE;;AAEFoC;AACEvC;AACAM;AACAL;AACAE;;AAEF;;;AAGFE;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;;;;AAEuCrB;;AACvC;AAEA;;AAGA;;;AAKI8B;AACAC;AACAC;AACF;AAEEC;;AAEAH;AAEAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEA;;;AAGE6E;AACAH;AACAS;AACF;AACF;;ACnHA;;;;;;AAAiDC;AAAU;AAE3D;AAWO;;;;;AAEiB;AAAM9B;;;;;AAO1B;;AAEA;AACE;AACA;;AAEE;AAEE;AACA;;AAKF+B;;AAEJ;AACF;AACA;AAEE;AACA;AAGF;;AAEI;;AAEJ;AACA;AACA;AACErF;AACF;AACF;AAEA;AAGE;;AAEA;;AAEA;AAAa;AAAQ;AAAS;AAC5B;AACE;AACF;;AAEE;AACA;AACAsF;AACF;AACEA;AACF;;;AAGEA;AACF;AACF;AACA;;AAEA;AACA;AACF;;AC/FA;AAEO;;AAEL;AAAkB9E;;;AAEd;AACA;AACE8E;AACAC;AACF;AACED;AACF;AACF;AACF;AACA;AACF;AAEO;;AAEL;AACF;AAEO;AACL;AACF;;ACzBA;AAcA;AAAQ1B;AAAkB;;AAE1B;AACA;AACA;AAEA;AACE4B;AACE;AACA;AACA;AACA;AACA;;AAEFC;AACEC;AACAC;AACAC;AACAC;AACAC;AACAxD;;AAEFC;AACE;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACAwD;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEFC;;;;;;;;;;AAUAC;AACIC;AAAe5D;AAAe;AAC9B4D;AAAgB5D;AAAe;AAC/B4D;AAAe5D;AAAe;AAC9B4D;AAAa5D;AAAe;AAC5B4D;AAAiB5D;AAAe;AAChC4D;AAAa5D;AAAe;AAEhC6D;AAgBE;AACA;AACA;;AAiBJ;AAEA;AACEtC;AACApB;AACAD;AACAsB;AACE;;AAEFnB;AACF;AACA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;AAGnCH;AACA;AACA4C;;;AAGAzC;AACF;;AAEA;AACA;AACE;;AAGF;;AACQnD;AAAsB;AAC9B;AACE;AACA;AACA;;;AAKA;AACF;AAEA;AACER;AACA;AACF;AAEA;;AAEA;;AAGF;;AC7KA;AACO;AACL;AACA;AACEA;AACF;AACE;AACA;AAIA;AACA;AACA;AACEA;;AAIA;AACF;AACA;AACA;AAEA;AACEA;;AAIA;AACF;;AAIA;AACEqG;AACArG;AACF;AACF;;AAGEA;;AAIA;AACF;AAEA;AACF;;AChDO;;;;;;AAaHsG;AAQF;AAEA;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AAEF;AAEEuB;AACAvB;AACA1F;;AAEN;AACA;AACEzC;AAGA2J;AACF;AACE3J;AACF;AACF;AACE;AACEoE;AAEAqF;AAEIC;AACAvB;;AAEF;AAEEuB;AACAvB;AACA1F;;AAEN;AACA;AACEzC;AACA2J;AACF;AACE3J;AACF;AACF;AACF;AACF;AACF;;AC1FO;;AAELmJ;AAIF;AACE;AAEA;AACF;;ACFA;AAAQvF;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;;;AAGFnB;AACF;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAIA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;AAEcZ;;;;;AAMVqB;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEA;AACEkG;;AAEF;AACF;;AC5FO;AAGc;AACnBiD;;AAGEnJ;AACmByI;AAAenD;;AAAe6C;;AAASmB;AAAS;AAErE;AACEtJ;AACAA;;AAEA;AACEA;AACAA;AAGF;AACF;;AAEE;AACEA;AACAA;AAGF;AACF;AACF;;AC5BO;;AAELmJ;AAIF;AACE;AACA;;AAGF;;ACHA;AAAQvF;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;;;AAGFnB;AACF;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAIA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;AAEcZ;;;;;AAMVqB;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEA;AACEkG;;AAEF;AACF;;AClFO;;AAELiD;AAIF;AACE;;;;AAII;;AAEEhB;AACF;AACA;AACEyB;AACF;AACF;AACA5J;AAGMyI;;AAEApG;AACAiH;AACF;AAKN;AACE;AAKAtJ;AACAA;;AAEAA;;AAEE;;AAEEmI;AACF;AACA;;AAIA;AACF;AAC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D;AACE;;AAMF;AACAlJ;AACAA;;;AAEoDkJ;AAAI;AACxD;;AACkDA;AAAI;AACtD;AAAmEA;AAAI;AACvE;AACF;AAEO;;AACqCA;AAAI;AAChD;AAEA;;AAGUgC;;AAAyDhC;AAAI;AACrE;;AAEF;AAEO;;;;AAID+B;AACF;AACA;;AAEF;AACF;;ACjJA;;;AAA2CE;AAA2B;AAQtE;AACA;;;AAGM;AACAC;AACF;AACF;AACA;AACF;AAEA;AACO;;AAEHC;AACEjL;AACE;AACAkL;AACF;AACF;AACF;AACA;AACF;AAEO;AAKL;;;AAEUxK;AAAU;;;AAGhByK;AACAC;AACF;AACAxL;AACA;;AAEF;AACF;AAEO;AACLyL;AACAC;AACuB;AACvB;;;AAIF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEQC;AACF;AAEFzL;AACA;;AAEA;AACA;;AAEYoE;AAAQ;;AAGpB;AACApE;AACA;AACF;AACF;AAEO;AACL;AACA;AACA;AACA;AACE;AACF;;;AAGEgE;;AAEJ;AAOO;;AASGgF;AAAqB0C;AAAc;AACzCpI;;;AAGF;AACA;AACE;AACA;;AAEE;AACF;;AAEA;AACE0F;AACF;AACA;;AAEE;;;;AAIEqC;AACAM;AACAjL;AACF;;;;;AAKE;AACE;;AAOF;AACF;AACAV;AACA;AACF;AACF;AACA;AACF;;ACrIA;;AAAY4L;AAAI;AAMhB;;AAIU5C;AAAoB;AAC1B1F;;;AAGF;AAA4BuI;AAAU;;AAEtC;AACF;AAEO;;;;;;;AASHC;AACoB;;AAItB;;;AAGA;AACA;AACA;AAEA;AACEC;AACAC;AACEC;AACAC;AACAC;;AAEFC;;;AAOF;;;AAGE;AACF;;AAEA;AACA;;AACQC;AAAkB;;AAElB;AAAW;AAAyB;;AAS5C;AAEA;AAAa;AAAS;;;AAEpB;AACEzM;AACA;AACF;;;AAMM;AACA;;AAGJ;AACF;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACE;AACA;AACA;;AAEE0M;;AAEA;;AAEA;AACA;;;AAGE;AACF;;AASE;AACEC;AACA3M;AACF;AACA;AACF;AAEA;;AAGE;;AAIA;AAEI;;AACqC4M;AAAe;AAExD;;AAEA;AACA;AAEA;AACE;AACMC;;AAEN;AAEMC;;AAIN;AACMC;AAA2D;;AAInE;;;;AAIe3I;AAAK;AAEd4I;AAAW5I;;;AAEb;;AAIJ;AACE;AACA;AACF;AAEA6I;AAQA;;;;;AAKA;AACA;AACEC;AACF;AAEA;AACEC;;AAEF;;AAGE;AACA;AAAgC/D;AAAI;AACpCgE;AAEA;AACE;AACED;;AAEF;AACA;AACA;;AAA2ChC;AAAgB;AAC7D;AACA;AACEkC;;;AAGF;;AAEAC;AACAC;AACF;AAEA;AACE;AACA;AAKA;AACA;;AASIzB;AACF;;AAGA;AACA;AACF;AACF;;AAGE;AACE;AACE0B;;AAEF;AACF;AACA;AACE;;AAEF;AACA;AACEC;;AAEE;AACA;AACF;AACF;AACA;AACE;;AAC4BrE;AAAI;AAClC;AACA;AACE;AACEsE;;AAIF;AACF;AACF;AACF;AACF;AACF;AACF;;AAEF;;AChUA;;;;AAIEC;AACF;AAWO;;;AAGHC;;;;AAIF;AAAMlK;;;AACN;AACA;AACA;AACA;AACA;AACA;AACEyH;AACF;AACEA;AACF;AACA;AACA;AACA;;;AAKA;;;;AAIE;;AAGE;;AAEA;;AAEA;;AASA;AACA0C;AAGA;AACA;AAEA;;AAEA;AACA;;;AAOA;;AAEAC;;AAEE;AACF;AACF;AAEF;AACEC;AACE;;;;AAIA;AACF;AACF;AACA;AACF;;ACxGA;;AAAaC;AAAK;AAWX;;;AAIUC;AAAc;AAC7B;;AAEE;;;AAGA;AACF;;AAEEL;;;AAGF;AAAMlK;;;AACN;;;AAIEyH;AACA;AACA2C;;AAEEI;AAGM;;AAEJ;AACA;AAEF;AACF;AACF;AACF;;ACDA;;;;AAA4BF;AAAK;AAOjC;AACE;AACE/B;;AAEF;AACA;AACF;AAEA;;;AAIejM;AAAQ;AAAM0D;;;;;;AAIzByH;AACF;AACA;AACF;AAEO;;;;;;;AASHe;AACoB;;AAGpBiC;AACF;;AAEE;AACF;AAEA;AACEhC;AACAC;AAAWC;AAAgBC;AAAkBC;;AAC7CC;;;AAOF;;AAEE;AACF;;;AAIA;AACA;;AACQC;AAAkB;;AAGxB;AACA;AACA;;;AAWFvM;;AAIA;AAAa;AAAS;;AACpB;AACEF;AACA;AACF;AACA;;AAKM;AACA;;AAGJ;AACF;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACE;AACA;AAEA;;AAEE0M;;;;AAIE;AACF;;;;AAaA;AACE;AACEC;AACA3M;AACF;AACA;AACF;AAEAE;AACA;;AAGE;;AAIA;AAEI;;AACqC0M;AAAe;AAExD;AAGA;AACA;AAGA;AAIA;AACA;AAKA;AACA;;AAIM;AACE;AACA;;;AAGA;AACF;AACF;AAGJ;AACE;;AAIY;AACA;;;AAMM;AACR;;AAIV;AACMC;;AAEN;AAEMC;;AAIN;AACMC;AAA2D;;AAInE;;;;AAIe3I;AAAK;AAEd4I;AAAW5I;;;AAEb;;AAIJ;AACE;AACA;AACF;AAEA;AACEqJ;AACF;AAEA;AAOAvN;AACAA;AACA;;;;AAIA;;AAEEA;AACA;AACF;AAEA;AACEkO;;AAEF;;AAGE;AACAC;AAA4CrO;AAAQ;AACpDoN;AAEA;AACE;AACED;;AAEF;AACA;AACA;;AAA2ChC;AAAgB;AAC7D;AACA;AACEkC;;;AAGF;;AAEAC;AACAC;AACF;AAEArN;AACAA;AACA;;AAEE;AACA;;AAMA;AACA;;AASI4L;AACF;;AAGA;AACA;AACF;AACF;;AAGE;AACE;AACE0B;;AAEF;AACF;AACAC;AACA;AACE;;AAEA;AACAY;;AAEA;AACA;AACA;AACAA;AAA4CrO;AAAQ;AACtD;AACA;AACE;AACE0N;;AAIF;AACF;AACF;AACF;AACF;AACF;AACF;;AAEF;;AClZO;AAEA;AAGL;;AAEA;AACA;AACE7F;AACF;AACA;AACEA;AACF;AACA;;AAEA;AACA;AACEA;AACF;AACA;;AAEA;AACA;AACF;;ACHA;;;;;;;;;;;;AAYEyG;AACF;AAEO;AAIP;AASA;AACE;AACA;AAA+B9B;;AACjC;AAEA;AAIE;;;AAGI;AACA;AACA;AACA+B;AACE;;AAC6CnF;AAAI;;AAGvD;AACF;;AAEA;AACA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAMA;;;;AAMQ;;AAEF;;AAEJ;AAEA;AAEA;AAIA;AAIM;;AAEE;AACF;;AAEE;AACA;;;;AAIA;AACA;AACA;AACA;AACA;AACF;AACA;AACF;AAQN;AAuDO;AACLA;AACAoF;AACa;;AACqCpF;AAAI;;AAEtD;;AAMiCA;AAAI;AACrC;;AAKqCwD;;AAErC;AACA;AACA;AAIA;AACA;AACA;AACE;AACA;AACA;AACA;;;;AAII6B;AACF;AACF;AACF;AACA;AAMEA;AACF;;AAEEA;;AAEF;AACA;AACA;;AAGEC;AACF;AACA;AACED;AACF;AACA;;AACQE;AAAuB;AAC/B;;AAEA;;AAEA;AACA;AACA;;;;;AAIUC;;AACR;AACA;AACA;AACEC;AACA;AACA;AACA;;;AAGA;AACF;AACA;AACEC;AACA;AACA;AACA;;;AAGA;AACF;AACA;AAGA;AACE;AACA;;AAKE;;;;AAIA;AACF;AACF;AACAC;AAIF;AACEC;AACAC;AACF;AACA;AACA;;AAIA;;AAMA;;;;;;;AAWEC;AAAYC;;;;;;;;;AAQZC;AACEX;AACAY;;AAEFC;AACE;;AAKA;AACAD;AAGF;;AAEJ;AAQO;;AAKHE;;AAEAC;AACF;AACE9L;;;AAGF;;;AAGItD;AAMF;AACF;;;;AAC4BgP;AAAgB;AAC5C;AACA;;AAEEhP;AAMA;AACF;AACA;AACE;AACAA;AAMA;AACF;AACA;AACEA;AAMA;AACF;AACA;AACEA;AAMA;AACF;;;AAQE;AACF;AACA;;;AAGE;AACF;;;AAGE;AACF;AACA;;AAEE;AACF;;AAEEA;AAMA;AACF;AACA;AAIEA;AAMF;AACA;AACF;;ACvdA;;AAAa4N;AAAK;AAEX;;AAEHtK;;AAEF;;AAEE6L;AACAnP;AACF;;AAEE;AACF;;;AAEQqO;AAAM;;AAEZ;AACF;AACE;AACF;AACF;;ACdA;AAAQzK;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;AACAuL;AACE/M;AACAC;AACAE;;AAEF6M;A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Q;AACF;AACE;AACE7Q;AAGF;AACA4Q;AACF;AACF;AACF;;;AAII1J;AACA9C;AACAxD;;AAEJ;AACF;;AAGE;AACEZ;AACF;AAEA;;AAEIkH;;AAEAtG;;AAEJ;;;;AAKWsG;AAAW9C;AAA0BxD;;AAChD;AACF;;AAGEsG;AACA9C;AACAxD;;;AAGA;;AAEJ;;AAEA;AACO;;;;;;;AAOD;AACA;AACF;AACA;AACE;AACE;AACA;AACF;AACA;AACE;AACA;AACA;AACF;;AAEI;;;AAGE;AACE;AACA;AACA;AACF;AACF;AACF;AACA;AACEkQ;AACF;AACE;AACA;AACF;AACF;AACF;AACE;;;AAGEC;AACF;AACF;AACF;AAEA;AACF;;ACvIO;;AAMH;AAEI7J;AACAtG;;AAEA;AACF;;AAMAZ;AACF;;AAEA;AAEA;AACF;;;AAIEgR;AACAA;AACAA;AAGAA;AACAA;AACAA;AACAA;AACAA;AACA;;AAGEhR;AACF;;AAEA;AACA;AACF;;AAGEA;AACAA;AACF;;AAEA;AACF;;ACrDO;;;AASH;AACF;AACA;AACEA;AACA;AACF;;AAGF;;ACXA;AAAQ4D;AAAkB;AAE1B;AACEC;AACApB;AAEAD;AACAsB;AACE;AACA;AACAkF;AACE1G;AACAG;;AAEFwO;AACE3O;AACAC;AACAE;;AAEFyO;AACE5O;AACAG;AACF;;AAEFE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;AAGEqF;AACAlG;AACAC;AACAkO;AACAC;;;AAIF;AACElR;;;AAGAA;AACAA;;AAEF;;;AAKIoE;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEA;AAOF;;ACnHO;AAOL;;AAEA;;AAEA;;AAEA;;AAGA;AAEA;AAEAA;AACA;AACEA;AAGAA;AAGF;AACEA;;AAEEA;AAGF;AACAA;;AAEEA;AAGF;AACF;;;AAIE;AACA;AACA;AACA;AACA;;AAEA;;;AAIA;AACEA;AACF;;AAKA;AAEA;AACEA;AACAA;;AAEF;AACA;;;AAGE;;AAEEA;AACAA;;AAEF;AACA;AACF;AACAA;AACAA;;AAIIA;AACA;AACF;AAEFA;AACAA;;;;AASA;AACEA;AACAA;;AAEF;AACF;AACF;AAEA;AAME;;AACQJ;AAAQ;;;AAIdA;;AAIE;AACA;AACA;AACA;;AAEF;AACAyE;;;;AACsB2G;AAAO;;;;AACNmG;;AACzB;AACE;AACEvR;AACF;AACEA;AACF;AACF;AACF;;ACxIA;AAAQgE;AAAkB;AAE1B;AACEC;AACApB;AAEAD;AACAsB;AACE;AACAsN;AACE9O;AACAG;;AAEFuG;AACE1G;AACAG;;AAEF4O;AACE/O;AACAC;AACAE;;AAGF6O;AACEhP;AACAC;AACAE;;AAEFyO;AACE5O;AACAG;AACF;;AAEFE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;AAIA;AACE3D;;;;;AAKF;;;AAIA;AACA;AACA;;;AAIImE;AACAC;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEF;AACE;AACF;;;AAE4C0E;;AAE5C;;AAEEhJ;AACAA;;AAEF;;AAGA;;AAKA;AAEA;AACEA;AACA;AACF;AAEA;AAOF;;AC1JO;AAOL;;AACQJ;AAAQ;AAChB;AACA;AAEA;AACEI;AACAA;AACAA;AACA;;AAEF;AACEA;AACAA;AACAA;AACA;;AAEF;;;;AAKE;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAIA;AACEA;AACAA;;AAEF;;;AAGEA;AACA;;AAEEA;AACAA;;AAEF;AACA;AACF;;;AAGEuR;AACA;AACF;AACA;;AAEEvR;AAGA;AACF;AACA;AACA;AACA;;AAEEA;;AAEAA;AACAA;AACF;;AAEEA;AAGAuR;AACAvR;AACA;AACF;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEAuR;AACAvR;AACF;;;;;AAQA;AACEA;AACAA;;AAEF;AACF;AACF;;AC5GA;AAAQ4D;AAAkB;AAE1B;AACEC;AACApB;AAEAD;AACAsB;AACE;AACAsN;AACE9O;AACAC;AACAE;;AAEFuG;AACE1G;AACAG;;AAEFwO;AACE3O;AACAC;AACAE;;AAGFuI;AACE1I;AACAG;;AAEF+O;AACElP;AACAC;AACAE;;AAEFyO;AACE5O;AACAG;AACF;;AAEFE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;AAIA;AACE3D;;;;;AAKF;;;AAIA;AACA;AACA;;;AAIImE;AACAC;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEF;AACE;AACF;;AAGA;AACE8M;AACF;;AAGA;AACEH;AACF;AACA;AACEA;AACF;AAEA;;AAEEjR;AACAA;AACAA;;AAEF;;AAGA;;AAKA;AAEA;AACEA;AACA;AACF;;AAGF;;AC/JA;AAAQ4D;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;AACAkF;AACE1G;AACAG;;AAEFyO;AACE5O;AACAC;AACAE;AACF;AACA;;AAEFE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;AAEA;AAEA;AACE3D;;;;AAIAA;;AAEF;;AAGA;AACEyR;AACF;;;AAKEzR;AACA;AACEyR;AACF;AACAA;AACA;AACEzR;AACA;AACF;AACA;AAAkD2D;AAAW;AAC7D;AACF;;AAGE3D;AACA;AACE;AACAyR;AACF;AACA;AACEzR;AACA;AACF;AACA;AAAmD2D;AAAW;AAC9D;AACF;;AAGA;;;;AAIE3D;AA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AACA;AACF;;;AAIIuP;AACA2E;AACE5M;AACA6M;;AAEAC;;AAEFC;;;;;;AAMED;AACF;AACF;;AAkDApU;AACAA;AACA;;AAIA;AACEA;AAGF;AACAA;AACA;AACEA;AAGF;AACEA;AAGAA;AACAA;AAGF;AACAA;AACA;AACE;AACAA;AAGAA;AACAA;AACAA;AACAA;AAGF;AACEA;AACAA;AACAA;AAGF;AACAA;AACAA;AACAA;AACAA;AACAA;;;;;;;AAOAA;AACAA;AACAA;;AAEEA;AACAA;AACAsU;AACEtU;AACF;AACF;AACEA;AACF;AACAA;AACAA;AACAA;;AAEE;AACEA;AACF;AACEA;AACF;AACAA;AACAA;AAGF;AACEA;AACF;AACAA;AACA;AACEA;AACAA;AACAA;AAGAA;AACAA;AACAA;AACAA;AAGAA;AAGAA;;;;;;;AAOAA;AACAA;AACAA;AACAA;AAGAA;;;;;;;AAOAA;AACAA;AACAA;;AAEEA;AAGAA;AACAmU;AACEnU;AACF;AACF;AACEA;AAGF;AACAA;AACAA;AACAA;;AAEEA;AACAA;;AASF;AACEA;AAGF;AACAA;AACF;AACA;AACF;AAEAA;AAGAA;AACAA;AACF;;AC/PO;AAIL;;AAEE;AACF;AAEA;AACF;;ACbA;AACA;AACA;AACA;AACO;;;;AAOHuU;;AAEA;AACE;;AAEEA;AACA;;AAEA;AACAC;AACF;;AAEA;AACF;AACA;AACED;AACF;AACF;AACE;AACAnC;AAEA;AACE;AACA;AACE;AACAmC;AACA;;AAEAC;AACF;AACEA;AACF;AACF;AAEA;AACED;AACF;AACF;;;AAEgBA;;AAClB;;ACtCA;AAAQ3Q;AAAkB;AAE1B;AACEC;AACApB;AAEAD;AACAsB;AACE;;;AAGFnB;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;AAEcZ;;;AAEd;;;AAEewR;AAAM;;AAIjBp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;AAA2B;AACxCW;AAAeX;AAA6B;AAC5CW;AAAqBX;AAAmC;AACxDW;AAAyBX;AAAuC;AAChEW;AAAmBX;AAAiC;AACpDW;AAAmBX;AAAiC;AACpDW;AAAqBX;;;;AAK7B;;AClDO;;;AAOH;AACF;AAEA;AACF;;ACDA;AAAQ9F;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;AACA;AACAwC;AACE7D;AACAF;AACAD;AACF;;AAEFK;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;;AAEwB2C;;AAExB;;AAEA;;AAII/B;;AAEAH;AACAC;AACAC;AACF;;AAGEF;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AAEAC;AACAC;AACF;AAEEC;;AAEAH;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEA;AAKF;;ACxGA;AAEO;;AAEL;AAA8B2D;AAAW;AACvC;AAEIqR;AACAC;AACAjL;AACAyL;AACAC;AACF;;;;;AAMA;AAEJ;AACF;;ACxBO;AACL;AACA;AAIA;AACA;;AAEE;AACEtR;AAEAqF;AAEI;;;AAGEtB;;;AAGJ;AAEEuB;AACAvB;AACA1F;;AAIN;AACA;AACE;AACF;AACF;AACEzC;AAGF;AACF;;ACzCO;AACL;AACA;AACA;AACEoE;AACAqF;AAEIC;AACAvB;AACA1F;AACF;AAEEiH;AACAvB;AACA1F;;AAIN;AACA;;AAEA;AACF;;ACTA;AAAQmB;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;AACA;AACAyC;AACEjE;AACAM;AACAL;AACAE;;AAEFqG;AACExG;AACAM;AACAL;AACAE;;AAEFsG;AACEzG;AACAM;AACAL;AACAE;;AAEFiE;AACEpE;AACAM;AACAL;AACAE;;AAEFuG;AACE1G;AACAG;;AAEFwG;AACE3G;AACAC;AACAE;;AAGFyG;AACE5G;AACAC;AACAE;;AAGF2G;AACE9G;AACAC;AACAE;;AAGF4G;AACE/G;AACAM;AACAH;;AAEF6G;AACEhH;AACAC;AACAE;;AAGFuB;AACE1B;AACAM;AACAL;AACAE;;AAEF8G;AACEjH;AACAC;AACAE;;AAGFiG;AACEpG;AACAM;AACAL;AACAE;AAEF;;AAEF;AACAE;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;;;;AAOEqF;;;AAGAE;;;;;;;;AAQAR;;AAmBF;;AAEA;AAEA;;AAKA;AACA;AACA;AACA;;AAEA;AACA;;;AAIE;;AAEAiN;AACF;;AAEA;AACA;AACA;AACA;;AAEI;AACA;AACEpL;AACF;AACAoL;AACF;AACF;AAEA;AACE3V;AAGAA;AACAA;AAGAA;AACF;;;AAKImE;AACAC;AACAC;AACAC;AAIF;AAEEH;AACAC;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEEC;;AAEAH;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEF;AACE;AACF;;AAEA;AACA;AACEtE;AACA;AACF;AAEA;AACE2I;;;;;AAKAM;AACAC;;;AAGAE;AACAC;AACAC;AACAhD;;;;AAIF;AACF;;AC7TO;AAIL;;AAEA;;AACQ1G;AAAQ;AAEhBA;AAEA;AAKAA;AAEA;AACEQ;AACF;;AAGF;;ACzBO;AAGLJ;AACF;;ACLO;;;AAMH;AACF;;AAGF;;ACAA;AAAQ4D;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;;;AAGFnB;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;AAEA;;AAEA;AACA;;;AAKIQ;AACAC;AACAC;AACAC;AAIF;;AAGEF;AACAC;AACAC;AACF;AAEEC;;AAEAH;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEA;AACF;;ACzFO;;;AAGLuK;AAKF;AACE;;AAEA;;AACQ3K;AAAQ;AAEhBI;AACAA;AAEAJ;;AAOAA;AAEA;;;AAGE;AACF;AAEA;AAOA;AACF;;ACxCA;AAGO;;;AAKHuJ;AAKF;AAEA;AACA;;AAIA;AACA;AACA;AACA;AACE;;;;;AAKE;AACAnJ;AACAA;AACA;AACF;AAEA;AACEA;AACAwK;AACE;AACExK;AACAA;AACF;AACEA;AACF;AACAA;AACF;AACF;AACE;AACAA;AACAA;AACAA;AACF;AAEA;AACF;;AAGEA;AACAA;AACAA;AACAA;AAGAA;AAGAA;;AAIAA;AACAA;AACAA;;AAIAA;;AAEEsF;AACEtF;AACF;;AAEEA;AACF;AACF;AACAA;;AAEEsF;AACEtF;AACF;;AAEEA;AACF;AACF;AACAA;;AAEEsF;AACEtF;AACF;;AAEEA;AACF;AACF;AACAA;;AAEEsF;AACEtF;AACF;;AAEEA;AACF;AACF;AACAA;;AAEEsF;AACEtF;AACF;;AAEEA;AACF;AACF;AACAA;;AAEAA;AACAA;AAGAA;AACA;AACE;AACE;AACF;AACA;;;AAKA;AACF;AACAA;;AAEAA;AACAA;AAGAA;AACA;AACE;AACE;AACF;AACA;;;AAKA;AACF;AACAA;AAEA;AACF;;AAEA;AACA;;AAEAA;;AAGIyK;AACApC;AACAqC;AACAC;AACF;AAEF3K;AAGAA;AACF;;ACxLO;;;;;;AAMLmJ;AAQF;AACE;;;AAGEoB;AACF;;AAEE;AACF;;;;AAKEpB;AACF;AACF;;ACnBA;AAAQvF;AAAkB;AAE1B;AAGA;AACEC;AACApB;AACAD;AACAsB;AACE;AACA;AACAuE;AACE/F;AACAC;AACAE;;AAGFsB;AACEzB;AACAM;AACAL;AACAE;AAEF;;AAEFE;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AA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ACAC;AACAC;AACAvN;AACAnI;AACAmB;AACAwU;AAAe;AACfC;AACErU;AACAiU;;AAEFK;AACA;AACA;AACAC;AACAC;AACF;;AAEA;AACA;AACA;AACEC;AACAL;AACAxU;AACAyU;AACErU;AACAiU;;AAEFxV;AACAiW;AAEAtV;AACE6U;AACF;AACF;;AAGErW;AAQAU;AACF;;AAEA;;AAGAE;AACAA;;AAEA;AACAmW;AACE;AACA;AACE;AACA;AACE;;;AAWF;AACF;AACF;;AAIAnW;AACE;;AAEA;AACAd;AACF;AACF;AAEA;AACE;;;AAGE;AAEA;;AAEA;;AASF;AACF;AAEA;AACE;AACA;;AAGEkX;AACAxV;AACF;AAEA;AACA;AACE;AACA;;;AAGA;AACF;;AAEE;AACF;AACE;AACF;AACF;;AClKO;;;;;;AAMLgD;AAQF;AACE;;;;;AAKEA;AACF;;AAEE;AACF;AAEA;AACE1E;AACA;AACF;;AAGEmJ;AACF;AACF;;AC7BA;AAAQvF;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;AACA;AACAY;AACEpC;AACAM;AACAL;AACAE;;AAEFoC;AACEvC;AACAM;AACAL;AACAE;;AAEF8S;AACEjT;AACAM;AACAL;AACAE;;AAEF0U;AACE7U;AACAM;AACAL;AACAE;;AAEFkD;AACErD;AACAM;AACAL;AACAE;AACF;;AAEFE;AACF;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;AAEcZ;;AACd;;AAEA;;AAIIwB;;AAEAH;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEEC;;AAEAH;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEA;;;;;;;AAOA;AACF;;AC3JO;;AAKD;AACE;AACF;AACA;AACA;;AAGN;AACA;AACA;AAEI;AAEJ;;ACpBO;;;;AASHA;AAGA;AACF;AACA;AACF;;ACRO;AACL;;;AACoBoX;AAAU;;;;AAOhC;;AAEA;;AAEA;AACE;AACF;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAGMhT;AACA7B;AACF;AAEA;;;AACoB6U;AAAU;;AAE5B;;AAEA;AACA;;AAEA;;;AAKF;AACF;AACF;;ACrDO;AACL;AACE;AACEpX;AACAA;AACA;AACF;;AAOA;;AAGE;AACEA;AACA;AACF;AACA;AACA;AACAA;AAGF;AACF;AACF;;ACfA;AAAQ4D;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;AACAuT;AACE/U;AACAC;AACAE;;AAEF6U;AACEhV;AACAC;AACAE;AACF;;AAEFE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;AAErC;AACA;;AAEE;AACF;;;;;AAMEA;AACF;;;AAEiB0T;;;AAIblT;AACAC;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;;AAEA;;;AACoBoX;AAAU;AAC9B;;;AAGE;;;AAGA;AACF;AACE;;AAEA;AACA;;AAEA;AACF;;AAEEpX;AACF;AACF;;AC7EA;AAAQuX;AAAoB;;AAE5B;AACA;AACE;AACE7N;AACA;AACArC;;AAEF;;AAGE;AAEImQ;AACAC;AACApV;AACAqV;AACAC;AACAC;AACAC;AACAC;AACAC;AACAC;AACAC;AACAC;AACAhF;AACA;AACA;AACA3J;AACA4O;AACAhR;AACA;AACAiR;AACA3L;AACA4L;AACA;AACA;AACAxQ;AACF;;;AAIE6B;AACAiI;AAAc/J;AAAoC;AACpD;;;AAIF;AACA;;;AAGE0Q;;AAEF;AACEA;;;AAGF;AACEA;AACAC;AACAC;AACF;AACEF;AACF;AACAtY;;AAEA;AACEF;AACF;;AAEF;AACF","debugId":"d3d3d563-0e77-4bef-aa59-13c56f702e16"}
|
|
1
|
+
{"version":3,"file":"cli.js","sources":["../../src/utils/fail-msg-with-badge.ts","../../src/utils/api.ts","../../src/commands/analytics/fetch-org-analytics.ts","../../src/commands/analytics/fetch-repo-analytics.ts","../../src/utils/markdown.ts","../../src/commands/analytics/display-analytics.ts","../../src/flags.ts","../../src/utils/handle-bad-input.ts","../../src/utils/output-formatting.ts","../../src/utils/meow-with-subcommands.ts","../../src/commands/analytics/cmd-analytics.ts","../../src/commands/audit-log/fetch-audit-log.ts","../../src/commands/audit-log/output-audit-log.ts","../../src/commands/audit-log/handle-audit-log.ts","../../src/commands/audit-log/cmd-audit-log.ts","../../src/commands/cdxgen/run-cyclonedx.ts","../../src/utils/cmd.ts","../../src/commands/cdxgen/cmd-cdxgen.ts","../../src/commands/ci/fetch-default-org-slug.ts","../../src/commands/scan/fetch-create-org-full-scan.ts","../../src/commands/scan/fetch-supported-scan-file-names.ts","../../src/commands/scan/fetch-report-data.ts","../../src/commands/scan/generate-report.ts","../../src/utils/map-to-object.ts","../../src/utils/walk-nested-map.ts","../../src/commands/scan/output-scan-report.ts","../../src/commands/scan/handle-scan-report.ts","../../src/commands/scan/output-create-new-scan.ts","../../src/commands/scan/handle-create-new-scan.ts","../../src/commands/ci/handle-ci.ts","../../src/commands/ci/cmd-ci.ts","../../src/commands/config/discover-config-value.ts","../../src/commands/config/output-config-auto.ts","../../src/commands/config/handle-config-auto.ts","../../src/commands/config/cmd-config-auto.ts","../../src/commands/config/output-config-get.ts","../../src/commands/config/handle-config-get.ts","../../src/commands/config/cmd-config-get.ts","../../src/commands/config/output-config-list.ts","../../src/commands/config/cmd-config-list.ts","../../src/commands/config/output-config-set.ts","../../src/commands/config/handle-config-set.ts","../../src/commands/config/cmd-config-set.ts","../../src/commands/config/output-config-unset.ts","../../src/commands/config/handle-config-unset.ts","../../src/commands/config/cmd-config-unset.ts","../../src/commands/config/cmd-config.ts","../../src/commands/dependencies/fetch-dependencies.ts","../../src/commands/dependencies/output-dependencies.ts","../../src/commands/dependencies/handle-dependencies.ts","../../src/commands/dependencies/cmd-dependencies.ts","../../src/commands/diff-scan/fetch-diff-scan.ts","../../src/commands/diff-scan/output-diff-scan.ts","../../src/commands/diff-scan/handle-diff-scan.ts","../../src/commands/diff-scan/cmd-diff-scan-get.ts","../../src/commands/diff-scan/cmd-diff-scan.ts","../../src/commands/fix/git.ts","../../src/commands/fix/open-pr.ts","../../src/commands/fix/npm-fix.ts","../../src/utils/npm.ts","../../src/utils/agent.ts","../../src/commands/fix/pnpm-fix.ts","../../src/commands/fix/shared.ts","../../src/utils/package-environment.ts","../../src/commands/fix/run-fix.ts","../../src/commands/fix/cmd-fix.ts","../../src/commands/info/fetch-package-info.ts","../../src/commands/info/output-package-info.ts","../../src/commands/info/handle-package-info.ts","../../src/commands/info/cmd-info.ts","../../src/commands/login/apply-login.ts","../../src/commands/login/attempt-login.ts","../../src/commands/login/cmd-login.ts","../../src/commands/logout/apply-logout.ts","../../src/commands/logout/attempt-logout.ts","../../src/commands/logout/cmd-logout.ts","../../src/commands/manifest/convert-conda-to-requirements.ts","../../src/commands/manifest/output-requirements.ts","../../src/commands/manifest/handle-manifest-conda.ts","../../src/commands/manifest/cmd-manifest-conda.ts","../../src/commands/manifest/convert_gradle_to_maven.ts","../../src/commands/manifest/cmd-manifest-gradle.ts","../../src/commands/manifest/convert_sbt_to_maven.ts","../../src/commands/manifest/cmd-manifest-scala.ts","../../src/commands/manifest/cmd-manifest-auto.ts","../../src/commands/manifest/cmd-manifest-kotlin.ts","../../src/commands/manifest/cmd-manifest.ts","../../src/commands/npm/wrap-npm.ts","../../src/commands/npm/cmd-npm.ts","../../src/commands/npx/wrap-npx.ts","../../src/commands/npx/cmd-npx.ts","../../src/commands/oops/cmd-oops.ts","../../src/commands/optimize/deps-includes-by-agent.ts","../../src/commands/optimize/get-dependency-entries.ts","../../src/commands/optimize/get-overrides-by-agent.ts","../../src/commands/optimize/lockfile-includes-by-agent.ts","../../src/commands/optimize/ls-by-agent.ts","../../src/commands/optimize/shared.ts","../../src/commands/optimize/update-manifest-by-agent.ts","../../src/commands/optimize/add-overrides.ts","../../src/commands/optimize/update-lockfile.ts","../../src/commands/optimize/apply-optimization.ts","../../src/commands/optimize/cmd-optimize.ts","../../src/commands/organization/fetch-organization-list.ts","../../src/commands/organization/output-organization-list.ts","../../src/commands/organization/handle-organization-list.ts","../../src/commands/organization/cmd-organization-list.ts","../../src/commands/organization/fetch-license-policy.ts","../../src/commands/organization/output-license-policy.ts","../../src/commands/organization/handle-license-policy.ts","../../src/commands/organization/cmd-organization-policy-license.ts","../../src/commands/organization/fetch-security-policy.ts","../../src/commands/organization/output-security-policy.ts","../../src/commands/organization/handle-security-policy.ts","../../src/commands/organization/cmd-organization-policy-security.ts","../../src/commands/organization/cmd-organization-policy.ts","../../src/commands/organization/fetch-quota.ts","../../src/commands/organization/output-quota.ts","../../src/commands/organization/handle-quota.ts","../../src/commands/organization/cmd-organization-quota.ts","../../src/commands/organization/cmd-organization.ts","../../src/commands/package/fetch-purl-deep-score.ts","../../src/commands/package/output-purl-score.ts","../../src/commands/package/handle-purl-deep-score.ts","../../src/commands/package/parse-package-specifiers.ts","../../src/commands/package/cmd-package-score.ts","../../src/commands/package/fetch-purls-shallow-score.ts","../../src/commands/package/output-purls-shallow-score.ts","../../src/commands/package/handle-purls-shallow-score.ts","../../src/commands/package/cmd-package-shallow.ts","../../src/commands/package/cmd-package.ts","../../src/commands/raw-npm/run-raw-npm.ts","../../src/commands/raw-npm/cmd-raw-npm.ts","../../src/commands/raw-npx/run-raw-npx.ts","../../src/commands/raw-npx/cmd-raw-npx.ts","../../src/commands/report/cmd-report-create.ts","../../src/commands/report/cmd-report-view.ts","../../src/commands/report/cmd-report.ts","../../src/commands/repos/fetch-create-repo.ts","../../src/commands/repos/output-create-repo.ts","../../src/commands/repos/handle-create-repo.ts","../../src/commands/repos/cmd-repos-create.ts","../../src/commands/repos/handle-delete-repo.ts","../../src/commands/repos/cmd-repos-del.ts","../../src/commands/repos/fetch-list-repos.ts","../../src/commands/repos/output-list-repos.ts","../../src/commands/repos/handle-list-repos.ts","../../src/commands/repos/cmd-repos-list.ts","../../src/commands/repos/fetch-update-repo.ts","../../src/commands/repos/output-update-repo.ts","../../src/commands/repos/handle-update-repo.ts","../../src/commands/repos/cmd-repos-update.ts","../../src/commands/repos/fetch-view-repo.ts","../../src/commands/repos/output-view-repo.ts","../../src/commands/repos/handle-view-repo.ts","../../src/commands/repos/cmd-repos-view.ts","../../src/commands/repos/cmd-repos.ts","../../src/commands/scan/suggest-org-slug.ts","../../src/commands/scan/suggest_target.ts","../../src/commands/scan/cmd-scan-create.ts","../../src/commands/scan/fetch-delete-org-full-scan.ts","../../src/commands/scan/output-delete-scan.ts","../../src/commands/scan/handle-delete-scan.ts","../../src/commands/scan/cmd-scan-del.ts","../../src/commands/scan/fetch-diff-scan.ts","../../src/commands/scan/output-diff-scan.ts","../../src/commands/scan/handle-diff-scan.ts","../../src/commands/scan/cmd-scan-diff.ts","../../src/commands/scan/fetch-list-scans.ts","../../src/commands/scan/output-list-scans.ts","../../src/commands/scan/handle-list-scans.ts","../../src/commands/scan/cmd-scan-list.ts","../../src/commands/scan/fetch-scan-metadata.ts","../../src/commands/scan/output-scan-metadata.ts","../../src/commands/scan/handle-scan-metadata.ts","../../src/commands/scan/cmd-scan-metadata.ts","../../src/commands/scan/cmd-scan-report.ts","../../src/commands/scan/fetch-scan.ts","../../src/commands/scan/output-scan-view.ts","../../src/commands/scan/handle-scan-view.ts","../../src/commands/scan/streamScan.ts","../../src/commands/scan/cmd-scan-view.ts","../../src/commands/scan/cmd-scan.ts","../../src/commands/threat-feed/fetch-threat-feed.ts","../../src/commands/threat-feed/output-threat-feed.ts","../../src/commands/threat-feed/handle-threat-feed.ts","../../src/commands/threat-feed/cmd-threat-feed.ts","../../src/commands/wrapper/add-socket-wrapper.ts","../../src/commands/wrapper/check-socket-wrapper-setup.ts","../../src/commands/wrapper/postinstall-wrapper.ts","../../src/commands/wrapper/remove-socket-wrapper.ts","../../src/commands/wrapper/cmd-wrapper.ts","../../src/cli.ts"],"sourcesContent":["import colors from 'yoctocolors-cjs'\n\nexport function failMsgWithBadge(badge: string, msg: string): string {\n return `${colors.bgRed(colors.bold(colors.white(` ${badge}: `)))} ${colors.bold(msg)}`\n}\n","import process from 'node:process'\n\nimport { debugLog } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { isNonEmptyString } from '@socketsecurity/registry/lib/strings'\n\nimport { getConfigValue } from './config'\nimport { AuthError } from './errors'\nimport constants from '../constants'\nimport { failMsgWithBadge } from './fail-msg-with-badge'\n\nimport type {\n SocketSdkErrorType,\n SocketSdkOperations\n} from '@socketsecurity/sdk'\n\nexport function handleUnsuccessfulApiResponse<T extends SocketSdkOperations>(\n _name: T,\n sockSdkError: SocketSdkErrorType<T>\n): never {\n const message = sockSdkError.error || 'No error message returned'\n const { status } = sockSdkError\n if (status === 401 || status === 403) {\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.stop()\n\n throw new AuthError(message)\n }\n logger.fail(failMsgWithBadge('Socket API returned an error', message))\n // eslint-disable-next-line n/no-process-exit\n process.exit(1)\n}\n\nexport async function handleApiCall<T>(\n value: T,\n description: string\n): Promise<T> {\n let result: T\n try {\n result = await value\n } catch (e) {\n debugLog(`handleApiCall[${description}] error:\\n`, e)\n throw new Error(`Failed ${description}`, { cause: e })\n }\n return result\n}\n\nexport async function handleApiError(code: number) {\n if (code === 400) {\n return 'One of the options passed might be incorrect'\n }\n if (code === 403) {\n return 'Your API token may not have the required permissions for this command or you might be trying to access (data from) an organization that is not linked to the API key you are logged in with'\n }\n if (code === 404) {\n return 'The requested Socket API endpoint was not found (404) or there was no result for the requested parameters. This could be a temporary problem caused by an incident or a bug in the CLI. If the problem persists please let us know.'\n }\n return `Server responded with status code ${code}`\n}\n\nexport function getLastFiveOfApiToken(token: string): string {\n // Get the last 5 characters of the API token before the trailing \"_api\".\n return token.slice(-9, -4)\n}\n\n// The API server that should be used for operations.\nexport function getDefaultApiBaseUrl(): string | undefined {\n const baseUrl =\n process.env['SOCKET_SECURITY_API_BASE_URL'] || getConfigValue('apiBaseUrl')\n if (isNonEmptyString(baseUrl)) {\n return baseUrl\n }\n // Lazily access constants.API_V0_URL.\n const API_V0_URL = constants.API_V0_URL\n return API_V0_URL\n}\n\nexport async function queryApi(path: string, apiToken: string) {\n const API_V0_URL = getDefaultApiBaseUrl() || ''\n if (!API_V0_URL) {\n logger.warn(\n 'API endpoint is not set and default was empty. Request is likely to fail.'\n )\n }\n return await fetch(\n `${API_V0_URL}${API_V0_URL.endsWith('/') ? '' : '/'}${path}`,\n {\n method: 'GET',\n headers: {\n Authorization: `Basic ${btoa(`${apiToken}:`)}`\n }\n }\n )\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { Spinner } from '@socketsecurity/registry/lib/spinner'\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchOrgAnalyticsData(\n time: number,\n spinner: Spinner\n): Promise<SocketSdkReturnType<'getOrgAnalytics'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n const result = await handleApiCall(\n sockSdk.getOrgAnalytics(time.toString()),\n 'fetching analytics data'\n )\n\n if (result.success === false) {\n handleUnsuccessfulApiResponse('getOrgAnalytics', result)\n }\n\n spinner.stop()\n\n if (!result.data.length) {\n logger.log('No analytics data is available for this organization yet.')\n return\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { Spinner } from '@socketsecurity/registry/lib/spinner'\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchRepoAnalyticsData(\n repo: string,\n time: number,\n spinner: Spinner\n): Promise<SocketSdkReturnType<'getRepoAnalytics'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n const result = await handleApiCall(\n sockSdk.getRepoAnalytics(repo, time.toString()),\n 'fetching analytics data'\n )\n\n if (result.success === false) {\n handleUnsuccessfulApiResponse('getRepoAnalytics', result)\n }\n\n spinner.stop()\n\n if (!result.data.length) {\n logger.log('No analytics data is available for this organization yet.')\n return\n }\n\n return result.data\n}\n","export function mdTableStringNumber(\n title1: string,\n title2: string,\n obj: Record<string, number | string>\n): string {\n // | Date | Counts |\n // | ----------- | ------ |\n // | Header | 201464 |\n // | Paragraph | 18 |\n let mw1 = title1.length\n let mw2 = title2.length\n for (const [key, value] of Object.entries(obj)) {\n mw1 = Math.max(mw1, key.length)\n mw2 = Math.max(mw2, String(value ?? '').length)\n }\n\n const lines = []\n lines.push(`| ${title1.padEnd(mw1, ' ')} | ${title2.padEnd(mw2)} |`)\n lines.push(`| ${'-'.repeat(mw1)} | ${'-'.repeat(mw2)} |`)\n for (const [key, value] of Object.entries(obj)) {\n lines.push(\n `| ${key.padEnd(mw1, ' ')} | ${String(value ?? '').padStart(mw2, ' ')} |`\n )\n }\n lines.push(`| ${'-'.repeat(mw1)} | ${'-'.repeat(mw2)} |`)\n\n return lines.join('\\n')\n}\n\nexport function mdTable<T extends Array<Record<string, string>>>(\n logs: T,\n // This is saying \"an array of strings and the strings are a valid key of elements of T\"\n // In turn, T is defined above as the audit log event type from our OpenAPI docs.\n cols: Array<string & keyof T[number]>,\n titles: string[] = cols\n): string {\n // Max col width required to fit all data in that column\n const cws = cols.map(col => col.length)\n\n for (const log of logs) {\n for (let i = 0, { length } = cols; i < length; i += 1) {\n // @ts-ignore\n const val: unknown = log[cols[i] ?? ''] ?? ''\n cws[i] = Math.max(\n cws[i] ?? 0,\n String(val).length,\n (titles[i] || '').length\n )\n }\n }\n\n let div = '|'\n for (const cw of cws) {\n div += ' ' + '-'.repeat(cw) + ' |'\n }\n\n let header = '|'\n for (let i = 0, { length } = titles; i < length; i += 1) {\n header += ' ' + String(titles[i]).padEnd(cws[i] ?? 0, ' ') + ' |'\n }\n\n let body = ''\n for (const log of logs) {\n body += '|'\n for (let i = 0, { length } = cols; i < length; i += 1) {\n // @ts-ignore\n const val: unknown = log[cols[i] ?? ''] ?? ''\n body += ' ' + String(val).padEnd(cws[i] ?? 0, ' ') + ' |'\n }\n body += '\\n'\n }\n\n return [div, header, div, body.trim(), div].filter(s => !!s.trim()).join('\\n')\n}\n\nexport function mdTableOfPairs(\n arr: Array<[string, string]>,\n // This is saying \"an array of strings and the strings are a valid key of elements of T\"\n // In turn, T is defined above as the audit log event type from our OpenAPI docs.\n cols: string[]\n): string {\n // Max col width required to fit all data in that column\n const cws = cols.map(col => col.length)\n\n for (const [key, val] of arr) {\n cws[0] = Math.max(cws[0] ?? 0, String(key).length)\n cws[1] = Math.max(cws[1] ?? 0, String(val ?? '').length)\n }\n\n let div = '|'\n for (const cw of cws) {\n div += ' ' + '-'.repeat(cw) + ' |'\n }\n\n let header = '|'\n for (let i = 0, { length } = cols; i < length; i += 1) {\n header += ' ' + String(cols[i]).padEnd(cws[i] ?? 0, ' ') + ' |'\n }\n\n let body = ''\n for (const [key, val] of arr) {\n body += '|'\n body += ' ' + String(key).padEnd(cws[0] ?? 0, ' ') + ' |'\n body += ' ' + String(val ?? '').padEnd(cws[1] ?? 0, ' ') + ' |'\n body += '\\n'\n }\n\n return [div, header, div, body.trim(), div].filter(s => !!s.trim()).join('\\n')\n}\n","import fs from 'node:fs/promises'\n\nimport { codeBlock } from 'common-tags'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { fetchOrgAnalyticsData } from './fetch-org-analytics'\nimport { fetchRepoAnalyticsData } from './fetch-repo-analytics'\nimport constants from '../../constants'\nimport { mdTableStringNumber } from '../../utils/markdown'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\nimport type { Widgets } from 'blessed' // Note: Widgets does not seem to actually work as code :'(\nimport type { grid as ContribGrid } from 'blessed-contrib'\n\ninterface FormattedData {\n top_five_alert_types: Record<string, number>\n total_critical_alerts: Record<string, number>\n total_high_alerts: Record<string, number>\n total_medium_alerts: Record<string, number>\n total_low_alerts: Record<string, number>\n total_critical_added: Record<string, number>\n total_medium_added: Record<string, number>\n total_low_added: Record<string, number>\n total_high_added: Record<string, number>\n total_critical_prevented: Record<string, number>\n total_high_prevented: Record<string, number>\n total_medium_prevented: Record<string, number>\n total_low_prevented: Record<string, number>\n}\n\nconst METRICS = [\n 'total_critical_alerts',\n 'total_high_alerts',\n 'total_medium_alerts',\n 'total_low_alerts',\n 'total_critical_added',\n 'total_medium_added',\n 'total_low_added',\n 'total_high_added',\n 'total_critical_prevented',\n 'total_high_prevented',\n 'total_medium_prevented',\n 'total_low_prevented'\n] as const\n\n// Note: This maps `new Date(date).getMonth()` to English three letters\nconst Months = [\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'May',\n 'Jun',\n 'Jul',\n 'Aug',\n 'Sep',\n 'Oct',\n 'Nov',\n 'Dec'\n] as const\n\nexport async function displayAnalytics({\n filePath,\n outputKind,\n repo,\n scope,\n time\n}: {\n scope: string\n time: number\n repo: string\n outputKind: 'json' | 'markdown' | 'print'\n filePath: string\n}): Promise<void> {\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching analytics data')\n\n let data:\n | undefined\n | SocketSdkReturnType<'getOrgAnalytics'>['data']\n | SocketSdkReturnType<'getRepoAnalytics'>['data']\n if (scope === 'org') {\n data = await fetchOrgAnalyticsData(time, spinner)\n } else if (repo) {\n data = await fetchRepoAnalyticsData(repo, time, spinner)\n }\n\n // A message should already have been printed if we have no data here\n if (!data) {\n return\n }\n\n if (outputKind === 'json') {\n const serialized = renderJson(data)\n if (!serialized) {\n return\n }\n\n if (filePath && filePath !== '-') {\n try {\n await fs.writeFile(filePath, serialized, 'utf8')\n logger.log(`Data successfully written to ${filePath}`)\n } catch (e) {\n process.exitCode = 1\n logger.fail('There was an error trying to write the json to disk')\n logger.error(e)\n }\n } else {\n logger.log(serialized)\n }\n } else {\n const fdata = scope === 'org' ? formatDataOrg(data) : formatDataRepo(data)\n\n if (outputKind === 'markdown') {\n const serialized = renderMarkdown(fdata, time, repo)\n\n if (filePath && filePath !== '-') {\n try {\n await fs.writeFile(filePath, serialized, 'utf8')\n logger.log(`Data successfully written to ${filePath}`)\n } catch (e) {\n logger.error(e)\n }\n } else {\n logger.log(serialized)\n }\n } else {\n displayAnalyticsScreen(fdata)\n }\n }\n}\n\nfunction renderJson(data: unknown): string | undefined {\n try {\n return JSON.stringify(data, null, 2)\n } catch (e) {\n process.exitCode = 1\n // This could be caused by circular references, which is an \"us\" problem\n logger.fail(\n 'There was a problem converting the data set to JSON. Please try without --json or with --markdown'\n )\n return\n }\n}\n\nfunction renderMarkdown(\n data: FormattedData,\n days: number,\n repoSlug: string\n): string {\n return codeBlock`\n# Socket Alert Analytics\n\nThese are the Socket.dev stats are analytics for the ${repoSlug ? `${repoSlug} repo` : 'org'} of the past ${days} days\n\n${[\n [\n 'Total critical alerts',\n mdTableStringNumber('Date', 'Counts', data['total_critical_alerts'])\n ],\n [\n 'Total high alerts',\n mdTableStringNumber('Date', 'Counts', data['total_high_alerts'])\n ],\n [\n 'Total critical alerts added to the main branch',\n mdTableStringNumber('Date', 'Counts', data['total_critical_added'])\n ],\n [\n 'Total high alerts added to the main branch',\n mdTableStringNumber('Date', 'Counts', data['total_high_added'])\n ],\n [\n 'Total critical alerts prevented from the main branch',\n mdTableStringNumber('Date', 'Counts', data['total_critical_prevented'])\n ],\n [\n 'Total high alerts prevented from the main branch',\n mdTableStringNumber('Date', 'Counts', data['total_high_prevented'])\n ],\n [\n 'Total medium alerts prevented from the main branch',\n mdTableStringNumber('Date', 'Counts', data['total_medium_prevented'])\n ],\n [\n 'Total low alerts prevented from the main branch',\n mdTableStringNumber('Date', 'Counts', data['total_low_prevented'])\n ]\n]\n .map(\n ([title, table]) =>\n codeBlock`\n## ${title}\n\n${table}\n`\n )\n .join('\\n\\n')}\n\n## Top 5 alert types\n\n${mdTableStringNumber('Name', 'Counts', data['top_five_alert_types'])}\n`\n}\n\nfunction displayAnalyticsScreen(data: FormattedData): void {\n const ScreenWidget = require('blessed/lib/widgets/screen')\n // Lazily access constants.blessedOptions.\n const screen: Widgets.Screen = new ScreenWidget({\n ...constants.blessedOptions\n })\n const contrib = require('blessed-contrib')\n const grid = new contrib.grid({ rows: 5, cols: 4, screen })\n\n renderLineCharts(\n grid,\n screen,\n 'Total critical alerts',\n [0, 0, 1, 2],\n data['total_critical_alerts']\n )\n renderLineCharts(\n grid,\n screen,\n 'Total high alerts',\n [0, 2, 1, 2],\n data['total_high_alerts']\n )\n renderLineCharts(\n grid,\n screen,\n 'Total critical alerts added to the main branch',\n [1, 0, 1, 2],\n data['total_critical_added']\n )\n renderLineCharts(\n grid,\n screen,\n 'Total high alerts added to the main branch',\n [1, 2, 1, 2],\n data['total_high_added']\n )\n renderLineCharts(\n grid,\n screen,\n 'Total critical alerts prevented from the main branch',\n [2, 0, 1, 2],\n data['total_critical_prevented']\n )\n renderLineCharts(\n grid,\n screen,\n 'Total high alerts prevented from the main branch',\n [2, 2, 1, 2],\n data['total_high_prevented']\n )\n renderLineCharts(\n grid,\n screen,\n 'Total medium alerts prevented from the main branch',\n [3, 0, 1, 2],\n data['total_medium_prevented']\n )\n renderLineCharts(\n grid,\n screen,\n 'Total low alerts prevented from the main branch',\n [3, 2, 1, 2],\n data['total_low_prevented']\n )\n\n const bar = grid.set(4, 0, 1, 2, contrib.bar, {\n label: 'Top 5 alert types',\n barWidth: 10,\n barSpacing: 17,\n xOffset: 0,\n maxHeight: 9,\n barBgColor: 'magenta'\n })\n\n screen.append(bar) //must append before setting data\n\n bar.setData({\n titles: Object.keys(data.top_five_alert_types),\n data: Object.values(data.top_five_alert_types)\n })\n\n screen.render()\n // eslint-disable-next-line n/no-process-exit\n screen.key(['escape', 'q', 'C-c'], () => process.exit(0))\n}\n\nfunction formatDataRepo(\n data: SocketSdkReturnType<'getRepoAnalytics'>['data']\n): FormattedData {\n const sortedTopFiveAlerts: Record<string, number> = {}\n const totalTopAlerts: Record<string, number> = {}\n\n const formattedData = {} as Omit<FormattedData, 'top_five_alert_types'>\n for (const metric of METRICS) {\n formattedData[metric] = {}\n }\n\n for (const entry of data) {\n const topFiveAlertTypes = entry['top_five_alert_types']\n for (const type of Object.keys(topFiveAlertTypes)) {\n const count = topFiveAlertTypes[type] ?? 0\n if (!totalTopAlerts[type]) {\n totalTopAlerts[type] = count\n } else if (count > (totalTopAlerts[type] ?? 0)) {\n totalTopAlerts[type] = count\n }\n }\n }\n for (const entry of data) {\n for (const metric of METRICS) {\n formattedData[metric]![formatDate(entry['created_at'])] = entry[metric]\n }\n }\n\n const topFiveAlertEntries = Object.entries(totalTopAlerts)\n .sort(([_keya, a], [_keyb, b]) => b - a)\n .slice(0, 5)\n for (const [key, value] of topFiveAlertEntries) {\n sortedTopFiveAlerts[key] = value\n }\n\n return {\n ...formattedData,\n top_five_alert_types: sortedTopFiveAlerts\n }\n}\n\nfunction formatDataOrg(\n data: SocketSdkReturnType<'getOrgAnalytics'>['data']\n): FormattedData {\n const sortedTopFiveAlerts: Record<string, number> = {}\n const totalTopAlerts: Record<string, number> = {}\n\n const formattedData = {} as Omit<FormattedData, 'top_five_alert_types'>\n for (const metric of METRICS) {\n formattedData[metric] = {}\n }\n\n for (const entry of data) {\n const topFiveAlertTypes = entry['top_five_alert_types']\n for (const type of Object.keys(topFiveAlertTypes)) {\n const count = topFiveAlertTypes[type] ?? 0\n if (!totalTopAlerts[type]) {\n totalTopAlerts[type] = count\n } else {\n totalTopAlerts[type] += count\n }\n }\n }\n\n for (const metric of METRICS) {\n const formatted = formattedData[metric]\n for (const entry of data) {\n const date = formatDate(entry['created_at'])\n if (!formatted[date]) {\n formatted[date] = entry[metric]!\n } else {\n formatted[date] += entry[metric]!\n }\n }\n }\n\n const topFiveAlertEntries = Object.entries(totalTopAlerts)\n .sort(([_keya, a], [_keyb, b]) => b - a)\n .slice(0, 5)\n for (const [key, value] of topFiveAlertEntries) {\n sortedTopFiveAlerts[key] = value\n }\n\n return {\n ...formattedData,\n top_five_alert_types: sortedTopFiveAlerts\n }\n}\n\nfunction formatDate(date: string): string {\n return `${Months[new Date(date).getMonth()]} ${new Date(date).getDate()}`\n}\n\nfunction renderLineCharts(\n grid: ContribGrid,\n screen: Widgets.Screen,\n title: string,\n coords: number[],\n data: Record<string, number>\n): void {\n const contrib = require('blessed-contrib')\n const line = grid.set(...coords, contrib.line, {\n style: { line: 'cyan', text: 'cyan', baseline: 'black' },\n xLabelPadding: 0,\n xPadding: 0,\n xOffset: 0,\n wholeNumbersOnly: true,\n legend: {\n width: 1\n },\n label: title\n })\n\n screen.append(line)\n\n const lineData = {\n x: Object.keys(data),\n y: Object.values(data)\n }\n\n line.setData([lineData])\n}\n","import type { Flag } from 'meow'\n\n// TODO: not sure if I'm missing something but meow doesn't seem to expose this?\ntype StringFlag = Flag<'string', string> | Flag<'string', string[], true>\ntype BooleanFlag = Flag<'boolean', boolean> | Flag<'boolean', boolean[], true>\ntype NumberFlag = Flag<'number', number> | Flag<'number', number[], true>\ntype AnyFlag = StringFlag | BooleanFlag | NumberFlag\n\n// Note: we use this description in getFlagListOutput, meow doesn't care\nexport type MeowFlags = Record<\n string,\n AnyFlag & { description: string; hidden?: boolean }\n>\n\nexport const commonFlags: MeowFlags = {\n config: {\n type: 'string',\n default: '',\n hidden: true,\n description: 'Override the local config with this JSON'\n },\n dryRun: {\n type: 'boolean',\n default: false,\n hidden: true, // Only show in root command\n description: 'Do input validation for a command and exit 0 when input is ok'\n },\n help: {\n type: 'boolean',\n default: false,\n shortFlag: 'h',\n description: 'Print this help'\n },\n silent: {\n type: 'boolean',\n default: false,\n hidden: true,\n shortFlag: 's',\n description: 'Make the CLI less chatty'\n }\n}\n\nexport const outputFlags: MeowFlags = {\n json: {\n type: 'boolean',\n shortFlag: 'j',\n default: false,\n description: 'Output result as json'\n },\n markdown: {\n type: 'boolean',\n shortFlag: 'm',\n default: false,\n description: 'Output result as markdown'\n }\n}\n\nexport const validationFlags: MeowFlags = {\n all: {\n type: 'boolean',\n default: false,\n description: 'Include all issues'\n },\n strict: {\n type: 'boolean',\n default: false,\n description: 'Exits with an error code if any matching issues are found'\n }\n}\n","import colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { failMsgWithBadge } from './fail-msg-with-badge'\n\nexport function handleBadInput(\n ...checks: Array<{\n fail: string\n message: string\n pass: string\n test: boolean\n nook?: boolean | undefined\n }>\n) {\n if (checks.every(d => d.test)) {\n return false\n }\n\n const msg = [\n failMsgWithBadge(\n 'Input error',\n 'Please review the input requirements and try again'\n ),\n ''\n ]\n for (const d of checks) {\n // If nook, then ignore when test is ok\n if (d.nook && d.test) {\n continue\n }\n const lines = d.message.split('\\n')\n\n // If the message has newlines then format the first line with the input\n // expectation and teh rest indented below it\n msg.push(\n ` - ${lines[0]} (${d.test ? colors.green(d.pass) : colors.red(d.fail)})`\n )\n if (lines.length > 1) {\n msg.push(...lines.slice(1).map(str => ` ${str}`))\n }\n msg.push('')\n }\n\n logger.fail(msg.join('\\n'))\n\n // Use exit status of 2 to indicate incorrect usage, generally invalid\n // options or missing arguments.\n // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html\n process.exitCode = 2\n\n return true\n}\n","import type { MeowFlags } from '../flags'\n\ntype HelpListOptions = {\n keyPrefix: string\n padName: number\n}\n\ntype ListDescription =\n | { description: string }\n | { description: string; hidden: boolean }\n\nexport function getFlagListOutput(\n list: MeowFlags,\n indent: number,\n { keyPrefix = '--', padName } = {} as HelpListOptions\n): string {\n return getHelpListOutput(\n {\n ...list\n },\n indent,\n { keyPrefix, padName }\n )\n}\n\nexport function getHelpListOutput(\n list: Record<string, ListDescription>,\n indent: number,\n { keyPrefix = '', padName = 18 } = {} as HelpListOptions\n): string {\n let result = ''\n const names = Object.keys(list).sort()\n for (const name of names) {\n const entry = list[name]\n if (entry && 'hidden' in entry && entry?.hidden) {\n continue\n }\n const description =\n (typeof entry === 'object' ? entry.description : entry) || ''\n result +=\n ''.padEnd(indent) +\n (keyPrefix + name).padEnd(padName) +\n description +\n '\\n'\n }\n return result.trim() || '(none)'\n}\n","import path from 'node:path'\nimport process from 'node:process'\n\nimport meow from 'meow'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { toSortedObject } from '@socketsecurity/registry/lib/objects'\nimport { normalizePath } from '@socketsecurity/registry/lib/path'\nimport { escapeRegExp } from '@socketsecurity/registry/lib/regexps'\n\nimport { getLastFiveOfApiToken } from './api'\nimport {\n getConfigValue,\n isReadOnlyConfig,\n overrideCachedConfig,\n overrideConfigApiToken\n} from './config'\nimport { getFlagListOutput, getHelpListOutput } from './output-formatting'\nimport constants from '../constants'\nimport { MeowFlags, commonFlags } from '../flags'\nimport { getDefaultToken } from './sdk'\n\nimport type { Options } from 'meow'\n\nconst { DRY_RUN_LABEL, REDACTED } = constants\n\ninterface CliAlias {\n description: string\n argv: readonly string[]\n hidden?: boolean | undefined\n}\n\ntype CliAliases = Record<string, CliAlias>\n\ntype CliSubcommandRun = (\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n context: { parentName: string }\n) => Promise<void> | void\n\nexport interface CliSubcommand {\n description: string\n hidden?: boolean | undefined\n run: CliSubcommandRun\n}\n\n// Property names are picked such that the name is at the top when the props\n// get ordered by alphabet while flags is near the bottom and the help text\n// at the bottom, because they tend ot occupy the most lines of code.\nexport interface CliCommandConfig {\n commandName: string // tmp optional while we migrate\n description: string\n hidden: boolean\n flags: MeowFlags // tmp optional while we migrate\n help: (command: string, config: CliCommandConfig) => string\n}\n\ninterface MeowOptions extends Options<any> {\n aliases?: CliAliases | undefined\n argv: readonly string[]\n name: string\n // When no sub-command is given, default to this sub-command\n defaultSub?: string\n}\n\n// For debugging. Whenever you call meowOrExit it will store the command here\n// This module exports a getter that returns the current value.\nlet lastSeenCommand = ''\n\nexport function getLastSeenCommand(): string {\n return lastSeenCommand\n}\n\nexport async function meowWithSubcommands(\n subcommands: Record<string, CliSubcommand>,\n options: MeowOptions\n): Promise<void> {\n const {\n aliases = {},\n argv,\n defaultSub,\n importMeta,\n name,\n ...additionalOptions\n } = { __proto__: null, ...options }\n const [commandOrAliasName_, ...rawCommandArgv] = argv\n let commandOrAliasName = commandOrAliasName_\n if (!commandOrAliasName && defaultSub) {\n commandOrAliasName = defaultSub\n }\n\n const flags: MeowFlags = {\n ...commonFlags,\n ...additionalOptions.flags\n }\n\n // No further args or first arg is a flag (shrug)\n if (\n name === 'socket' &&\n (!commandOrAliasName || commandOrAliasName?.startsWith('-'))\n ) {\n flags['dryRun'] = {\n type: 'boolean',\n default: false,\n hidden: false, // Only show on root\n description:\n 'Do input validation for a command and exit 0 when input is ok. Every command should support this flag (not shown on help screens)'\n }\n }\n\n const cli = meow(\n `\n Usage\n $ ${name} <command>\n\n Commands\n ${getHelpListOutput(\n {\n ...toSortedObject(\n Object.fromEntries(\n Object.entries(subcommands).filter(\n ({ 1: subcommand }) => !subcommand.hidden\n )\n )\n ),\n ...toSortedObject(\n Object.fromEntries(\n Object.entries(aliases).filter(({ 1: alias }) => {\n const { hidden } = alias\n const cmdName = hidden ? '' : alias.argv[0]\n const subcommand = cmdName ? subcommands[cmdName] : undefined\n return subcommand && !subcommand.hidden\n })\n )\n )\n },\n 6\n )}\n\n Options\n ${getFlagListOutput(flags, 6)}\n\n Examples\n $ ${name} --help\n `,\n {\n argv,\n importMeta,\n ...additionalOptions,\n flags,\n // Do not strictly check for flags here.\n allowUnknownFlags: true,\n // We will emit help when we're ready\n // Plus, if we allow this then meow() can just exit here.\n autoHelp: false\n }\n )\n\n // Hard override the config if instructed to do so.\n // The env var overrides the --flag, which overrides the persisted config\n // Also, when either of these are used, config updates won't persist.\n let configOverrideResult\n if (process.env['SOCKET_CLI_CONFIG']) {\n configOverrideResult = overrideCachedConfig(\n process.env['SOCKET_CLI_CONFIG']\n )\n } else if (cli.flags['config']) {\n configOverrideResult = overrideCachedConfig(\n String(cli.flags['config'] || '')\n )\n }\n\n if (process.env['SOCKET_CLI_NO_API_TOKEN']) {\n // This overrides the config override and even the explicit token env var.\n // The config will be marked as readOnly to prevent persisting it.\n overrideConfigApiToken(undefined)\n } else {\n // Note: these are SOCKET_SECURITY prefixed because they're not specific to\n // the CLI. For the sake of consistency we'll also support the env\n // keys that do have the SOCKET_CLI prefix, it's an easy mistake.\n // In case multiple are supplied, the tokens supersede the keys and the\n // security prefix supersedes the cli prefix. \"Adventure mode\" ;)\n const tokenOverride =\n process.env['SOCKET_CLI_API_KEY'] ||\n process.env['SOCKET_SECURITY_API_KEY'] ||\n process.env['SOCKET_CLI_API_TOKEN'] ||\n process.env['SOCKET_SECURITY_API_TOKEN']\n if (tokenOverride) {\n // This will set the token (even if there was a config override) and\n // set it to readOnly, making sure the temp token won't be persisted.\n overrideConfigApiToken(tokenOverride)\n }\n }\n\n if (configOverrideResult?.ok === false) {\n emitBanner(name)\n logger.fail(configOverrideResult.message)\n process.exitCode = 2\n return\n }\n\n // If we got at least some args, then lets find out if we can find a command.\n if (commandOrAliasName) {\n const alias = aliases[commandOrAliasName]\n // First: Resolve argv data from alias if its an alias that's been given.\n const [commandName, ...commandArgv] = alias\n ? [...alias.argv, ...rawCommandArgv]\n : [commandOrAliasName, ...rawCommandArgv]\n // Second: Find a command definition using that data.\n const commandDefinition = commandName ? subcommands[commandName] : undefined\n // Third: If a valid command has been found, then we run it...\n if (commandDefinition) {\n return await commandDefinition.run(commandArgv, importMeta, {\n parentName: name\n })\n }\n }\n\n // ...else we provide basic instructions and help.\n if (!cli.flags['silent']) {\n emitBanner(name)\n }\n if (!cli.flags['help'] && cli.flags['dryRun']) {\n process.exitCode = 0\n logger.log(`${DRY_RUN_LABEL}: No-op, call a sub-command; ok`)\n } else {\n cli.showHelp()\n }\n}\n\n/**\n * Note: meow will exit immediately if it calls its .showHelp()\n */\nexport function meowOrExit({\n allowUnknownFlags, // commands that pass-through args need to allow this\n argv,\n config,\n importMeta,\n parentName\n}: {\n allowUnknownFlags?: boolean | undefined\n argv: readonly string[]\n config: CliCommandConfig\n parentName: string\n importMeta: ImportMeta\n}) {\n const command = `${parentName} ${config.commandName}`\n lastSeenCommand = command\n\n // This exits if .printHelp() is called either by meow itself or by us.\n const cli = meow({\n argv,\n description: config.description,\n help: config.help(command, config),\n importMeta,\n flags: config.flags,\n allowUnknownFlags: Boolean(allowUnknownFlags),\n autoHelp: false // otherwise we can't exit(0)\n })\n\n if (!cli.flags['silent']) {\n emitBanner(command)\n }\n if (cli.flags['help']) {\n cli.showHelp()\n }\n return cli\n}\n\nexport function emitBanner(name: string) {\n // Print a banner at the top of each command.\n // This helps with brand recognition and marketing.\n // It also helps with debugging since it contains version and command details.\n // Note: print over stderr to preserve stdout for flags like --json and\n // --markdown. If we don't do this, you can't use --json in particular\n // and pipe the result to other tools. By emitting the banner over stderr\n // you can do something like `socket scan view xyz | jq | process`.\n // The spinner also emits over stderr for example.\n logger.error(getAsciiHeader(name))\n}\n\nfunction getAsciiHeader(command: string) {\n // Note: In tests we return <redacted> because otherwise snapshots will fail.\n // The '@rollup/plugin-replace' will replace \"process.env['VITEST']\".\n const redacting = process.env['VITEST']\n const cliVersion = redacting\n ? REDACTED\n : // The '@rollup/plugin-replace' will replace \"process.env['INLINED_SOCKET_CLI_VERSION_HASH']\".\n process.env['INLINED_SOCKET_CLI_VERSION_HASH']\n const nodeVersion = redacting ? REDACTED : process.version\n const apiToken = getDefaultToken()\n const defaultOrg = getConfigValue('defaultOrg')\n const readOnlyConfig = isReadOnlyConfig() ? '*' : '.'\n const shownToken = redacting\n ? REDACTED\n : apiToken\n ? getLastFiveOfApiToken(apiToken)\n : 'no'\n const relCwd = redacting\n ? REDACTED\n : normalizePath(\n process\n .cwd()\n .replace(\n new RegExp(\n `^${escapeRegExp(constants.homePath)}(?:${path.sep}|$)`,\n 'i'\n ),\n '~/'\n )\n )\n const body = `\n _____ _ _ /---------------\n | __|___ ___| |_ ___| |_ | Socket.dev CLI ver ${cliVersion}\n |__ | ${readOnlyConfig} | _| '_| -_| _| | Node: ${nodeVersion}, API token set: ${shownToken}${defaultOrg ? `, default org: ${redacting ? REDACTED : defaultOrg}` : ''}\n |_____|___|___|_,_|___|_|.dev | Command: \\`${command}\\`, cwd: ${relCwd}`.trimStart()\n return ` ${body}\\n`\n}\n","import assert from 'node:assert'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { displayAnalytics } from './display-analytics'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'analytics',\n description: `Look up analytics data`,\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n file: {\n type: 'string',\n shortFlag: 'f',\n default: '-',\n description:\n 'Filepath to save output. Only valid with --json/--markdown. Defaults to stdout.'\n },\n repo: {\n type: 'string',\n shortFlag: 'r',\n default: '',\n description: 'Name of the repository. Only valid when scope=repo'\n },\n scope: {\n type: 'string',\n shortFlag: 's',\n default: 'org',\n description:\n \"Scope of the analytics data - either 'org' or 'repo', default: org\"\n },\n time: {\n type: 'number',\n shortFlag: 't',\n default: 7,\n description: 'Time filter - either 7, 30 or 90, default: 7'\n }\n },\n help: (command, { flags }) => `\n Usage\n $ ${command} --scope=<scope> --time=<time filter>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: report:write\n\n Default parameters are set to show the organization-level analytics over the\n last 7 days.\n\n Options\n ${getFlagListOutput(flags, 6)}\n\n Examples\n $ ${command} --scope=org --time=7\n $ ${command} --scope=org --time=30\n $ ${command} --scope=repo --repo=test-repo --time=30\n `\n}\n\nexport const cmdAnalytics = {\n description: config.description,\n hidden: config.hidden,\n run: run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { file, json, markdown, repo, scope, time } = cli.flags\n\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n test: scope === 'org' || scope === 'repo',\n message: 'Scope must be \"repo\" or \"org\"',\n pass: 'ok',\n fail: 'bad'\n },\n {\n test: time === 7 || time === 30 || time === 90,\n message: 'The time filter must either be 7, 30 or 90',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: scope === 'org' || !!repo,\n message: 'When scope=repo, repo name should be set through --repo',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: file === '-' || !!json || !!markdown,\n message:\n 'The `--file` flag is only valid when using `--json` or `--markdown`',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n assert(assertScope(scope))\n assert(assertTime(time))\n\n return await displayAnalytics({\n scope,\n time,\n repo: String(repo || ''),\n outputKind: json ? 'json' : markdown ? 'markdown' : 'print',\n filePath: String(file || '')\n })\n}\n\nfunction assertScope(scope: unknown): scope is 'org' | 'repo' {\n return scope === 'org' || scope === 'repo'\n}\n\nfunction assertTime(time: unknown): time is 7 | 30 | 90 {\n return time === 7 || time === 30 || time === 90\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchAuditLog({\n logType,\n orgSlug,\n outputKind,\n page,\n perPage\n}: {\n outputKind: 'json' | 'markdown' | 'print'\n orgSlug: string\n page: number\n perPage: number\n logType: string\n}): Promise<SocketSdkReturnType<'getAuditLogEvents'>['data'] | void> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start(`Looking up audit log for ${orgSlug}`)\n\n const result = await handleApiCall(\n sockSdk.getAuditLogEvents(orgSlug, {\n // I'm not sure this is used at all.\n outputJson: String(outputKind === 'json'),\n // I'm not sure this is used at all.\n outputMarkdown: String(outputKind === 'markdown'),\n orgSlug,\n type: logType,\n page: String(page),\n per_page: String(perPage)\n }),\n `Looking up audit log for ${orgSlug}\\n`\n )\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getAuditLogEvents', result)\n }\n\n spinner.stop()\n\n return result.data\n}\n","import process from 'node:process'\n\nimport { debugLog, isDebug } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { mdTable } from '../../utils/markdown'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nconst { REDACTED } = constants\n\nexport async function outputAuditLog(\n auditLogs: SocketSdkReturnType<'getAuditLogEvents'>['data'],\n {\n logType,\n orgSlug,\n outputKind,\n page,\n perPage\n }: {\n outputKind: 'json' | 'markdown' | 'print'\n orgSlug: string\n page: number\n perPage: number\n logType: string\n }\n): Promise<void> {\n if (outputKind === 'json') {\n logger.log(\n await outputAsJson(auditLogs.results, {\n logType,\n orgSlug,\n page,\n perPage\n })\n )\n } else {\n logger.log(\n await outputAsMarkdown(auditLogs.results, {\n logType,\n orgSlug,\n page,\n perPage\n })\n )\n }\n}\n\nexport async function outputAsJson(\n auditLogs: SocketSdkReturnType<'getAuditLogEvents'>['data']['results'],\n {\n logType,\n orgSlug,\n page,\n perPage\n }: {\n orgSlug: string\n page: number\n perPage: number\n logType: string\n }\n): Promise<string> {\n let json\n try {\n json = JSON.stringify(\n {\n desc: 'Audit logs for given query',\n generated: process.env['VITEST'] ? REDACTED : new Date().toISOString(),\n org: orgSlug,\n logType,\n page,\n perPage,\n logs: auditLogs.map(log => {\n // Note: The subset is pretty arbitrary\n const {\n created_at,\n event_id,\n ip_address,\n type,\n user_agent,\n user_email\n } = log\n return {\n event_id,\n created_at,\n ip_address,\n type,\n user_agent,\n user_email\n }\n })\n },\n null,\n 2\n )\n } catch (e) {\n process.exitCode = 1\n logger.fail(\n 'There was a problem converting the logs to JSON, please try without the `--json` flag'\n )\n if (isDebug()) {\n debugLog('Error:\\n', e)\n }\n return '{}'\n }\n\n return json\n}\n\nexport async function outputAsMarkdown(\n auditLogs: SocketSdkReturnType<'getAuditLogEvents'>['data']['results'],\n {\n logType,\n orgSlug,\n page,\n perPage\n }: {\n orgSlug: string\n page: number\n perPage: number\n logType: string\n }\n): Promise<string> {\n try {\n const table = mdTable<any>(auditLogs, [\n 'event_id',\n 'created_at',\n 'type',\n 'user_email',\n 'ip_address',\n 'user_agent'\n ])\n\n return `\n# Socket Audit Logs\n\nThese are the Socket.dev audit logs as per requested query.\n- org: ${orgSlug}\n- type filter: ${logType || '(none)'}\n- page: ${page}\n- per page: ${perPage}\n- generated: ${process.env['VITEST'] ? REDACTED : new Date().toISOString()}\n\n${table}\n`\n } catch (e) {\n process.exitCode = 1\n logger.fail(\n 'There was a problem converting the logs to Markdown, please try the `--json` flag'\n )\n if (isDebug()) {\n debugLog('Error:\\n', e)\n }\n // logger.error(e)\n return ''\n }\n}\n","import { fetchAuditLog } from './fetch-audit-log'\nimport { outputAuditLog } from './output-audit-log'\n\nexport async function handleAuditLog({\n logType,\n orgSlug,\n outputKind,\n page,\n perPage\n}: {\n outputKind: 'json' | 'markdown' | 'print'\n orgSlug: string\n page: number\n perPage: number\n logType: string\n}): Promise<void> {\n const auditLogs = await fetchAuditLog({\n orgSlug,\n outputKind,\n page,\n perPage,\n logType\n })\n if (!auditLogs) {\n return\n }\n\n await outputAuditLog(auditLogs, {\n logType,\n orgSlug,\n outputKind,\n page,\n perPage\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleAuditLog } from './handle-audit-log'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'audit-log',\n description: 'Look up the audit log for an organization',\n hidden: false,\n flags: {\n type: {\n type: 'string',\n shortFlag: 't',\n default: '',\n description: 'Type of log event'\n },\n perPage: {\n type: 'number',\n shortFlag: 'pp',\n default: 30,\n description: 'Results per page - default is 30'\n },\n page: {\n type: 'number',\n shortFlag: 'p',\n default: 1,\n description: 'Page number - default is 1'\n },\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: audit-log:list\n\n This feature requires an Enterprise Plan. To learn more about getting access\n to this feature and many more, please visit https://socket.dev/pricing\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg\n `\n}\n\nexport const cmdAuditLog = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown, page, perPage, type } = cli.flags\n const logType = String(type || '')\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n test: !!orgSlug,\n message: 'Org name should be the first arg',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleAuditLog({\n orgSlug,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'print',\n page: Number(page || 0),\n perPage: Number(perPage || 0),\n logType: logType.charAt(0).toUpperCase() + logType.slice(1)\n })\n}\n","import { existsSync, promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\n\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport shadowBin from '../../shadow/npm/bin'\n\nconst { NPM, NPX, PACKAGE_LOCK_JSON, PNPM, YARN, YARN_LOCK } = constants\n\nconst nodejsPlatformTypes = new Set([\n 'javascript',\n 'js',\n 'nodejs',\n NPM,\n PNPM,\n 'ts',\n 'tsx',\n 'typescript'\n])\n\nexport async function runCycloneDX(yargvWithYes: any) {\n let cleanupPackageLock = false\n const { yes, ...yargv } = { __proto__: null, ...yargvWithYes } as any\n const yesArgs = yes ? ['--yes'] : []\n if (\n yargv.type !== YARN &&\n nodejsPlatformTypes.has(yargv.type) &&\n existsSync(`./${YARN_LOCK}`)\n ) {\n if (existsSync(`./${PACKAGE_LOCK_JSON}`)) {\n yargv.type = NPM\n } else {\n // Use synp to create a package-lock.json from the yarn.lock,\n // based on the node_modules folder, for a more accurate SBOM.\n try {\n await shadowBin(NPX, [\n ...yesArgs,\n // The '@rollup/plugin-replace' will replace \"process.env['INLINED_SYNP_VERSION']\".\n `synp@${process.env['INLINED_SYNP_VERSION']}`,\n '--source-file',\n `./${YARN_LOCK}`\n ])\n yargv.type = NPM\n cleanupPackageLock = true\n } catch {}\n }\n }\n await shadowBin(NPX, [\n ...yesArgs,\n // The '@rollup/plugin-replace' will replace \"process.env['INLINED_CYCLONEDX_CDXGEN_VERSION']\".\n `@cyclonedx/cdxgen@${process.env['INLINED_CYCLONEDX_CDXGEN_VERSION']}`,\n ...argvToArray(yargv)\n ])\n if (cleanupPackageLock) {\n try {\n await fs.rm(`./${PACKAGE_LOCK_JSON}`)\n } catch {}\n }\n const fullOutputPath = path.join(process.cwd(), yargv.output)\n if (existsSync(fullOutputPath)) {\n logger.log(colors.cyanBright(`${yargv.output} created!`))\n }\n}\n\nfunction argvToArray(argv: {\n [key: string]: boolean | null | number | string | Array<string | number>\n}): string[] {\n if (argv['help']) {\n return ['--help']\n }\n const result = []\n for (const { 0: key, 1: value } of Object.entries(argv)) {\n if (key === '_' || key === '--') {\n continue\n }\n if (key === 'babel' || key === 'install-deps' || key === 'validate') {\n // cdxgen documents no-babel, no-install-deps, and no-validate flags so\n // use them when relevant.\n result.push(`--${value ? key : `no-${key}`}`)\n } else if (value === true) {\n result.push(`--${key}`)\n } else if (typeof value === 'string') {\n result.push(`--${key}`, String(value))\n } else if (Array.isArray(value)) {\n result.push(`--${key}`, ...value.map(String))\n }\n }\n if (argv['--']) {\n result.push('--', ...(argv as any)['--'])\n }\n return result\n}\n","const helpFlags = new Set(['--help', '-h'])\n\nexport function cmdFlagsToString(args: string[]) {\n const result = []\n for (let i = 0, { length } = args; i < length; i += 1) {\n if (args[i]!.startsWith('--')) {\n // Check if the next item exists and is NOT another flag.\n if (i + 1 < length && !args[i + 1]!.startsWith('--')) {\n result.push(`${args[i]}=${args[i + 1]}`)\n i += 1\n } else {\n result.push(args[i])\n }\n }\n }\n return result.join(' ')\n}\n\nexport function cmdPrefixMessage(cmdName: string, text: string): string {\n const cmdPrefix = cmdName ? `${cmdName}: ` : ''\n return `${cmdPrefix}${text}`\n}\n\nexport function isHelpFlag(cmdArg: string) {\n return helpFlags.has(cmdArg)\n}\n","// import { meowOrExit } from '../../utils/meow-with-subcommands'\nimport yargsParse from 'yargs-parser'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { pluralize } from '@socketsecurity/registry/lib/words'\n\nimport { runCycloneDX } from './run-cyclonedx'\nimport constants from '../../constants'\nimport { isHelpFlag } from '../../utils/cmd'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\n// TODO: convert yargs to meow. Or convert all the other things to yargs.\nconst toLower = (arg: string) => arg.toLowerCase()\nconst arrayToLower = (arg: string[]) => arg.map(toLower)\n\nconst yargsConfig = {\n configuration: {\n 'camel-case-expansion': false,\n 'strip-aliased': true,\n 'parse-numbers': false,\n 'populate--': true,\n 'unknown-options-as-args': true\n },\n coerce: {\n author: arrayToLower,\n filter: arrayToLower,\n only: arrayToLower,\n profile: toLower,\n standard: arrayToLower,\n type: arrayToLower\n },\n default: {\n //author: ['OWASP Foundation'],\n //'auto-compositions': true,\n //babel: true,\n //evidence: false,\n //'include-crypto': false,\n //'include-formulation': false,\n\n // Default 'install-deps' to `false` and 'lifecycle' to 'pre-build' to\n // sidestep arbitrary code execution during a cdxgen scan.\n // https://github.com/CycloneDX/cdxgen/issues/1328\n 'install-deps': false,\n lifecycle: 'pre-build',\n\n //output: 'bom.json',\n //profile: 'generic',\n //'project-version': '',\n //recurse: true,\n //'server-host': '127.0.0.1',\n //'server-port': '9090',\n //'spec-version': '1.5',\n type: ['js']\n //validate: true,\n },\n alias: {\n help: ['h'],\n output: ['o'],\n print: ['p'],\n recurse: ['r'],\n 'resolve-class': ['c'],\n type: ['t'],\n version: ['v'],\n yes: ['y']\n },\n array: [\n { key: 'author', type: 'string' },\n { key: 'exclude', type: 'string' },\n { key: 'filter', type: 'string' },\n { key: 'only', type: 'string' },\n { key: 'standard', type: 'string' },\n { key: 'type', type: 'string' }\n ],\n boolean: [\n 'auto-compositions',\n 'babel',\n 'deep',\n 'evidence',\n 'fail-on-error',\n 'generate-key-and-sign',\n 'help',\n 'include-formulation',\n 'include-crypto',\n 'install-deps',\n 'print',\n 'required-only',\n 'server',\n 'validate',\n 'version',\n // The --yes flag and -y alias map to the corresponding flag and alias of npx.\n // https://docs.npmjs.com/cli/v7/commands/npx#compatibility-with-older-npx-versions\n 'yes'\n ],\n string: [\n 'api-key',\n 'lifecycle',\n 'output',\n 'parent-project-id',\n 'profile',\n 'project-group',\n 'project-name',\n 'project-version',\n 'project-id',\n 'server-host',\n 'server-port',\n 'server-url',\n 'spec-version'\n ]\n}\n\nconst config: CliCommandConfig = {\n commandName: 'cdxgen',\n description: 'Create an SBOM with CycloneDX generator (cdxgen)',\n hidden: false,\n flags: {\n // TODO: convert from yargsConfig\n },\n help: (command, config) => `\n Usage\n $ ${command} [options]\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n `\n}\n\nexport const cmdCdxgen = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n allowUnknownFlags: true,\n // Don't let meow take over --help.\n argv: argv.filter(a => !isHelpFlag(a)),\n config,\n importMeta,\n parentName\n })\n\n // TODO: Convert to meow.\n const yargv = {\n ...yargsParse(argv as string[], yargsConfig)\n } as any\n\n const unknown: string[] = yargv._\n const { length: unknownLength } = unknown\n if (unknownLength) {\n // Use exit status of 2 to indicate incorrect usage, generally invalid\n // options or missing arguments.\n // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html\n process.exitCode = 2\n logger.fail(\n `Unknown ${pluralize('argument', unknownLength)}: ${yargv._.join(', ')}`\n )\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n if (yargv.output === undefined) {\n yargv.output = 'socket-cdx.json'\n }\n\n await runCycloneDX(yargv)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleApiCall } from '../../utils/api'\nimport { getConfigValue } from '../../utils/config'\nimport { setupSdk } from '../../utils/sdk'\n\n// Use the config defaultOrg when set, otherwise discover from remote\nexport async function getDefaultOrgSlug(): Promise<string | void> {\n let defaultOrg = getConfigValue('defaultOrg')\n if (defaultOrg) {\n logger.info(`Using default org: ${defaultOrg}`)\n } else {\n const sockSdk = await setupSdk()\n const result = await handleApiCall(\n sockSdk.getOrganizations(),\n 'looking up organizations'\n )\n // Ignore a failed request here. It was not the primary goal of\n // running this command and reporting it only leads to end-user confusion.\n if (!result.success) {\n logger.fail(\n 'Failed to fetch default organization from API. Unable to continue.'\n )\n process.exitCode = 1\n return\n }\n const orgs = result.data.organizations\n const keys = Object.keys(orgs)\n\n if (!keys[0]) {\n logger.fail(\n 'Could not find default organization for the current API token. Unable to continue.'\n )\n process.exitCode = 1\n return\n }\n\n const slug = (keys[0] in orgs && orgs?.[keys[0]]?.name) ?? undefined\n\n if (slug) {\n defaultOrg = slug\n logger.info(`Resolved org to: ${defaultOrg}`)\n }\n }\n\n if (!defaultOrg) {\n logger.fail(\n 'Could not find the default organization for the current API token. Unable to continue.'\n )\n process.exitCode = 1\n return\n }\n\n return defaultOrg\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchCreateOrgFullScan(\n packagePaths: string[],\n orgSlug: string,\n defaultBranch: boolean,\n pendingHead: boolean,\n tmp: boolean,\n cwd: string,\n {\n branchName,\n commitHash,\n commitMessage,\n committers,\n pullRequest,\n repoName\n }: {\n branchName: string\n commitHash: string\n commitMessage: string\n committers: string\n pullRequest: number\n repoName: string\n }\n): Promise<SocketSdkReturnType<'CreateOrgFullScan'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start(\n `Sending request to create a scan with ${packagePaths.length} packages...`\n )\n\n const result = await handleApiCall(\n sockSdk.createOrgFullScan(\n orgSlug,\n {\n ...(branchName ? { branch: branchName } : {}),\n ...(commitHash ? { commit_hash: commitHash } : {}),\n ...(commitMessage ? { commit_message: commitMessage } : {}),\n ...(committers ? { committers } : {}),\n make_default_branch: String(defaultBranch),\n ...(pullRequest ? { pull_request: String(pullRequest) } : {}),\n repo: repoName || 'socket-default-repository', // mandatory, this is server default for repo\n set_as_pending_head: String(pendingHead),\n tmp: String(tmp)\n },\n packagePaths,\n cwd\n ),\n 'Creating scan'\n )\n\n spinner.successAndStop('Completed request to create a new scan.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('CreateOrgFullScan', result)\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchSupportedScanFileNames(): Promise<\n SocketSdkReturnType<'getReportSupportedFiles'>['data'] | undefined\n> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Requesting supported scan file types from API...')\n\n const result = await handleApiCall(\n sockSdk.getReportSupportedFiles(),\n 'fetching supported scan file types'\n )\n\n spinner.stop()\n logger.success('Received response while fetched supported scan file types.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getReportSupportedFiles', result)\n }\n\n return result.data\n}\n","import { debugLog } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { handleApiCall, handleApiError, queryApi } from '../../utils/api'\nimport { AuthError } from '../../utils/errors'\nimport { failMsgWithBadge } from '../../utils/fail-msg-with-badge'\nimport { getDefaultToken, setupSdk } from '../../utils/sdk'\n\nimport type {\n SocketSdkResultType,\n SocketSdkReturnType\n} from '@socketsecurity/sdk'\nimport type { components } from '@socketsecurity/sdk/types/api'\n\n/**\n * This fetches all the relevant pieces of data to generate a report, given a\n * full scan ID.\n */\nexport async function fetchReportData(\n orgSlug: string,\n scanId: string,\n includeLicensePolicy: boolean\n): Promise<\n | {\n ok: true\n scan: Array<components['schemas']['SocketArtifact']>\n securityPolicy: SocketSdkReturnType<'getOrgSecurityPolicy'>\n }\n | {\n ok: false\n scan: undefined\n securityPolicy: undefined\n }\n> {\n const apiToken = getDefaultToken()\n if (!apiToken) {\n throw new AuthError(\n 'User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.'\n )\n }\n\n const sockSdk = await setupSdk(apiToken)\n\n let scanStatus = 'requested..'\n let policyStatus = 'requested..'\n let finishedFetching = false\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n function updateScan(desc: string) {\n scanStatus = desc\n updateProgress()\n }\n\n function updatePolicy(desc: string) {\n policyStatus = desc\n updateProgress()\n }\n\n function updateProgress() {\n if (finishedFetching) {\n spinner.stop()\n logger.info(\n `Scan result: ${scanStatus}. Security policy: ${policyStatus}.`\n )\n } else {\n spinner.start(\n `Scan result: ${scanStatus}. Security policy: ${policyStatus}.`\n )\n }\n }\n\n async function fetchScanResult(apiToken: string) {\n const response = await queryApi(\n `orgs/${orgSlug}/full-scans/${encodeURIComponent(scanId)}${includeLicensePolicy ? '?include_license_details=true' : ''}`,\n apiToken\n )\n updateScan('received response')\n\n if (!response.ok) {\n spinner.stop()\n const err = await handleApiError(response.status)\n logger.fail(failMsgWithBadge(response.statusText, `Fetch error: ${err}`))\n debugLog(err)\n updateScan(`request resulted in status code ${response.status}`)\n return undefined\n }\n\n updateScan(`ok, downloading response..`)\n const jsons = await response.text()\n updateScan(`received`)\n\n const lines = jsons.split('\\n').filter(Boolean)\n const data = lines.map(line => {\n try {\n return JSON.parse(line)\n } catch {\n scanStatus = `received invalid JSON response`\n spinner.stop()\n logger.error(\n 'Response was not valid JSON but it ought to be (please report if this persists)'\n )\n debugLog(line)\n updateProgress()\n return\n }\n }) as unknown as Array<components['schemas']['SocketArtifact']>\n\n return data\n }\n\n async function fetchSecurityPolicy() {\n const r = await sockSdk.getOrgSecurityPolicy(orgSlug)\n updatePolicy('received response')\n\n const s = await handleApiCall(\n r,\n \"looking up organization's security policy\"\n )\n updatePolicy('received')\n return s\n }\n\n updateProgress()\n\n const [scan, securityPolicyMaybe]: [\n undefined | Array<components['schemas']['SocketArtifact']>,\n SocketSdkResultType<'getOrgSecurityPolicy'>\n ] = await Promise.all([\n fetchScanResult(apiToken).catch(e => {\n updateScan(`failure; unknown blocking problem occurred`)\n throw e\n }),\n fetchSecurityPolicy().catch(e => {\n updatePolicy(`failure; unknown blocking problem occurred`)\n throw e\n })\n ]).finally(() => {\n finishedFetching = true\n updateProgress()\n })\n\n if (!Array.isArray(scan)) {\n logger.error('Was unable to fetch scan result, bailing')\n process.exitCode = 1\n return {\n ok: false,\n scan: undefined,\n securityPolicy: undefined\n }\n }\n\n if (!securityPolicyMaybe?.success) {\n logger.error('Was unable to fetch security policy, bailing')\n process.exitCode = 1\n return {\n ok: false,\n scan: undefined,\n securityPolicy: undefined\n }\n }\n\n return {\n ok: true,\n scan,\n securityPolicy: securityPolicyMaybe\n }\n}\n","import type { Spinner } from '@socketsecurity/registry/lib/spinner'\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\nimport type { components } from '@socketsecurity/sdk/types/api'\n\ntype AlertAction = 'defer' | 'ignore' | 'monitor' | 'error' | 'warn'\ntype AlertKey = string\n\ntype FileMap = Map<string, ReportLeafNode | Map<AlertKey, ReportLeafNode>>\ntype VersionMap = Map<string, ReportLeafNode | FileMap>\ntype PackageMap = Map<string, ReportLeafNode | VersionMap>\ntype EcoMap = Map<string, ReportLeafNode | PackageMap>\nexport type ViolationsMap = Map<string, EcoMap>\n\nexport interface ShortScanReport {\n healthy: boolean\n}\nexport interface ScanReport {\n orgSlug: string\n scanId: string\n options: { fold: string; reportLevel: string }\n healthy: boolean\n alerts: ViolationsMap\n}\n\nexport type ReportLeafNode = {\n type: string\n policy: 'defer' | 'ignore' | 'monitor' | 'warn' | 'error'\n url: string\n manifest: string[]\n}\n\nexport function generateReport(\n scan: Array<components['schemas']['SocketArtifact']>,\n securityPolicy: SocketSdkReturnType<'getOrgSecurityPolicy'>,\n {\n fold,\n orgSlug,\n reportLevel,\n scanId,\n short,\n spinner\n }: {\n fold: 'pkg' | 'version' | 'file' | 'none'\n orgSlug: string\n reportLevel: 'defer' | 'ignore' | 'monitor' | 'warn' | 'error'\n scanId: string\n short?: boolean | undefined\n spinner?: Spinner | undefined\n }\n): ScanReport | ShortScanReport {\n const now = Date.now()\n\n spinner?.start('Generating report...')\n\n // Create an object that includes:\n // healthy: boolean\n // worst violation level;\n // per eco\n // per package\n // per version\n // per offending file\n // reported issue -> policy action\n\n // In the context of a report;\n // - the alert.severity is irrelevant\n // - the securityPolicyDefault is irrelevant\n // - the report defaults to healthy:true with no alerts\n // - the appearance of an alert will trigger the policy action;\n // - error: healthy will end up as false, add alerts to report\n // - warn: healthy unchanged, add alerts to report\n // - monitor/ignore: no action\n // - defer: unknown (no action)\n\n // Note: the server will emit alerts for license policy violations but\n // those are only included if you set the flag when requesting the scan\n // data. The alerts map to a single security policy key that determines\n // what to do with any violation, regardless of the concrete license.\n // That rule is called \"License Policy Violation\".\n // The license policy part is implicitly handled here. Either they are\n // included and may show up, or they are not and won't show up.\n\n const violations = new Map()\n\n let healthy = true\n\n const securityRules: SocketSdkReturnType<'getOrgSecurityPolicy'>['data']['securityPolicyRules'] =\n securityPolicy.data.securityPolicyRules\n if (securityRules) {\n // Note: reportLevel: error > warn > monitor > ignore > defer\n scan.forEach(artifact => {\n const {\n alerts,\n name: pkgName = '<unknown>',\n type: ecosystem,\n version = '<unknown>'\n } = artifact\n\n alerts?.forEach(\n (\n alert: NonNullable<\n components['schemas']['SocketArtifact']['alerts']\n >[number]\n ) => {\n const alertName = alert.type as keyof typeof securityRules // => policy[type]\n const action = securityRules[alertName]?.action || ''\n switch (action) {\n case 'error': {\n healthy = false\n if (!short) {\n addAlert(\n artifact,\n violations,\n fold,\n ecosystem,\n pkgName,\n version,\n alert,\n action\n )\n }\n break\n }\n case 'warn': {\n if (!short && reportLevel !== 'error') {\n addAlert(\n artifact,\n violations,\n fold,\n ecosystem,\n pkgName,\n version,\n alert,\n action\n )\n }\n break\n }\n case 'monitor': {\n if (!short && reportLevel !== 'warn' && reportLevel !== 'error') {\n addAlert(\n artifact,\n violations,\n fold,\n ecosystem,\n pkgName,\n version,\n alert,\n action\n )\n }\n break\n }\n\n case 'ignore': {\n if (\n !short &&\n reportLevel !== 'warn' &&\n reportLevel !== 'error' &&\n reportLevel !== 'monitor'\n ) {\n addAlert(\n artifact,\n violations,\n fold,\n ecosystem,\n pkgName,\n version,\n alert,\n action\n )\n }\n break\n }\n\n case 'defer': {\n // Not sure but ignore for now. Defer to later ;)\n if (!short && reportLevel === 'defer') {\n addAlert(\n artifact,\n violations,\n fold,\n ecosystem,\n pkgName,\n version,\n alert,\n action\n )\n }\n break\n }\n\n default: {\n // This value was not emitted from the api at the time of writing.\n }\n }\n }\n )\n })\n }\n\n spinner?.successAndStop(`Generated reported in ${Date.now() - now} ms`)\n\n const report = short\n ? { healthy }\n : {\n healthy,\n orgSlug,\n scanId,\n options: { fold, reportLevel },\n alerts: violations\n }\n\n return report\n}\n\nfunction createLeaf(\n art: components['schemas']['SocketArtifact'],\n alert: NonNullable<components['schemas']['SocketArtifact']['alerts']>[number],\n policyAction: AlertAction\n): ReportLeafNode {\n const leaf: ReportLeafNode = {\n type: alert.type,\n policy: policyAction,\n url: `https://socket.dev/${art.type}/package/${art.name}/${art.version}`,\n manifest: art.manifestFiles?.map(obj => obj.file) ?? []\n }\n return leaf\n}\n\nfunction addAlert(\n art: components['schemas']['SocketArtifact'],\n violations: ViolationsMap,\n foldSetting: 'pkg' | 'version' | 'file' | 'none',\n ecosystem: string,\n pkgName: string,\n version: string,\n alert: NonNullable<components['schemas']['SocketArtifact']['alerts']>[number],\n policyAction: AlertAction\n): void {\n if (!violations.has(ecosystem)) {\n violations.set(ecosystem, new Map())\n }\n const ecomap: EcoMap = violations.get(ecosystem)!\n if (foldSetting === 'pkg') {\n const existing = ecomap.get(pkgName) as ReportLeafNode | undefined\n if (!existing || isStricterPolicy(existing.policy, policyAction)) {\n ecomap.set(pkgName, createLeaf(art, alert, policyAction))\n }\n } else {\n if (!ecomap.has(pkgName)) {\n ecomap.set(pkgName, new Map())\n }\n const pkgmap = ecomap.get(pkgName) as PackageMap\n if (foldSetting === 'version') {\n const existing = pkgmap.get(version) as ReportLeafNode | undefined\n if (!existing || isStricterPolicy(existing.policy, policyAction)) {\n pkgmap.set(version, createLeaf(art, alert, policyAction))\n }\n } else {\n if (!pkgmap.has(version)) {\n pkgmap.set(version, new Map())\n }\n const file = alert.file || '<unknown>'\n const vermap = pkgmap.get(version) as VersionMap\n\n if (foldSetting === 'file') {\n const existing = vermap.get(file) as ReportLeafNode | undefined\n if (!existing || isStricterPolicy(existing.policy, policyAction)) {\n vermap.set(file, createLeaf(art, alert, policyAction))\n }\n } else {\n if (!vermap.has(file)) {\n vermap.set(file, new Map())\n }\n const key = `${alert.type} at ${alert.start}:${alert.end}`\n const filemap: FileMap = vermap.get(file) as FileMap\n const existing = filemap.get(key) as ReportLeafNode | undefined\n if (!existing || isStricterPolicy(existing.policy, policyAction)) {\n filemap.set(key, createLeaf(art, alert, policyAction))\n }\n }\n }\n }\n}\n\nfunction isStricterPolicy(\n was: 'error' | 'warn' | 'monitor' | 'ignore' | 'defer',\n is: 'error' | 'warn' | 'monitor' | 'ignore' | 'defer'\n): boolean {\n // error > warn > monitor > ignore > defer > {unknown}\n if (was === 'error') {\n return false\n }\n if (is === 'error') {\n return true\n }\n if (was === 'warn') {\n return false\n }\n if (is === 'warn') {\n return false\n }\n if (was === 'monitor') {\n return false\n }\n if (is === 'monitor') {\n return false\n }\n if (was === 'ignore') {\n return false\n }\n if (is === 'ignore') {\n return false\n }\n if (was === 'defer') {\n return false\n }\n if (is === 'defer') {\n return false\n }\n // unreachable?\n return false\n}\n","interface NestedRecord<T> {\n [key: string]: T | NestedRecord<T>\n}\n\n/**\n * Convert a Map<string, Map|string> to a nested object of similar shape.\n * The goal is to serialize it with JSON.stringify, which Map can't do.\n */\nexport function mapToObject<T>(\n map: Map<string, T | Map<string, T | Map<string, T>>>\n): NestedRecord<T> {\n return Object.fromEntries(\n Array.from(map.entries()).map(([k, v]) => [\n k,\n v instanceof Map ? mapToObject(v) : v\n ])\n )\n}\n","type NestedMap<T> = Map<string, T | NestedMap<T>>\n\nexport function* walkNestedMap<T>(\n map: NestedMap<T>,\n keys: string[] = []\n): Generator<{ keys: string[]; value: T }> {\n for (const [key, value] of map.entries()) {\n if (value instanceof Map) {\n yield* walkNestedMap(value as NestedMap<T>, keys.concat(key))\n } else {\n yield { keys: keys.concat(key), value: value }\n }\n }\n}\n","import fs from 'node:fs/promises'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { generateReport } from './generate-report'\nimport constants from '../../constants'\nimport { mapToObject } from '../../utils/map-to-object'\nimport { mdTable } from '../../utils/markdown'\nimport { walkNestedMap } from '../../utils/walk-nested-map'\n\nimport type { ReportLeafNode, ScanReport } from './generate-report'\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\nimport type { components } from '@socketsecurity/sdk/types/api'\n\nexport async function outputScanReport(\n scan: Array<components['schemas']['SocketArtifact']>,\n securityPolicy: SocketSdkReturnType<'getOrgSecurityPolicy'>,\n {\n filePath,\n fold,\n includeLicensePolicy,\n orgSlug,\n outputKind,\n reportLevel,\n scanId,\n short\n }: {\n orgSlug: string\n scanId: string\n includeLicensePolicy: boolean\n outputKind: 'json' | 'markdown' | 'text'\n filePath: string\n fold: 'pkg' | 'version' | 'file' | 'none'\n reportLevel: 'defer' | 'ignore' | 'monitor' | 'warn' | 'error'\n short: boolean\n }\n): Promise<void> {\n const scanReport = generateReport(scan, securityPolicy, {\n orgSlug,\n scanId,\n fold,\n reportLevel,\n short,\n // Lazily access constants.spinner.\n spinner: constants.spinner\n })\n\n if (!scanReport.healthy) {\n process.exitCode = 1\n }\n\n if (\n outputKind === 'json' ||\n (outputKind === 'text' && filePath && filePath.endsWith('.json'))\n ) {\n const json = short\n ? JSON.stringify(scanReport)\n : toJsonReport(scanReport as ScanReport, includeLicensePolicy)\n\n if (filePath && filePath !== '-') {\n logger.log('Writing json report to', filePath)\n return await fs.writeFile(filePath, json)\n }\n\n logger.log(json)\n return\n }\n\n if (outputKind === 'markdown' || (filePath && filePath.endsWith('.md'))) {\n const md = short\n ? `healthy = ${scanReport.healthy}`\n : toMarkdownReport(scanReport as ScanReport, includeLicensePolicy)\n\n if (filePath && filePath !== '-') {\n logger.log('Writing markdown report to', filePath)\n return await fs.writeFile(filePath, md)\n }\n\n logger.log(md)\n return\n }\n\n if (short) {\n logger.log(scanReport.healthy ? 'OK' : 'ERR')\n } else {\n logger.dir(scanReport, { depth: null })\n }\n}\n\nexport function toJsonReport(\n report: ScanReport,\n includeLicensePolicy: boolean\n): string {\n const obj = mapToObject(report.alerts)\n\n const json = JSON.stringify(\n {\n includeLicensePolicy,\n ...report,\n alerts: obj\n },\n null,\n 2\n )\n\n return json\n}\n\nexport function toMarkdownReport(\n report: ScanReport,\n includeLicensePolicy: boolean\n): string {\n const flatData = Array.from(walkNestedMap(report.alerts)).map(\n ({ keys, value }: { keys: string[]; value: ReportLeafNode }) => {\n const { manifest, policy, type, url } = value\n return {\n 'Alert Type': type,\n Package: keys[1] || '<unknown>',\n 'Introduced by': keys[2] || '<unknown>',\n url,\n 'Manifest file': manifest.join(', '),\n Policy: policy\n }\n }\n )\n\n const md =\n `\n# Scan Policy Report\n\nThis report tells you whether the results of a Socket scan results violate the\nsecurity${includeLicensePolicy ? ' or license' : ''} policy set by your organization.\n\n## Health status\n\n${\n report.healthy\n ? `The scan *PASSES* all requirements set by your security${includeLicensePolicy ? ' and license' : ''} policy.`\n : 'The scan *VIOLATES* one or more policies set to the \"error\" level.'\n}\n\n## Settings\n\nConfiguration used to generate this report:\n\n- Organization: ${report.orgSlug}\n- Scan ID: ${report.scanId}\n- Alert folding: ${report.options.fold === 'none' ? 'none' : `up to ${report.options.fold}`}\n- Minimal policy level for alert to be included in report: ${report.options.reportLevel === 'defer' ? 'everything' : report.options.reportLevel}\n- Include license alerts: ${includeLicensePolicy ? 'yes' : 'no'}\n\n## Alerts\n\n${\n report.alerts.size\n ? `All the alerts from the scan with a policy set to at least \"${report.options.reportLevel}\"}.`\n : `The scan contained no alerts for with a policy set to at least \"${report.options.reportLevel}\".`\n}\n\n${\n !report.alerts.size\n ? ''\n : mdTable(flatData, [\n 'Policy',\n 'Alert Type',\n 'Package',\n 'Introduced by',\n 'url',\n 'Manifest file'\n ])\n}\n `.trim() + '\\n'\n\n return md\n}\n","import { fetchReportData } from './fetch-report-data'\nimport { outputScanReport } from './output-scan-report'\n\nexport async function handleScanReport({\n filePath,\n fold,\n includeLicensePolicy,\n orgSlug,\n outputKind,\n reportLevel,\n scanId,\n short\n}: {\n orgSlug: string\n scanId: string\n includeLicensePolicy: boolean\n outputKind: 'json' | 'markdown' | 'text'\n filePath: string\n fold: 'pkg' | 'version' | 'file' | 'none'\n reportLevel: 'defer' | 'ignore' | 'monitor' | 'warn' | 'error'\n short: boolean\n}): Promise<void> {\n const { ok, scan, securityPolicy } = await fetchReportData(\n orgSlug,\n scanId,\n includeLicensePolicy\n )\n if (!ok) {\n return\n }\n\n await outputScanReport(scan, securityPolicy, {\n filePath,\n fold,\n scanId: scanId,\n includeLicensePolicy,\n orgSlug,\n outputKind,\n reportLevel,\n short\n })\n}\n","import open from 'open'\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { confirm } from '@socketsecurity/registry/lib/prompts'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputCreateNewScan(\n data: SocketSdkReturnType<'CreateOrgFullScan'>['data'],\n outputKind: 'json' | 'markdown' | 'text',\n interactive: boolean\n) {\n if (!data.id) {\n logger.fail('Did not receive a scan ID from the API...')\n process.exitCode = 1\n }\n\n if (outputKind === 'json') {\n const json = data.id\n ? { success: true, data }\n : { success: false, message: 'No scan ID received' }\n\n logger.log(JSON.stringify(json, null, 2))\n logger.log('')\n\n return\n }\n\n if (outputKind === 'markdown') {\n logger.log('# Create New Scan')\n logger.log('')\n if (data.id) {\n logger.log(\n `A [new Scan](${data.html_report_url}) was created with ID: ${data.id}`\n )\n logger.log('')\n } else {\n logger.log(\n `The server did not return a Scan ID while trying to create a new Scan. This could be an indication something went wrong.`\n )\n }\n logger.log('')\n return\n }\n\n const link = colors.underline(colors.cyan(`${data.html_report_url}`))\n logger.log(`Available at: ${link}`)\n\n if (\n interactive &&\n (await confirm({\n message: 'Would you like to open it in your browser?',\n default: false\n }))\n ) {\n await open(`${data.html_report_url}`)\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { fetchCreateOrgFullScan } from './fetch-create-org-full-scan'\nimport { fetchSupportedScanFileNames } from './fetch-supported-scan-file-names'\nimport { handleScanReport } from './handle-scan-report'\nimport { outputCreateNewScan } from './output-create-new-scan'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { getPackageFilesForScan } from '../../utils/path-resolve'\n\nexport async function handleCreateNewScan({\n branchName,\n commitHash,\n commitMessage,\n committers,\n cwd,\n defaultBranch,\n interactive,\n orgSlug,\n outputKind,\n pendingHead,\n pullRequest,\n readOnly,\n repoName,\n report,\n targets,\n tmp\n}: {\n branchName: string\n commitHash: string\n commitMessage: string\n committers: string\n cwd: string\n defaultBranch: boolean\n interactive: boolean\n orgSlug: string\n pendingHead: boolean\n pullRequest: number\n outputKind: 'json' | 'markdown' | 'text'\n readOnly: boolean\n repoName: string\n report: boolean\n targets: string[]\n tmp: boolean\n}): Promise<void> {\n const supportedFileNames = await fetchSupportedScanFileNames()\n if (!supportedFileNames) {\n return\n }\n\n const packagePaths = await getPackageFilesForScan(\n cwd,\n targets,\n supportedFileNames\n )\n\n if (\n handleBadInput({\n nook: true,\n test: packagePaths.length > 0,\n pass: 'ok',\n fail: 'found no eligible files to scan',\n message:\n 'TARGET (file/dir) must contain matching / supported file types for a scan'\n })\n ) {\n return\n }\n\n if (readOnly) {\n logger.log('[ReadOnly] Bailing now')\n return\n }\n\n const data = await fetchCreateOrgFullScan(\n packagePaths,\n orgSlug,\n defaultBranch,\n pendingHead,\n tmp,\n cwd,\n {\n commitHash,\n commitMessage,\n committers,\n pullRequest,\n repoName,\n branchName\n }\n )\n if (!data) {\n return\n }\n\n if (report) {\n if (data?.id) {\n await handleScanReport({\n filePath: '-',\n fold: 'version',\n includeLicensePolicy: true,\n orgSlug,\n outputKind,\n reportLevel: 'error',\n scanId: data.id,\n short: false\n })\n } else {\n logger.fail('Failure: Server did not respond with a scan ID')\n process.exitCode = 1\n }\n } else {\n await outputCreateNewScan(data, outputKind, interactive)\n }\n}\n","import { getDefaultOrgSlug } from './fetch-default-org-slug'\nimport { handleCreateNewScan } from '../scan/handle-create-new-scan'\n\nexport async function handleCI(): Promise<void> {\n // ci: {\n // description: 'Alias for \"report create --view --strict\"',\n // argv: ['report', 'create', '--view', '--strict']\n // }\n const orgSlug = await getDefaultOrgSlug()\n if (!orgSlug) {\n return\n }\n\n // TODO: does it make sense to discover the commit details from local git?\n // TODO: does it makes sense to use custom branch/repo names here? probably socket.yml, right\n await handleCreateNewScan({\n branchName: 'socket-default-branch',\n commitMessage: '',\n commitHash: '',\n committers: '',\n cwd: process.cwd(),\n defaultBranch: false,\n interactive: false,\n orgSlug,\n outputKind: 'json',\n pendingHead: true, // when true, requires branch name set, tmp false\n pullRequest: 0,\n repoName: 'socket-default-repository',\n readOnly: false,\n report: true,\n targets: ['.'],\n tmp: false // don't set when pendingHead is true\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleCI } from './handle-ci'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'ci',\n description:\n 'Create a new scan and report whether it passes your security policy',\n hidden: true,\n flags: {\n ...commonFlags\n },\n help: (parentName, _config) => `\n Usage\n $ ${parentName}\n\n This command is intended to use in CI runs to allow automated systems to\n accept or reject a current build. When the scan does not pass your security\n policy, the exit code will be non-zero.\n\n It will use the default org for the set API token.\n `\n}\n\nexport const cmdCI = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleCI()\n}\n","import { handleApiCall } from '../../utils/api'\nimport { supportedConfigKeys } from '../../utils/config'\nimport { getDefaultToken, setupSdk } from '../../utils/sdk'\n\nimport type { LocalConfig } from '../../utils/config'\n\nexport async function discoverConfigValue(\n key: string\n): Promise<{ success: boolean; value: unknown; message: string }> {\n // This will have to be a specific implementation per key because certain\n // keys should request information from particular API endpoints while\n // others should simply return their default value, like endpoint URL.\n\n if (!supportedConfigKeys.has(key as keyof LocalConfig)) {\n return {\n success: false,\n value: undefined,\n message: 'Requested key is not a valid config key.'\n }\n }\n\n if (key === 'apiBaseUrl') {\n // Return the default value\n return {\n success: false,\n value: undefined,\n message:\n \"If you're unsure about the base endpoint URL then simply unset it.\"\n }\n }\n\n if (key === 'apiProxy') {\n // I don't think we can auto-discover this with any order of reliability..?\n return {\n success: false,\n value: undefined,\n message:\n 'When uncertain, unset this key. Otherwise ask your network administrator'\n }\n }\n\n if (key === 'apiToken') {\n return {\n success: false,\n value: undefined,\n message:\n 'You can find/create your API token in your Socket dashboard > settings > API tokens.\\nYou should then use `socket login` to login instead of this command.'\n }\n }\n\n if (key === 'defaultOrg') {\n const apiToken = getDefaultToken()\n if (!apiToken) {\n return {\n success: false,\n value: undefined,\n message:\n 'No API token set, must have a token to resolve its default org.'\n }\n }\n\n const org = await getDefaultOrgFromToken()\n if (!org?.length) {\n return {\n success: false,\n value: undefined,\n message:\n 'Was unable to determine default org for the current API token.'\n }\n }\n\n if (Array.isArray(org)) {\n return {\n success: true,\n value: org,\n message: 'These are the orgs that the current API token can access.'\n }\n }\n\n return {\n success: true,\n value: org,\n message: 'This is the org that belongs to the current API token.'\n }\n }\n\n if (key === 'enforcedOrgs') {\n const apiToken = getDefaultToken()\n if (!apiToken) {\n return {\n success: false,\n value: undefined,\n message:\n 'No API token set, must have a token to resolve orgs to enforce.'\n }\n }\n\n const orgs = await getEnforceableOrgsFromToken()\n if (!orgs?.length) {\n return {\n success: false,\n value: undefined,\n message:\n 'Was unable to determine any orgs to enforce for the current API token.'\n }\n }\n\n return {\n success: true,\n value: orgs,\n message: 'These are the orgs whose security policy you can enforce.'\n }\n }\n\n if (key === 'test') {\n return {\n success: false,\n value: undefined,\n message: ''\n }\n }\n\n // Mostly to please TS, because we're not telling it `key` is keyof LocalConfig\n return {\n success: false,\n value: undefined,\n message: 'unreachable?'\n }\n}\n\nasync function getDefaultOrgFromToken(): Promise<\n string[] | string | undefined\n> {\n const sockSdk = await setupSdk()\n const result = await handleApiCall(\n sockSdk.getOrganizations(),\n 'looking up organizations'\n )\n\n if (result.success) {\n const arr = Array.from(Object.values(result.data.organizations)).map(\n ({ slug }) => slug\n )\n if (arr.length === 0) {\n return undefined\n }\n if (arr.length === 1) {\n return arr[0]\n }\n return arr\n }\n\n return undefined\n}\n\nasync function getEnforceableOrgsFromToken(): Promise<string[] | undefined> {\n const sockSdk = await setupSdk()\n const result = await handleApiCall(\n sockSdk.getOrganizations(),\n 'looking up organizations'\n )\n\n if (result.success) {\n const arr = Array.from(Object.values(result.data.organizations)).map(\n ({ slug }) => slug\n )\n if (arr.length === 0) {\n return undefined\n }\n return arr\n }\n\n return undefined\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\nimport { select } from '@socketsecurity/registry/lib/prompts'\n\nimport { LocalConfig, updateConfigValue } from '../../utils/config'\n\nexport async function outputConfigAuto(\n key: keyof LocalConfig,\n {\n message,\n success,\n value\n }: {\n success: boolean\n value: unknown\n message: string\n },\n outputKind: 'json' | 'markdown' | 'text'\n) {\n if (outputKind === 'json') {\n logger.log(JSON.stringify({ success, message, result: { key, value } }))\n } else if (outputKind === 'markdown') {\n logger.log(`# Auto discover config value`)\n logger.log('')\n logger.log(\n `Attempted to automatically discover the value for config key: \"${key}\"`\n )\n logger.log('')\n if (success) {\n logger.log(`The discovered value is: \"${value}\"`)\n if (message) {\n logger.log('')\n logger.log(message)\n }\n } else {\n logger.log(`The discovery failed: ${message}`)\n }\n logger.log('')\n } else {\n if (message) {\n logger.log(message)\n logger.log('')\n }\n logger.log(`- ${key}: ${value}`)\n logger.log('')\n\n if (success) {\n if (key === 'defaultOrg') {\n const proceed = await select<string>({\n message:\n 'Would you like to update the default org in local config to this value?',\n choices: (Array.isArray(value) ? value : [value])\n .map(slug => ({\n name: 'Yes [' + slug + ']',\n value: slug,\n description: `Use \"${slug}\" as the default organization`\n }))\n .concat({\n name: 'No',\n value: '',\n description: 'Do not use any of these organizations'\n })\n })\n if (proceed) {\n logger.log(\n `OK. Setting defaultOrg to \"${proceed}\".\\nYou should no longer need to add the org to commands that normally require it.`\n )\n updateConfigValue('defaultOrg', proceed)\n } else {\n logger.log('OK. No changes made.')\n }\n } else if (key === 'enforcedOrgs') {\n const proceed = await select<string>({\n message:\n 'Would you like to update the enforced orgs in local config to this value?',\n choices: (Array.isArray(value) ? value : [value])\n .map(slug => ({\n name: 'Yes [' + slug + ']',\n value: slug,\n description: `Enforce the security policy of \"${slug}\" on this machine`\n }))\n .concat({\n name: 'No',\n value: '',\n description: 'Do not use any of these organizations'\n })\n })\n if (proceed) {\n logger.log(`OK. Setting enforcedOrgs key to \"${proceed}\".`)\n updateConfigValue('defaultOrg', proceed)\n } else {\n logger.log('OK. No changes made.')\n }\n }\n }\n }\n}\n","import { discoverConfigValue } from './discover-config-value'\nimport { outputConfigAuto } from './output-config-auto'\n\nimport type { LocalConfig } from '../../utils/config'\n\nexport async function handleConfigAuto({\n key,\n outputKind\n}: {\n key: keyof LocalConfig\n outputKind: 'json' | 'markdown' | 'text'\n}) {\n const result = await discoverConfigValue(key)\n\n await outputConfigAuto(key, result, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleConfigAuto } from './handle-config-auto'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { supportedConfigKeys } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { LocalConfig } from '../../utils/config'\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'auto',\n description: 'Automatically discover and set the correct value config item',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug>\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Attempt to automatically discover the correct value for a certain config key.\n\n For certain keys it will request the value from server, for others it will\n reset the value to the default. For some keys this has no effect.\n\n Keys:\n\n${Array.from(supportedConfigKeys.entries())\n .map(([key, desc]) => ` - ${key} -- ${desc}`)\n .join('\\n')}\n\n Examples\n $ ${command} auto defaultOrg\n `\n}\n\nexport const cmdConfigAuto = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const [key = ''] = cli.input\n\n const wasBadInput = handleBadInput(\n {\n test: supportedConfigKeys.has(key as keyof LocalConfig) && key !== 'test',\n message: 'Config key should be the first arg',\n pass: 'ok',\n fail: key ? 'invalid config key' : 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleConfigAuto({\n key: key as keyof LocalConfig,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text'\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { LocalConfig } from '../../utils/config'\n\nexport async function outputConfigGet(\n key: keyof LocalConfig,\n value: unknown,\n readOnly: boolean, // Is config in read-only mode? (Overrides applied)\n outputKind: 'json' | 'markdown' | 'text'\n) {\n if (outputKind === 'json') {\n logger.log(\n JSON.stringify({ success: true, result: { key, value }, readOnly })\n )\n } else if (outputKind === 'markdown') {\n logger.log(`# Config Value`)\n logger.log('')\n logger.log(`Config key '${key}' has value '${value}`)\n if (readOnly) {\n logger.log('')\n logger.log(\n 'Note: the config is in read-only mode, meaning at least one key was temporarily\\n overridden from an env var or command flag.'\n )\n }\n } else {\n logger.log(`${key}: ${value}`)\n if (readOnly) {\n logger.log('')\n logger.log(\n 'Note: the config is in read-only mode, meaning at least one key was temporarily overridden from an env var or command flag.'\n )\n }\n }\n}\n","import { outputConfigGet } from './output-config-get'\nimport { getConfigValue, isReadOnlyConfig } from '../../utils/config'\n\nimport type { LocalConfig } from '../../utils/config'\n\nexport async function handleConfigGet({\n key,\n outputKind\n}: {\n key: keyof LocalConfig\n outputKind: 'json' | 'markdown' | 'text'\n}) {\n const value = getConfigValue(key)\n const readOnly = isReadOnlyConfig()\n\n await outputConfigGet(key, value, readOnly, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleConfigGet } from './handle-config-get'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { supportedConfigKeys } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { LocalConfig } from '../../utils/config'\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'get',\n description: 'Get the value of a local CLI config item',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug>\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Keys:\n\n${Array.from(supportedConfigKeys.entries())\n .map(([key, desc]) => ` - ${key} -- ${desc}`)\n .join('\\n')}\n\n Examples\n $ ${command} FakeOrg --repoName=test-repo\n `\n}\n\nexport const cmdConfigGet = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const [key = ''] = cli.input\n\n const wasBadInput = handleBadInput(\n {\n test: supportedConfigKeys.has(key as keyof LocalConfig) || key === 'test',\n message: 'Config key should be the first arg',\n pass: 'ok',\n fail: key ? 'invalid config key' : 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleConfigGet({\n key: key as keyof LocalConfig,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text'\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport {\n getConfigValue,\n isReadOnlyConfig,\n sensitiveConfigKeys,\n supportedConfigKeys\n} from '../../utils/config'\n\nexport async function outputConfigList({\n full,\n outputKind\n}: {\n full: boolean\n outputKind: 'json' | 'markdown' | 'text'\n}) {\n const readOnly = isReadOnlyConfig()\n if (outputKind === 'json') {\n const obj: Record<string, unknown> = {}\n for (const key of supportedConfigKeys.keys()) {\n let value = getConfigValue(key)\n if (!full && sensitiveConfigKeys.has(key)) {\n value = '********'\n }\n if (full || value !== undefined) {\n obj[key as any] = value ?? '<none>'\n }\n }\n logger.log(\n JSON.stringify(\n {\n success: true,\n full,\n config: obj,\n readOnly\n },\n null,\n 2\n )\n )\n } else {\n const maxWidth = Array.from(supportedConfigKeys.keys()).reduce(\n (a, b) => Math.max(a, b.length),\n 0\n )\n\n logger.log('# Local CLI Config')\n logger.log('')\n logger.log(`This is the local CLI config (full=${!!full}):`)\n logger.log('')\n for (const key of supportedConfigKeys.keys()) {\n let value = getConfigValue(key)\n if (!full && sensitiveConfigKeys.has(key)) {\n value = '********'\n }\n if (full || value !== undefined) {\n logger.log(\n `- ${key}:${' '.repeat(Math.max(0, maxWidth - key.length + 3))} ${Array.isArray(value) ? value.join(', ') || '<none>' : (value ?? '<none>')}`\n )\n }\n }\n if (readOnly) {\n logger.log('')\n logger.log(\n 'Note: the config is in read-only mode, meaning at least one key was temporarily\\n overridden from an env var or command flag.'\n )\n }\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { outputConfigList } from './output-config-list'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { supportedConfigKeys } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'list',\n description: 'Show all local CLI config items and their values',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n full: {\n type: 'boolean',\n default: false,\n description: 'Show full tokens in plaintext (unsafe)'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug>\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Keys:\n\n${Array.from(supportedConfigKeys.entries())\n .map(([key, desc]) => ` - ${key} -- ${desc}`)\n .join('\\n')}\n\n Examples\n $ ${command} FakeOrg --repoName=test-repo\n `\n}\n\nexport const cmdConfigList = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { full, json, markdown } = cli.flags\n\n const wasBadInput = handleBadInput({\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n })\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await outputConfigList({\n full: !!full,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text'\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { LocalConfig } from '../../utils/config'\n\nexport async function outputConfigSet(\n key: keyof LocalConfig,\n _value: string,\n readOnly: boolean,\n outputKind: 'json' | 'markdown' | 'text'\n) {\n if (outputKind === 'json') {\n logger.log(\n JSON.stringify({\n success: true,\n message: `Config key '${key}' was updated${readOnly ? ' (Note: since at least one value was overridden from flag/env, the config was not persisted)' : ''}`,\n readOnly\n })\n )\n } else if (outputKind === 'markdown') {\n logger.log(`# Update config`)\n logger.log('')\n logger.log(`Config key '${key}' was updated`)\n if (readOnly) {\n logger.log('')\n logger.log(\n 'Note: The change was not persisted because the config is in read-only mode,\\n meaning at least one key was temporarily overridden from an env var or\\n command flag.'\n )\n }\n } else {\n logger.log(`OK`)\n if (readOnly) {\n logger.log('')\n logger.log(\n 'Note: The change was not persisted because the config is in read-only mode, meaning at least one key was temporarily overridden from an env var or command flag.'\n )\n }\n }\n}\n","import { outputConfigSet } from './output-config-set'\nimport { isReadOnlyConfig, updateConfigValue } from '../../utils/config'\n\nimport type { LocalConfig } from '../../utils/config'\n\nexport async function handleConfigSet({\n key,\n outputKind,\n value\n}: {\n key: keyof LocalConfig\n outputKind: 'json' | 'markdown' | 'text'\n value: string\n}) {\n updateConfigValue(key, value)\n const readOnly = isReadOnlyConfig()\n\n await outputConfigSet(key, value, readOnly, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleConfigSet } from './handle-config-set'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { supportedConfigKeys } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { LocalConfig } from '../../utils/config'\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'set',\n description: 'Update the value of a local CLI config item',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <key> <value>\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n This is a crude way of updating the local configuration for this CLI tool.\n\n Note that updating a value here is nothing more than updating a key/value\n store entry. No validation is happening. The server may reject your config.\n\n Keys:\n\n${Array.from(supportedConfigKeys.entries())\n .map(([key, desc]) => ` - ${key} -- ${desc}`)\n .join('\\n')}\n\n Examples\n $ ${command} apiProxy https://example.com\n `\n}\n\nexport const cmdConfigSet = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const [key = '', ...rest] = cli.input\n const value = rest.join(' ')\n\n const wasBadInput = handleBadInput(\n {\n test: key === 'test' || supportedConfigKeys.has(key as keyof LocalConfig),\n message: 'Config key should be the first arg',\n pass: 'ok',\n fail: key ? 'invalid config key' : 'missing'\n },\n {\n test: !!value, // This is a string, empty string is not ok\n message:\n 'Key value should be the remaining args (use `unset` to unset a value)',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleConfigSet({\n key: key as keyof LocalConfig,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text',\n value\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { LocalConfig } from '../../utils/config'\n\nexport async function outputConfigUnset(\n key: keyof LocalConfig,\n outputKind: 'json' | 'markdown' | 'text'\n) {\n if (outputKind === 'json') {\n logger.log(\n JSON.stringify({\n success: true,\n message: `Config key '${key}' was unset`\n })\n )\n } else if (outputKind === 'markdown') {\n logger.log(`# Update config`)\n logger.log('')\n logger.log(`Config key '${key}' was unset`)\n } else {\n logger.log(`OK`)\n }\n}\n","import { outputConfigUnset } from './output-config-unset'\nimport { updateConfigValue } from '../../utils/config'\n\nimport type { LocalConfig } from '../../utils/config'\n\nexport async function handleConfigUnset({\n key,\n outputKind\n}: {\n key: keyof LocalConfig\n outputKind: 'json' | 'markdown' | 'text'\n}) {\n updateConfigValue(key, undefined)\n await outputConfigUnset(key, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleConfigUnset } from './handle-config-unset'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { supportedConfigKeys } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { LocalConfig } from '../../utils/config'\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'unset',\n description: 'Clear the value of a local CLI config item',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug>\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Keys:\n\n${Array.from(supportedConfigKeys.entries())\n .map(([key, desc]) => ` - ${key} -- ${desc}`)\n .join('\\n')}\n\n Examples\n $ ${command} FakeOrg --repoName=test-repo\n `\n}\n\nexport const cmdConfigUnset = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const [key = ''] = cli.input\n\n const wasBadInput = handleBadInput(\n {\n test: key === 'test' || supportedConfigKeys.has(key as keyof LocalConfig),\n message: 'Config key should be the first arg',\n pass: 'ok',\n fail: key ? 'invalid config key' : 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleConfigUnset({\n key: key as keyof LocalConfig,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text'\n })\n}\n","import { cmdConfigAuto } from './cmd-config-auto'\nimport { cmdConfigGet } from './cmd-config-get'\nimport { cmdConfigList } from './cmd-config-list'\nimport { cmdConfigSet } from './cmd-config-set'\nimport { cmdConfigUnset } from './cmd-config-unset'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\n\nimport type { CliSubcommand } from '../../utils/meow-with-subcommands'\n\nconst description = 'Commands related to the local CLI configuration'\n\nexport const cmdConfig: CliSubcommand = {\n description,\n hidden: true, // [beta]\n async run(argv, importMeta, { parentName }) {\n await meowWithSubcommands(\n {\n auto: cmdConfigAuto,\n get: cmdConfigGet,\n list: cmdConfigList,\n set: cmdConfigSet,\n unset: cmdConfigUnset\n },\n {\n argv,\n description,\n importMeta,\n name: `${parentName} config`\n }\n )\n }\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchDependencies({\n limit,\n offset\n}: {\n limit: number\n offset: number\n}): Promise<SocketSdkReturnType<'searchDependencies'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching organization dependencies...')\n\n const result = await handleApiCall(\n sockSdk.searchDependencies({ limit, offset }),\n 'Searching dependencies'\n )\n\n spinner.successAndStop('Received organization dependencies response.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('searchDependencies', result)\n }\n\n return result.data\n}\n","// @ts-ignore\nimport chalkTable from 'chalk-table'\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputDependencies(\n data: SocketSdkReturnType<'searchDependencies'>['data'],\n {\n limit,\n offset,\n outputKind\n }: {\n limit: number\n offset: number\n outputKind: 'json' | 'markdown' | 'text'\n }\n): Promise<void> {\n if (outputKind === 'json') {\n let json\n try {\n json = JSON.stringify(data, null, 2)\n } catch (e) {\n process.exitCode = 1\n logger.fail(\n 'There was a problem converting the data to JSON, please try without the `--json` flag'\n )\n return\n }\n\n logger.log(json)\n return\n }\n\n logger.log(\n 'Request details: Offset:',\n offset,\n ', limit:',\n limit,\n ', is there more data after this?',\n data.end ? 'no' : 'yes'\n )\n\n const options = {\n columns: [\n { field: 'namespace', name: colors.cyan('Namespace') },\n { field: 'name', name: colors.cyan('Name') },\n { field: 'version', name: colors.cyan('Version') },\n { field: 'repository', name: colors.cyan('Repository') },\n { field: 'branch', name: colors.cyan('Branch') },\n { field: 'type', name: colors.cyan('Type') },\n { field: 'direct', name: colors.cyan('Direct') }\n ]\n }\n\n logger.log(chalkTable(options, data.rows))\n}\n","import { fetchDependencies } from './fetch-dependencies'\nimport { outputDependencies } from './output-dependencies'\n\nexport async function handleDependencies({\n limit,\n offset,\n outputKind\n}: {\n limit: number\n offset: number\n outputKind: 'json' | 'markdown' | 'text'\n}): Promise<void> {\n const data = await fetchDependencies({ limit, offset })\n if (!data) {\n return\n }\n\n await outputDependencies(data, { limit, offset, outputKind })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleDependencies } from './handle-dependencies'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'dependencies',\n description:\n 'Search for any dependency that is being used in your organization',\n hidden: false,\n flags: {\n ...commonFlags,\n limit: {\n type: 'number',\n shortFlag: 'l',\n default: 50,\n description: 'Maximum number of dependencies returned'\n },\n offset: {\n type: 'number',\n shortFlag: 'o',\n default: 0,\n description: 'Page number'\n },\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n ${command}\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: none (does need token with access to target org)\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n ${command} --limit 20 --offset 10\n `\n}\n\nexport const cmdScanCreate = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, limit, markdown, offset } = cli.flags\n\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleDependencies({\n limit: Number(limit || 0) || 0,\n offset: Number(offset || 0) || 0,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text'\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { handleApiCall, handleApiError, queryApi } from '../../utils/api'\nimport { failMsgWithBadge } from '../../utils/fail-msg-with-badge'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchDiffScan({\n after,\n before,\n orgSlug\n}: {\n after: string\n before: string\n orgSlug: string\n}): Promise<SocketSdkReturnType<'GetOrgDiffScan'>['data'] | undefined> {\n const apiToken = getDefaultToken()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching diff-scan...')\n\n const response = await queryApi(\n `orgs/${orgSlug}/full-scans/diff?before=${encodeURIComponent(before)}&after=${encodeURIComponent(after)}`,\n apiToken || ''\n )\n\n spinner.successAndStop('Received diff-scan response')\n\n if (!response.ok) {\n const err = await handleApiError(response.status)\n logger.fail(failMsgWithBadge(response.statusText, err))\n return\n }\n\n const result = await handleApiCall(\n (await response.json()) as Promise<\n SocketSdkReturnType<'GetOrgDiffScan'>['data']\n >,\n 'Deserializing json'\n )\n\n return result\n}\n","import fs from 'node:fs'\nimport util from 'node:util'\n\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputDiffScan(\n result: SocketSdkReturnType<'GetOrgDiffScan'>['data'],\n {\n depth,\n file,\n outputKind\n }: {\n depth: number\n file: string\n outputKind: 'json' | 'markdown' | 'text'\n }\n): Promise<void> {\n const dashboardUrl = result.diff_report_url\n const dashboardMessage = dashboardUrl\n ? `\\n View this diff scan in the Socket dashboard: ${colors.cyan(dashboardUrl)}`\n : ''\n\n // When forcing json, or dumping to file, serialize to string such that it\n // won't get truncated. The only way to dump the full raw JSON to stdout is\n // to use `--json --file -` (the dash is a standard notation for stdout)\n if (outputKind === 'json' || file) {\n let json\n try {\n json = JSON.stringify(result, null, 2)\n } catch (e) {\n process.exitCode = 1\n // Most likely caused by a circular reference (or OOM)\n logger.fail('There was a problem converting the data to JSON')\n logger.error(e)\n return\n }\n\n if (file && file !== '-') {\n logger.log(`Writing json to \\`${file}\\``)\n fs.writeFile(file, JSON.stringify(result, null, 2), err => {\n if (err) {\n logger.fail(`Writing to \\`${file}\\` failed...`)\n logger.error(err)\n } else {\n logger.log(`Data successfully written to \\`${file}\\``)\n }\n logger.error(dashboardMessage)\n })\n } else {\n // TODO: expose different method for writing to stderr when simply dodging stdout\n logger.error(`\\n Diff scan result: \\n`)\n logger.log(json)\n logger.error(dashboardMessage)\n }\n\n return\n }\n\n // In this case neither the --json nor the --file flag was passed\n // Dump the JSON to CLI and let NodeJS deal with truncation\n\n logger.log('Diff scan result:')\n logger.log(\n util.inspect(result, {\n showHidden: false,\n depth: depth > 0 ? depth : null,\n colors: true,\n maxArrayLength: null\n })\n )\n logger.log(\n `\\n 📝 To display the detailed report in the terminal, use the --json flag \\n`\n )\n logger.log(dashboardMessage)\n}\n","import { fetchDiffScan } from './fetch-diff-scan'\nimport { outputDiffScan } from './output-diff-scan'\n\nexport async function handleDiffScan({\n after,\n before,\n depth,\n file,\n orgSlug,\n outputKind\n}: {\n after: string\n before: string\n depth: number\n file: string\n orgSlug: string\n outputKind: 'json' | 'markdown' | 'text'\n}): Promise<void> {\n const data = await fetchDiffScan({\n after,\n before,\n orgSlug\n })\n if (!data) {\n return\n }\n\n await outputDiffScan(data, {\n depth,\n file,\n outputKind\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleDiffScan } from './handle-diff-scan'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'get',\n description: 'Get a diff scan for an organization',\n hidden: false,\n flags: {\n ...commonFlags,\n after: {\n type: 'string',\n shortFlag: 'a',\n default: '',\n description: 'The scan ID of the head scan'\n },\n before: {\n type: 'string',\n shortFlag: 'b',\n default: '',\n description: 'The scan ID of the base scan'\n },\n depth: {\n type: 'number',\n default: 2,\n description:\n 'Max depth of JSON to display before truncating, use zero for no limit (without --json/--file)'\n },\n json: {\n type: 'boolean',\n shortFlag: 'j',\n default: false,\n description:\n 'Output result as json. This can be big. Use --file to store it to disk without truncation.'\n },\n file: {\n type: 'string',\n shortFlag: 'f',\n default: '',\n description:\n 'Path to a local file where the output should be saved. Use `-` to force stdout.'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> --before=<before> --after=<after>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: full-scans:list\n\n This command displays the package changes between two scans. The full output\n can be pretty large depending on the size of your repo and time range. It is\n best stored to disk to be further analyzed by other tools.\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeCorp --before=aaa0aa0a-aaaa-0000-0a0a-0000000a00a0 --after=aaa1aa1a-aaaa-1111-1a1a-1111111a11a1\n `\n}\n\nexport const cmdDiffScanGet = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { after, before, depth, file, json, markdown } = cli.flags\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n test: !!(before && after),\n message:\n 'Specify a before and after scan ID.\\nThe args are expecting a full `aaa0aa0a-aaaa-0000-0a0a-0000000a00a0` scan ID.',\n pass: 'ok',\n fail:\n !before && !after\n ? 'missing before and after'\n : !before\n ? 'missing before'\n : 'missing after'\n },\n {\n test: !!orgSlug,\n nook: true,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n logger.fail(\n 'Warning: this command is deprecated in favor of `socket scan diff` and will be removed in the next major bump.'\n )\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleDiffScan({\n before: String(before || ''),\n after: String(after || ''),\n depth: Number(depth),\n orgSlug,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text',\n file: String(file || '')\n })\n}\n","import { cmdDiffScanGet } from './cmd-diff-scan-get'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\n\nimport type { CliSubcommand } from '../../utils/meow-with-subcommands'\n\nconst description = 'Diff scans related commands'\n\nexport const cmdDiffScan: CliSubcommand = {\n description,\n // Hidden because it was broken all this time (nobody could be using it)\n // and we're not sure if it's useful to anyone in its current state.\n // Until we do, we'll hide this to keep the help tidier.\n // And later, we may simply move this under `scan`, anyways.\n hidden: true,\n async run(argv, importMeta, { parentName }) {\n await meowWithSubcommands(\n {\n get: cmdDiffScanGet\n },\n {\n argv,\n description,\n importMeta,\n name: parentName + ' diff-scan'\n }\n )\n }\n}\n","import path from 'node:path'\n\nimport { PackageURL } from '@socketregistry/packageurl-js'\nimport { debugLog } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { normalizePath } from '@socketsecurity/registry/lib/path'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport constants from '../../constants'\n\nconst { GITHUB_REF_NAME } = constants\n\nfunction formatBranchName(str: string): string {\n return str\n .replace(/[-_.\\\\/]+/g, '-')\n .replace(/[^-a-zA-Z0-9]+/g, '')\n .replace(/^-+|-+$/g, '')\n}\n\nfunction getPkgNameFromPurlObj(purlObj: PackageURL): string {\n return `${purlObj.namespace ? `${purlObj.namespace}/` : ''}${purlObj.name}`\n}\n\nexport function getBaseGitBranch() {\n // Lazily access constants.ENV[GITHUB_REF_NAME].\n return (\n constants.ENV[GITHUB_REF_NAME] ??\n // GitHub defaults to branch name \"main\"\n // https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-branches#about-the-default-branch\n 'main'\n )\n}\n\nexport function getSocketBranchName(\n purl: string,\n newVersion: string,\n workspaceName?: string | undefined\n): string {\n const purlObj = PackageURL.fromString(purl)\n const maybeWorkspaceName = workspaceName\n ? `${formatBranchName(workspaceName)}-`\n : ''\n const maybeNamespace = purlObj.namespace\n ? `${formatBranchName(purlObj.namespace)}-`\n : ''\n const fullName = `${maybeWorkspaceName}${maybeNamespace}${formatBranchName(purlObj.name)}`\n return `socket-fix-${fullName}-${formatBranchName(newVersion)}`\n}\n\nexport function getSocketPullRequestTitle(\n purl: string,\n newVersion: string,\n workspaceName?: string | undefined\n): string {\n const purlObj = PackageURL.fromString(purl)\n const pkgName = getPkgNameFromPurlObj(purlObj)\n const workspaceDetails = workspaceName ? ` in ${workspaceName}` : ''\n return `Bump ${pkgName} from ${purlObj.version} to ${newVersion}${workspaceDetails}`\n}\n\nexport function getSocketPullRequestBody(\n purl: string,\n newVersion: string,\n workspaceName?: string | undefined\n): string {\n const purlObj = PackageURL.fromString(purl)\n const pkgName = getPkgNameFromPurlObj(purlObj)\n const workspaceDetails = workspaceName ? ` in ${workspaceName}` : ''\n return `Bumps [${pkgName}](https://socket.dev/${purlObj.type}/package/${pkgName}) from ${purlObj.version} to ${newVersion}${workspaceDetails}.`\n}\n\nexport function getSocketCommitMessage(\n purl: string,\n newVersion: string,\n workspaceName?: string | undefined\n): string {\n const purlObj = PackageURL.fromString(purl)\n const pkgName = getPkgNameFromPurlObj(purlObj)\n const workspaceDetails = workspaceName ? ` in ${workspaceName}` : ''\n return `socket: Bump ${pkgName} from ${purlObj.version} to ${newVersion}${workspaceDetails}`\n}\n\nexport async function gitBranchExists(\n branch: string,\n cwd: string | undefined = process.cwd()\n): Promise<boolean> {\n try {\n await spawn(\n 'git',\n ['show-ref', '--verify', '--quiet', `refs/heads/${branch}`],\n {\n cwd,\n stdio: 'ignore'\n }\n )\n return true\n } catch {}\n return false\n}\n\nexport async function gitCheckoutBaseBranchIfAvailable(\n baseBranch: string,\n cwd = process.cwd()\n) {\n try {\n await gitHardReset()\n await spawn('git', ['fetch', '--depth=1', 'origin', baseBranch], { cwd })\n await spawn('git', ['checkout', baseBranch], { cwd })\n await spawn('git', ['reset', '--hard', `origin/${baseBranch}`], { cwd })\n logger.info(`Checked out and reset to ${baseBranch}`)\n } catch (e) {\n logger.warn(`Could not switch to ${baseBranch}. Proceeding with HEAD.`)\n debugLog(e)\n }\n}\n\nexport async function gitCreateAndPushBranchIfNeeded(\n branch: string,\n commitMsg: string,\n cwd = process.cwd()\n): Promise<boolean> {\n if (await gitBranchExists(branch, cwd)) {\n logger.warn(`Branch \"${branch}\" already exists. Skipping creation.`)\n return false\n }\n await spawn('git', ['checkout', '-b', branch], { cwd })\n const moddedFilepaths = (await gitUnstagedModifiedFiles(cwd)).filter(p => {\n const basename = path.basename(p)\n return (\n basename === 'package.json' ||\n basename === 'package-lock.json' ||\n basename === 'pnpm-lock.yaml'\n )\n })\n debugLog('branch', branch)\n debugLog('gitCreateAndPushBranchIfNeeded > moddedFilepaths', moddedFilepaths)\n if (moddedFilepaths.length) {\n await spawn('git', ['add', ...moddedFilepaths], { cwd })\n }\n await spawn('git', ['commit', '-m', commitMsg], { cwd })\n await spawn('git', ['push', '--set-upstream', 'origin', branch], { cwd })\n return true\n}\n\nexport async function gitHardReset(cwd = process.cwd()): Promise<void> {\n await spawn('git', ['reset', '--hard'], { cwd })\n}\n\nasync function gitUnstagedModifiedFiles(\n cwd = process.cwd()\n): Promise<string[]> {\n const { stdout } = await spawn('git', ['diff', '--name-only'], { cwd })\n const rawFiles = stdout?.trim().split('\\n') ?? []\n return rawFiles.map(relPath => normalizePath(relPath))\n}\n\nexport async function isInGitRepo(cwd = process.cwd()): Promise<boolean> {\n try {\n await spawn('git', ['rev-parse', '--is-inside-work-tree'], {\n cwd,\n stdio: 'ignore'\n })\n return true\n } catch {}\n return false\n}\n","import {\n GraphqlResponseError,\n graphql as OctokitGraphql\n} from '@octokit/graphql'\nimport { RequestError } from '@octokit/request-error'\nimport { Octokit } from '@octokit/rest'\nimport { codeBlock } from 'common-tags'\n\nimport { debugLog } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport { getSocketPullRequestBody, getSocketPullRequestTitle } from './git'\nimport constants from '../../constants'\n\nimport type { components } from '@octokit/openapi-types'\nimport type { OctokitResponse } from '@octokit/types'\n\ntype PullsCreateResponseData = components['schemas']['pull-request']\n\nconst { GITHUB_ACTIONS, GITHUB_REPOSITORY, SOCKET_SECURITY_GITHUB_PAT } =\n constants\n\ntype GitHubRepoInfo = {\n owner: string\n repo: string\n}\n\nlet _octokit: Octokit | undefined\nfunction getOctokit() {\n if (_octokit === undefined) {\n _octokit = new Octokit({\n // Lazily access constants.ENV[SOCKET_SECURITY_GITHUB_PAT].\n auth: constants.ENV[SOCKET_SECURITY_GITHUB_PAT]\n })\n }\n return _octokit\n}\n\nlet _octokitGraphql: typeof OctokitGraphql | undefined\nexport function getOctokitGraphql() {\n if (!_octokitGraphql) {\n _octokitGraphql = OctokitGraphql.defaults({\n headers: {\n // Lazily access constants.ENV[SOCKET_SECURITY_GITHUB_PAT].\n authorization: `token ${constants.ENV[SOCKET_SECURITY_GITHUB_PAT]}`\n }\n })\n }\n return _octokitGraphql\n}\n\nexport async function doesPullRequestExistForBranch(\n owner: string,\n repo: string,\n branch: string\n): Promise<boolean> {\n const octokit = getOctokit()\n try {\n const { data: prs } = await octokit.pulls.list({\n owner,\n repo,\n head: `${owner}:${branch}`,\n state: 'open'\n })\n debugLog('doesPullRequestExistForBranch > prs', prs)\n return prs.length > 0\n } catch {}\n return false\n}\n\nexport async function enableAutoMerge({\n node_id: prId,\n number: prNumber\n}: PullsCreateResponseData): Promise<boolean> {\n const octokitGraphql = getOctokitGraphql()\n try {\n await octokitGraphql(\n codeBlock`\n mutation EnableAutoMerge($pullRequestId: ID!) {\n enablePullRequestAutoMerge(input: {\n pullRequestId: $pullRequestId,\n mergeMethod: SQUASH\n }) {\n pullRequest {\n number\n autoMergeRequest {\n enabledAt\n }\n }\n }\n }\n `,\n {\n pullRequestId: prId\n }\n )\n logger.info(`Auto-merge enabled for PR #${prNumber}`)\n return true\n } catch (e) {\n let message = `Failed to enable auto-merge for PR #${prNumber}`\n if (e instanceof GraphqlResponseError && e.errors) {\n const details = e.errors\n .map(({ message }) => ` - ${message.trim()}`)\n .join('\\n')\n message += `:\\n${details}`\n }\n logger.error(message)\n return false\n }\n}\n\nexport function getGitHubEnvRepoInfo(): GitHubRepoInfo {\n // Lazily access constants.ENV[GITHUB_REPOSITORY].\n const ownerSlashRepo = constants.ENV[GITHUB_REPOSITORY]\n const slashIndex = ownerSlashRepo.indexOf('/')\n if (slashIndex === -1) {\n throw new Error('Missing GITHUB_REPOSITORY environment variable')\n }\n return {\n owner: ownerSlashRepo.slice(0, slashIndex),\n repo: ownerSlashRepo.slice(slashIndex + 1)\n }\n}\n\nexport type OpenGitHubPullRequestOptions = {\n cwd?: string | undefined\n workspaceName?: string | undefined\n}\n\nexport async function openGitHubPullRequest(\n owner: string,\n repo: string,\n baseBranch: string,\n branch: string,\n purl: string,\n newVersion: string,\n options?: OpenGitHubPullRequestOptions | undefined\n): Promise<OctokitResponse<PullsCreateResponseData> | null> {\n const { cwd = process.cwd(), workspaceName } = {\n __proto__: null,\n ...options\n } as OpenGitHubPullRequestOptions\n // Lazily access constants.ENV[GITHUB_ACTIONS].\n if (constants.ENV[GITHUB_ACTIONS]) {\n // Lazily access constants.ENV[SOCKET_SECURITY_GITHUB_PAT].\n const pat = constants.ENV[SOCKET_SECURITY_GITHUB_PAT]\n if (!pat) {\n throw new Error('Missing SOCKET_SECURITY_GITHUB_PAT environment variable')\n }\n const url = `https://x-access-token:${pat}@github.com/${owner}/${repo}`\n await spawn('git', ['remote', 'set-url', 'origin', url], {\n cwd\n })\n const octokit = getOctokit()\n try {\n return await octokit.pulls.create({\n owner,\n repo,\n title: getSocketPullRequestTitle(purl, newVersion, workspaceName),\n head: branch,\n base: baseBranch,\n body: getSocketPullRequestBody(purl, newVersion, workspaceName)\n })\n } catch (e) {\n let message = `Failed to open pull request`\n if (e instanceof RequestError) {\n const restErrors = (e.response?.data as any)?.['errors']\n if (Array.isArray(restErrors)) {\n const details = restErrors\n .map(\n restErr =>\n `- ${restErr.message?.trim() ?? `${restErr.resource}.${restErr.field} (${restErr.code})`}`\n )\n .join('\\n')\n message += `:\\n${details}`\n }\n }\n logger.error(message)\n return null\n }\n }\n throw new Error('Missing GITHUB_ACTIONS environment variable')\n}\n","import path from 'node:path'\n\nimport { getManifestData } from '@socketsecurity/registry'\nimport { arrayUnique } from '@socketsecurity/registry/lib/arrays'\nimport { runScript } from '@socketsecurity/registry/lib/npm'\nimport {\n fetchPackagePackument,\n readPackageJson\n} from '@socketsecurity/registry/lib/packages'\n\nimport {\n getBaseGitBranch,\n getSocketBranchName,\n getSocketCommitMessage,\n gitCheckoutBaseBranchIfAvailable,\n gitCreateAndPushBranchIfNeeded,\n gitHardReset,\n isInGitRepo\n} from './git'\nimport {\n doesPullRequestExistForBranch,\n enableAutoMerge,\n getGitHubEnvRepoInfo,\n openGitHubPullRequest\n} from './open-pr'\nimport { NormalizedFixOptions } from './types'\nimport constants from '../../constants'\nimport {\n Arborist,\n SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES,\n SafeArborist\n} from '../../shadow/npm/arborist/lib/arborist'\nimport {\n getAlertsMapFromArborist,\n getAlertsMapFromPurls\n} from '../../utils/alerts-map'\nimport {\n findPackageNode,\n findPackageNodes,\n updateNode,\n updatePackageJsonFromNode\n} from '../../utils/arborist-helpers'\nimport { globWorkspace } from '../../utils/glob'\nimport { applyRange } from '../../utils/semver'\nimport { getCveInfoByAlertsMap } from '../../utils/socket-package-alert'\n\nimport type { SafeNode } from '../../shadow/npm/arborist/lib/node'\nimport type { EnvDetails } from '../../utils/package-environment'\nimport type { PackageJson } from '@socketsecurity/registry/lib/packages'\n\nconst { CI, NPM } = constants\n\ntype InstallOptions = {\n cwd?: string | undefined\n}\n\nasync function install(\n idealTree: SafeNode,\n options: InstallOptions\n): Promise<void> {\n const { cwd = process.cwd() } = {\n __proto__: null,\n ...options\n } as InstallOptions\n const arb2 = new Arborist({ path: cwd })\n arb2.idealTree = idealTree\n await arb2.reify()\n}\n\nexport async function npmFix(\n pkgEnvDetails: EnvDetails,\n {\n autoMerge,\n cwd,\n purls,\n rangeStyle,\n spinner,\n test,\n testScript\n }: NormalizedFixOptions\n) {\n spinner?.start()\n\n const arb = new SafeArborist({\n path: pkgEnvDetails.pkgPath,\n ...SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES\n })\n // Calling arb.reify() creates the arb.diff object and nulls-out arb.idealTree.\n await arb.reify()\n\n const alertMapOptions = {\n consolidate: true,\n include: {\n existing: true,\n unfixable: false,\n upgradable: false\n },\n nothrow: true\n }\n\n const alertsMap = purls.length\n ? await getAlertsMapFromPurls(purls, alertMapOptions)\n : await getAlertsMapFromArborist(arb, alertMapOptions)\n\n const infoByPkg = getCveInfoByAlertsMap(alertsMap)\n if (!infoByPkg) {\n spinner?.stop()\n return\n }\n\n // Lazily access constants.ENV[CI].\n const isCi = constants.ENV[CI]\n const { pkgPath: rootPath } = pkgEnvDetails\n\n const { 0: isRepo, 1: workspacePkgJsonPaths } = await Promise.all([\n isInGitRepo(cwd),\n globWorkspace(pkgEnvDetails)\n ])\n const pkgJsonPaths = [\n pkgEnvDetails.editablePkgJson.filename!,\n ...workspacePkgJsonPaths\n ]\n\n await arb.buildIdealTree()\n\n for (const { 0: name, 1: infos } of infoByPkg) {\n const hasUpgrade = !!getManifestData(NPM, name)\n if (hasUpgrade) {\n spinner?.info(`Skipping ${name}. Socket Optimize package exists.`)\n continue\n }\n const oldVersions = arrayUnique(\n findPackageNodes(arb.idealTree!, name).map(n => n.version)\n )\n const packument =\n oldVersions.length && infos.length\n ? // eslint-disable-next-line no-await-in-loop\n await fetchPackagePackument(name)\n : null\n if (!packument) {\n continue\n }\n\n const failedSpecs = new Set<string>()\n const fixedSpecs = new Set<string>()\n const installedSpecs = new Set<string>()\n const testedSpecs = new Set<string>()\n const unavailableSpecs = new Set<string>()\n const revertedSpecs = new Set<string>()\n\n for (const pkgJsonPath of pkgJsonPaths) {\n for (const oldVersion of oldVersions) {\n const oldSpec = `${name}@${oldVersion}`\n const oldPurl = `pkg:npm/${oldSpec}`\n for (const {\n firstPatchedVersionIdentifier,\n vulnerableVersionRange\n } of infos) {\n const revertTree = arb.idealTree!\n arb.idealTree = null\n // eslint-disable-next-line no-await-in-loop\n await arb.buildIdealTree()\n\n const node = findPackageNode(arb.idealTree!, name, oldVersion)\n if (!node) {\n continue\n }\n\n if (\n !updateNode(\n node,\n packument,\n vulnerableVersionRange,\n firstPatchedVersionIdentifier\n )\n ) {\n if (!unavailableSpecs.has(oldSpec)) {\n unavailableSpecs.add(oldSpec)\n spinner?.fail(`No update available for ${oldSpec}`)\n }\n continue\n }\n\n const isWorkspaceRoot =\n pkgJsonPath === pkgEnvDetails.editablePkgJson.filename\n const workspaceName = isWorkspaceRoot\n ? ''\n : path.relative(rootPath, path.dirname(pkgJsonPath))\n const workspaceDetails = workspaceName ? ` in ${workspaceName}` : ''\n const editablePkgJson = isWorkspaceRoot\n ? pkgEnvDetails.editablePkgJson\n : // eslint-disable-next-line no-await-in-loop\n await readPackageJson(pkgJsonPath, { editable: true })\n\n const newVersion = node.package.version!\n const newVersionRange = applyRange(oldVersion, newVersion, rangeStyle)\n const newSpec = `${name}@${newVersionRange}`\n const newSpecKey = `${workspaceName ? `${workspaceName}>` : ''}${newSpec}`\n\n const revertData = {\n ...(editablePkgJson.content.dependencies\n ? { dependencies: editablePkgJson.content.dependencies }\n : undefined),\n ...(editablePkgJson.content.optionalDependencies\n ? {\n optionalDependencies:\n editablePkgJson.content.optionalDependencies\n }\n : undefined),\n ...(editablePkgJson.content.peerDependencies\n ? { peerDependencies: editablePkgJson.content.peerDependencies }\n : undefined)\n } as PackageJson\n\n const branch = isCi\n ? getSocketBranchName(oldPurl, newVersion, workspaceName)\n : ''\n const baseBranch = isCi ? getBaseGitBranch() : ''\n const { owner, repo } = isCi\n ? getGitHubEnvRepoInfo()\n : { owner: '', repo: '' }\n const shouldOpenPr = isCi\n ? // eslint-disable-next-line no-await-in-loop\n !(await doesPullRequestExistForBranch(owner, repo, branch))\n : false\n\n if (isCi) {\n // eslint-disable-next-line no-await-in-loop\n await gitCheckoutBaseBranchIfAvailable(baseBranch, cwd)\n }\n\n updatePackageJsonFromNode(\n editablePkgJson,\n arb.idealTree!,\n node,\n newVersion,\n rangeStyle\n )\n\n let error: unknown\n let errored = false\n let installed = false\n let saved = false\n\n // eslint-disable-next-line no-await-in-loop\n if (await editablePkgJson.save()) {\n saved = true\n }\n\n if (!installedSpecs.has(newSpecKey)) {\n testedSpecs.add(newSpecKey)\n spinner?.info(`Installing ${newSpec}${workspaceDetails}`)\n }\n\n try {\n // eslint-disable-next-line no-await-in-loop\n await install(arb.idealTree!, { cwd })\n installed = true\n\n if (test) {\n if (!testedSpecs.has(newSpecKey)) {\n testedSpecs.add(newSpecKey)\n spinner?.info(`Testing ${newSpec}${workspaceDetails}`)\n }\n // eslint-disable-next-line no-await-in-loop\n await runScript(testScript, [], { spinner, stdio: 'ignore' })\n }\n if (!fixedSpecs.has(newSpecKey)) {\n fixedSpecs.add(newSpecKey)\n spinner?.successAndStop(`Fixed ${name}${workspaceDetails}`)\n spinner?.start()\n }\n } catch (e) {\n error = e\n errored = true\n }\n\n if (!errored && shouldOpenPr) {\n // eslint-disable-next-line no-await-in-loop\n await gitCreateAndPushBranchIfNeeded(\n branch,\n getSocketCommitMessage(oldPurl, newVersion, workspaceName),\n cwd\n )\n // eslint-disable-next-line no-await-in-loop\n const prResponse = await openGitHubPullRequest(\n owner,\n repo,\n baseBranch,\n branch,\n oldPurl,\n newVersion,\n {\n cwd,\n workspaceName\n }\n )\n if (prResponse && autoMerge) {\n // eslint-disable-next-line no-await-in-loop\n await enableAutoMerge(prResponse.data)\n }\n }\n\n if (errored || isCi) {\n if (errored) {\n if (!revertedSpecs.has(newSpecKey)) {\n revertedSpecs.add(newSpecKey)\n spinner?.error(`Reverting ${newSpec}${workspaceDetails}`, error)\n }\n }\n if (isRepo) {\n // eslint-disable-next-line no-await-in-loop\n await gitHardReset(cwd)\n }\n if (saved) {\n editablePkgJson.update(revertData)\n if (!isRepo) {\n // eslint-disable-next-line no-await-in-loop\n await editablePkgJson.save()\n }\n }\n if (!isRepo && installed) {\n // eslint-disable-next-line no-await-in-loop\n await install(revertTree, { cwd })\n }\n if (errored) {\n if (!failedSpecs.has(newSpecKey)) {\n failedSpecs.add(newSpecKey)\n spinner?.failAndStop(\n `Update failed for ${oldSpec}${workspaceDetails}`\n )\n }\n }\n }\n }\n }\n }\n }\n spinner?.stop()\n}\n","import process from 'node:process'\n\nimport { isDebug } from '@socketsecurity/registry/lib/debug'\nimport {\n isAuditFlag,\n isFundFlag,\n isLoglevelFlag,\n isProgressFlag\n} from '@socketsecurity/registry/lib/npm'\nimport { isObject } from '@socketsecurity/registry/lib/objects'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport constants from '../constants'\nimport { getNpmBinPath } from '../shadow/npm/paths'\n\nimport type { Spinner } from '@socketsecurity/registry/lib/spinner'\n\nconst {\n NPM,\n SOCKET_CLI_SAFE_BIN,\n SOCKET_CLI_SAFE_PROGRESS,\n SOCKET_IPC_HANDSHAKE\n} = constants\n\ntype SpawnOption = Exclude<Parameters<typeof spawn>[2], undefined>\n\ntype SafeNpmInstallOptions = SpawnOption & {\n agentExecPath?: string | undefined\n args?: string[] | readonly string[] | undefined\n ipc?: object | undefined\n spinner?: Spinner | undefined\n}\n\nexport function safeNpmInstall(options?: SafeNpmInstallOptions) {\n const {\n agentExecPath = getNpmBinPath(),\n args = [],\n ipc,\n spinner,\n ...spawnOptions\n } = { __proto__: null, ...options } as SafeNpmInstallOptions\n let stdio = spawnOptions.stdio\n const useIpc = isObject(ipc)\n // Include 'ipc' in the spawnOptions.stdio when an options.ipc object is provided.\n // See https://github.com/nodejs/node/blob/v23.6.0/lib/child_process.js#L161-L166\n // and https://github.com/nodejs/node/blob/v23.6.0/lib/internal/child_process.js#L238.\n if (typeof stdio === 'string') {\n stdio = useIpc ? [stdio, stdio, stdio, 'ipc'] : [stdio, stdio, stdio]\n } else if (useIpc && Array.isArray(stdio) && !stdio.includes('ipc')) {\n stdio = stdio.concat('ipc')\n }\n const useDebug = isDebug()\n const terminatorPos = args.indexOf('--')\n const rawBinArgs = terminatorPos === -1 ? args : args.slice(0, terminatorPos)\n const progressArg = rawBinArgs.findLast(isProgressFlag) !== '--no-progress'\n const binArgs = rawBinArgs.filter(\n a => !isAuditFlag(a) && !isFundFlag(a) && !isProgressFlag(a)\n )\n const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos)\n const isSilent = !useDebug && !binArgs.some(isLoglevelFlag)\n const logLevelArgs = isSilent ? ['--loglevel', 'silent'] : []\n const spawnPromise = spawn(\n // Lazily access constants.execPath.\n constants.execPath,\n [\n // Lazily access constants.nodeHardenFlags.\n ...constants.nodeHardenFlags,\n // Lazily access constants.nodeNoWarningsFlags.\n ...constants.nodeNoWarningsFlags,\n // Lazily access process.env['INLINED_SOCKET_CLI_SENTRY_BUILD'].\n ...(process.env['INLINED_SOCKET_CLI_SENTRY_BUILD']\n ? [\n '--require',\n // Lazily access constants.distInstrumentWithSentryPath.\n constants.distInstrumentWithSentryPath\n ]\n : []),\n '--require',\n // Lazily access constants.distShadowNpmInjectPath.\n constants.distShadowNpmInjectPath,\n agentExecPath,\n 'install',\n // Avoid code paths for 'audit' and 'fund'.\n '--no-audit',\n '--no-fund',\n // Add '--no-progress' to fix input being swallowed by the npm spinner.\n '--no-progress',\n // Add '--loglevel=silent' if a loglevel flag is not provided and the\n // SOCKET_CLI_DEBUG environment variable is not truthy.\n ...logLevelArgs,\n ...binArgs,\n ...otherArgs\n ],\n {\n spinner,\n ...spawnOptions,\n stdio,\n env: {\n ...process.env,\n ...spawnOptions.env\n }\n }\n )\n if (useIpc) {\n spawnPromise.process.send({\n [SOCKET_IPC_HANDSHAKE]: {\n [SOCKET_CLI_SAFE_BIN]: NPM,\n [SOCKET_CLI_SAFE_PROGRESS]: progressArg,\n ...ipc\n }\n })\n }\n return spawnPromise\n}\n","import { spawn } from '@socketsecurity/registry/lib/spawn'\nimport { Spinner } from '@socketsecurity/registry/lib/spinner'\n\nimport constants from '../constants'\nimport { cmdFlagsToString } from './cmd'\nimport { safeNpmInstall } from './npm'\n\nimport type { EnvDetails } from './package-environment'\n\nconst { NPM, PNPM } = constants\n\ntype SpawnOption = Exclude<Parameters<typeof spawn>[2], undefined>\n\ntype SpawnResult = ReturnType<typeof spawn>\n\nexport type AgentInstallOptions = SpawnOption & {\n args?: string[] | readonly string[] | undefined\n spinner?: Spinner | undefined\n}\n\nexport function runAgentInstall(\n pkgEnvDetails: EnvDetails,\n options?: AgentInstallOptions | undefined\n): SpawnResult {\n const { agent, agentExecPath } = pkgEnvDetails\n // All package managers support the \"install\" command.\n if (agent === NPM) {\n return safeNpmInstall({\n agentExecPath,\n ...options\n })\n }\n const {\n args = [],\n spinner,\n ...spawnOptions\n } = { __proto__: null, ...options } as AgentInstallOptions\n const skipNodeHardenFlags =\n agent === PNPM && pkgEnvDetails.agentVersion.major < 11\n return spawn(agentExecPath, ['install', ...args], {\n spinner,\n stdio: 'inherit',\n ...spawnOptions,\n env: {\n ...process.env,\n NODE_OPTIONS: cmdFlagsToString([\n ...(skipNodeHardenFlags\n ? []\n : // Lazily access constants.nodeHardenFlags.\n constants.nodeHardenFlags),\n // Lazily access constants.nodeNoWarningsFlags.\n ...constants.nodeNoWarningsFlags\n ]),\n ...spawnOptions.env\n }\n })\n}\n","import path from 'node:path'\n\nimport { readWantedLockfile } from '@pnpm/lockfile.fs'\n\nimport { getManifestData } from '@socketsecurity/registry'\nimport { arrayUnique } from '@socketsecurity/registry/lib/arrays'\nimport { debugLog, isDebug } from '@socketsecurity/registry/lib/debug'\nimport { runScript } from '@socketsecurity/registry/lib/npm'\nimport {\n fetchPackagePackument,\n readPackageJson\n} from '@socketsecurity/registry/lib/packages'\n\nimport {\n getBaseGitBranch,\n getSocketBranchName,\n getSocketCommitMessage,\n gitCheckoutBaseBranchIfAvailable,\n gitCreateAndPushBranchIfNeeded,\n gitHardReset,\n isInGitRepo\n} from './git'\nimport {\n doesPullRequestExistForBranch,\n enableAutoMerge,\n getGitHubEnvRepoInfo,\n openGitHubPullRequest\n} from './open-pr'\nimport constants from '../../constants'\nimport {\n SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES,\n SafeArborist\n} from '../../shadow/npm/arborist/lib/arborist'\nimport { runAgentInstall } from '../../utils/agent'\nimport {\n getAlertsMapFromPnpmLockfile,\n getAlertsMapFromPurls\n} from '../../utils/alerts-map'\nimport {\n findBestPatchVersion,\n findPackageNode,\n findPackageNodes,\n updatePackageJsonFromNode\n} from '../../utils/arborist-helpers'\nimport { globWorkspace } from '../../utils/glob'\nimport { applyRange } from '../../utils/semver'\nimport { getCveInfoByAlertsMap } from '../../utils/socket-package-alert'\n\nimport type { NormalizedFixOptions } from './types'\nimport type { SafeNode } from '../../shadow/npm/arborist/lib/node'\nimport type { StringKeyValueObject } from '../../types'\nimport type { EnvDetails } from '../../utils/package-environment'\nimport type { PackageJson } from '@socketsecurity/registry/lib/packages'\nimport type { Spinner } from '@socketsecurity/registry/lib/spinner'\n\nconst { CI, NPM, OVERRIDES, PNPM } = constants\n\ntype InstallOptions = {\n cwd?: string | undefined\n spinner?: Spinner | undefined\n}\n\nasync function getActualTree(cwd: string = process.cwd()): Promise<SafeNode> {\n const arb = new SafeArborist({\n path: cwd,\n ...SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES\n })\n return await arb.loadActual()\n}\n\nasync function install(\n pkgEnvDetails: EnvDetails,\n options: InstallOptions\n): Promise<SafeNode> {\n const { cwd, spinner } = { __proto__: null, ...options } as InstallOptions\n await runAgentInstall(pkgEnvDetails, {\n args: ['--no-frozen-lockfile'],\n spinner,\n stdio: isDebug() ? 'inherit' : 'ignore'\n })\n return await getActualTree(cwd)\n}\n\nexport async function pnpmFix(\n pkgEnvDetails: EnvDetails,\n {\n autoMerge,\n cwd,\n purls,\n rangeStyle,\n spinner,\n test,\n testScript\n }: NormalizedFixOptions\n) {\n const lockfile = await readWantedLockfile(pkgEnvDetails.pkgPath, {\n ignoreIncompatible: false\n })\n if (!lockfile) {\n return\n }\n\n const alertMapOptions = {\n consolidate: true,\n include: { existing: true, unfixable: false, upgradable: false },\n nothrow: true\n }\n\n const alertsMap = purls.length\n ? await getAlertsMapFromPurls(purls, alertMapOptions)\n : await getAlertsMapFromPnpmLockfile(lockfile, alertMapOptions)\n\n const infoByPkg = getCveInfoByAlertsMap(alertsMap)\n if (!infoByPkg) {\n return\n }\n\n spinner?.start()\n\n // Lazily access constants.ENV[CI].\n const isCi = constants.ENV[CI]\n const { pkgPath: rootPath } = pkgEnvDetails\n\n const {\n 0: isRepo,\n 1: workspacePkgJsonPaths,\n 2: initialTree\n } = await Promise.all([\n isInGitRepo(cwd),\n globWorkspace(pkgEnvDetails),\n getActualTree(cwd)\n ])\n const pkgJsonPaths = [\n pkgEnvDetails.editablePkgJson.filename!,\n ...workspacePkgJsonPaths\n ]\n\n debugLog('workspacePkgJsonPaths', workspacePkgJsonPaths)\n\n let actualTree = initialTree\n\n for (const { 0: name, 1: infos } of infoByPkg) {\n if (getManifestData(NPM, name)) {\n spinner?.info(`Skipping ${name}. Socket Optimize package exists.`)\n continue\n }\n const oldVersions = arrayUnique(\n findPackageNodes(actualTree, name).map(n => n.version)\n )\n const packument =\n oldVersions.length && infos.length\n ? // eslint-disable-next-line no-await-in-loop\n await fetchPackagePackument(name)\n : null\n if (!packument) {\n continue\n }\n\n const failedSpecs = new Set<string>()\n const fixedSpecs = new Set<string>()\n const installedSpecs = new Set<string>()\n const testedSpecs = new Set<string>()\n const unavailableSpecs = new Set<string>()\n const revertedSpecs = new Set<string>()\n\n for (const pkgJsonPath of pkgJsonPaths) {\n for (const oldVersion of oldVersions) {\n const oldSpec = `${name}@${oldVersion}`\n const oldPurl = `pkg:npm/${oldSpec}`\n\n for (const {\n firstPatchedVersionIdentifier,\n vulnerableVersionRange\n } of infos) {\n const node = findPackageNode(actualTree, name, oldVersion)\n if (!node) {\n continue\n }\n\n const availableVersions = Object.keys(packument.versions)\n const newVersion = findBestPatchVersion(\n node,\n availableVersions,\n vulnerableVersionRange,\n firstPatchedVersionIdentifier\n )\n const newVersionPackument = newVersion\n ? packument.versions[newVersion]\n : undefined\n\n if (!(newVersion && newVersionPackument)) {\n if (!unavailableSpecs.has(oldSpec)) {\n unavailableSpecs.add(oldSpec)\n spinner?.fail(`No update available for ${oldSpec}`)\n }\n continue\n }\n\n const isWorkspaceRoot =\n pkgJsonPath === pkgEnvDetails.editablePkgJson.filename\n const workspaceName = isWorkspaceRoot\n ? ''\n : path.relative(rootPath, path.dirname(pkgJsonPath))\n const workspaceDetails = workspaceName ? ` in ${workspaceName}` : ''\n const editablePkgJson = isWorkspaceRoot\n ? pkgEnvDetails.editablePkgJson\n : // eslint-disable-next-line no-await-in-loop\n await readPackageJson(pkgJsonPath, { editable: true })\n\n const oldPnpm = editablePkgJson.content[PNPM] as\n | StringKeyValueObject\n | undefined\n const oldPnpmKeyCount = oldPnpm ? Object.keys(oldPnpm).length : 0\n const oldOverrides = (oldPnpm as StringKeyValueObject)?.[OVERRIDES] as\n | Record<string, string>\n | undefined\n const oldOverridesCount = oldOverrides\n ? Object.keys(oldOverrides).length\n : 0\n\n const overrideKey = `${name}@${vulnerableVersionRange}`\n const newVersionRange = applyRange(\n oldOverrides?.[overrideKey] ?? oldVersion,\n newVersion,\n rangeStyle\n )\n const newSpec = `${name}@${newVersionRange}`\n const newSpecKey = `${workspaceName ? `${workspaceName}>` : ''}${newSpec}`\n\n const updateData = isWorkspaceRoot\n ? {\n [PNPM]: {\n ...oldPnpm,\n [OVERRIDES]: {\n [overrideKey]: newVersionRange,\n ...oldOverrides\n }\n }\n }\n : undefined\n\n const revertData = {\n ...(isWorkspaceRoot\n ? {\n [PNPM]: oldPnpmKeyCount\n ? {\n ...oldPnpm,\n [OVERRIDES]:\n oldOverridesCount === 1\n ? undefined\n : {\n [overrideKey]: undefined,\n ...oldOverrides\n }\n }\n : undefined\n }\n : {}),\n ...(editablePkgJson.content.dependencies\n ? { dependencies: editablePkgJson.content.dependencies }\n : undefined),\n ...(editablePkgJson.content.optionalDependencies\n ? {\n optionalDependencies:\n editablePkgJson.content.optionalDependencies\n }\n : undefined),\n ...(editablePkgJson.content.peerDependencies\n ? { peerDependencies: editablePkgJson.content.peerDependencies }\n : undefined)\n } as PackageJson\n\n const branch = isCi\n ? getSocketBranchName(oldPurl, newVersion, workspaceName)\n : ''\n const baseBranch = isCi ? getBaseGitBranch() : ''\n const { owner, repo } = isCi\n ? getGitHubEnvRepoInfo()\n : { owner: '', repo: '' }\n const shouldOpenPr = isCi\n ? // eslint-disable-next-line no-await-in-loop\n !(await doesPullRequestExistForBranch(owner, repo, branch))\n : false\n\n if (isCi) {\n // eslint-disable-next-line no-await-in-loop\n await gitCheckoutBaseBranchIfAvailable(baseBranch, cwd)\n }\n\n if (updateData) {\n editablePkgJson.update(updateData)\n }\n\n const modded = updatePackageJsonFromNode(\n editablePkgJson,\n actualTree,\n node,\n newVersion,\n rangeStyle\n )\n debugLog('updatePackageJsonFromNode', modded)\n debugLog(branch, editablePkgJson.filename)\n let error: unknown\n let errored = false\n let installed = false\n\n // eslint-disable-next-line no-await-in-loop\n if (!(await editablePkgJson.save())) {\n debugLog(`Skipping nothing changed in ${editablePkgJson.filename}`)\n continue\n }\n\n if (!installedSpecs.has(newSpecKey)) {\n installedSpecs.add(newSpecKey)\n spinner?.info(`Installing ${newSpec}${workspaceDetails}`)\n }\n\n try {\n // eslint-disable-next-line no-await-in-loop\n actualTree = await install(pkgEnvDetails, { spinner })\n installed = true\n\n if (test) {\n if (!testedSpecs.has(newSpecKey)) {\n testedSpecs.add(newSpecKey)\n spinner?.info(`Testing ${newSpec}${workspaceDetails}`)\n }\n // eslint-disable-next-line no-await-in-loop\n await runScript(testScript, [], { spinner, stdio: 'ignore' })\n }\n if (!fixedSpecs.has(newSpecKey)) {\n fixedSpecs.add(newSpecKey)\n spinner?.successAndStop(`Fixed ${name}${workspaceDetails}`)\n spinner?.start()\n }\n } catch (e) {\n error = e\n errored = true\n }\n\n debugLog('check \"shouldOpenPr\":', shouldOpenPr)\n debugLog('check \"errored\":', errored)\n if (!errored && shouldOpenPr) {\n debugLog('1: gitCreateAndPushBranchIfNeeded')\n // eslint-disable-next-line no-await-in-loop\n await gitCreateAndPushBranchIfNeeded(\n branch,\n getSocketCommitMessage(oldPurl, newVersion, workspaceName),\n cwd\n )\n debugLog('2: openGitHubPullRequest')\n // eslint-disable-next-line no-await-in-loop\n const prResponse = await openGitHubPullRequest(\n owner,\n repo,\n baseBranch,\n branch,\n oldPurl,\n newVersion,\n {\n cwd,\n workspaceName\n }\n )\n if (prResponse && autoMerge) {\n // eslint-disable-next-line no-await-in-loop\n await enableAutoMerge(prResponse.data)\n }\n }\n\n if (errored || isCi) {\n if (errored) {\n if (!revertedSpecs.has(newSpecKey)) {\n revertedSpecs.add(newSpecKey)\n spinner?.error(`Reverting ${newSpec}${workspaceDetails}`, error)\n }\n }\n editablePkgJson.update(revertData)\n if (isRepo) {\n // eslint-disable-next-line no-await-in-loop\n await gitHardReset(cwd)\n // eslint-disable-next-line no-await-in-loop\n actualTree = await getActualTree(cwd)\n } else if (installed) {\n // eslint-disable-next-line no-await-in-loop\n await editablePkgJson.save()\n // eslint-disable-next-line no-await-in-loop\n actualTree = await install(pkgEnvDetails, { spinner })\n }\n if (errored) {\n if (!failedSpecs.has(newSpecKey)) {\n failedSpecs.add(newSpecKey)\n spinner?.failAndStop(\n `Update failed for ${oldSpec}${workspaceDetails}`\n )\n }\n }\n }\n }\n }\n }\n }\n spinner?.stop()\n}\n","import type { FixOptions, NormalizedFixOptions } from './types'\n\nexport const CMD_NAME = 'socket fix'\n\nexport function assignDefaultFixOptions(\n options: FixOptions\n): NormalizedFixOptions {\n if (options.autoPilot === undefined) {\n options.autoPilot = false\n }\n if (options.autoMerge === undefined) {\n options.autoMerge = !!options.autoPilot\n }\n if (options.cwd === undefined) {\n options.cwd = process.cwd()\n }\n if (options.rangeStyle === undefined) {\n options.rangeStyle = 'preserve'\n }\n if (options.test === undefined) {\n options.test = !!options.autoPilot || !!options.testScript\n }\n if (options.testScript === undefined) {\n options.testScript = 'test'\n }\n return options as NormalizedFixOptions\n}\n","import { existsSync } from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\n\nimport browserslist from 'browserslist'\nimport semver from 'semver'\nimport which from 'which'\n\nimport { parse as parseBunLockb } from '@socketregistry/hyrious__bun.lockb/index.cjs'\nimport { Logger } from '@socketsecurity/registry/lib/logger'\nimport { readPackageJson } from '@socketsecurity/registry/lib/packages'\nimport { naturalCompare } from '@socketsecurity/registry/lib/sorts'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\nimport { isNonEmptyString } from '@socketsecurity/registry/lib/strings'\n\nimport { cmdPrefixMessage } from './cmd'\nimport { findUp, readFileBinary, readFileUtf8 } from './fs'\nimport constants from '../constants'\n\nimport type { Remap } from '@socketsecurity/registry/lib/objects'\nimport type { EditablePackageJson } from '@socketsecurity/registry/lib/packages'\nimport type { SemVer } from 'semver'\n\nconst {\n BINARY_LOCK_EXT,\n BUN,\n HIDDEN_PACKAGE_LOCK_JSON,\n LOCK_EXT,\n NPM,\n NPM_BUGGY_OVERRIDES_PATCHED_VERSION,\n PACKAGE_JSON,\n PNPM,\n VLT,\n YARN,\n YARN_BERRY,\n YARN_CLASSIC\n} = constants\n\nexport const AGENTS = [BUN, NPM, PNPM, YARN_BERRY, YARN_CLASSIC, VLT] as const\n\nexport type Agent = (typeof AGENTS)[number]\n\nconst binByAgent = new Map<Agent, string>([\n [BUN, BUN],\n [NPM, NPM],\n [PNPM, PNPM],\n [YARN_BERRY, YARN],\n [YARN_CLASSIC, YARN],\n [VLT, VLT]\n])\n\nasync function getAgentExecPath(agent: Agent): Promise<string> {\n const binName = binByAgent.get(agent)!\n return (await which(binName, { nothrow: true })) ?? binName\n}\n\nasync function getAgentVersion(\n agentExecPath: string,\n cwd: string\n): Promise<SemVer | undefined> {\n let result\n try {\n result =\n // Coerce version output into a valid semver version by passing it through\n // semver.coerce which strips leading v's, carets (^), comparators (<,<=,>,>=,=),\n // and tildes (~).\n semver.coerce(\n // All package managers support the \"--version\" flag.\n (await spawn(agentExecPath, ['--version'], { cwd })).stdout\n ) ?? undefined\n } catch {}\n return result\n}\n\n// The order of LOCKS properties IS significant as it affects iteration order.\nconst LOCKS: Record<string, Agent> = {\n [`bun${LOCK_EXT}`]: BUN,\n [`bun${BINARY_LOCK_EXT}`]: BUN,\n // If both package-lock.json and npm-shrinkwrap.json are present in the root\n // of a project, npm-shrinkwrap.json will take precedence and package-lock.json\n // will be ignored.\n // https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json#package-lockjson-vs-npm-shrinkwrapjson\n 'npm-shrinkwrap.json': NPM,\n 'package-lock.json': NPM,\n 'pnpm-lock.yaml': PNPM,\n 'pnpm-lock.yml': PNPM,\n [`yarn${LOCK_EXT}`]: YARN_CLASSIC,\n 'vlt-lock.json': VLT,\n // Lastly, look for a hidden lock file which is present if .npmrc has package-lock=false:\n // https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json#hidden-lockfiles\n //\n // Unlike the other LOCKS keys this key contains a directory AND filename so\n // it has to be handled differently.\n 'node_modules/.package-lock.json': NPM\n}\n\ntype ReadLockFile =\n | ((lockPath: string) => Promise<string | undefined>)\n | ((lockPath: string, agentExecPath: string) => Promise<string | undefined>)\n\nconst readLockFileByAgent: Map<Agent, ReadLockFile> = (() => {\n function wrapReader<T extends (...args: any[]) => Promise<any>>(\n reader: T\n ): (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>> | undefined> {\n return async (...args: any[]): Promise<any> => {\n try {\n return await reader(...args)\n } catch {}\n return undefined\n }\n }\n\n const binaryReader = wrapReader(readFileBinary)\n\n const defaultReader = wrapReader(\n async (lockPath: string) => await readFileUtf8(lockPath)\n )\n\n return new Map([\n [\n BUN,\n wrapReader(async (lockPath: string, agentExecPath: string) => {\n const ext = path.extname(lockPath)\n if (ext === LOCK_EXT) {\n return await defaultReader(lockPath)\n }\n if (ext === BINARY_LOCK_EXT) {\n const lockBuffer = await binaryReader(lockPath)\n if (lockBuffer) {\n try {\n return parseBunLockb(lockBuffer)\n } catch {}\n }\n // To print a Yarn lockfile to your console without writing it to disk\n // use `bun bun.lockb`.\n // https://bun.sh/guides/install/yarnlock\n return (await spawn(agentExecPath, [lockPath])).stdout.trim()\n }\n return undefined\n })\n ],\n [NPM, defaultReader],\n [PNPM, defaultReader],\n [VLT, defaultReader],\n [YARN_BERRY, defaultReader],\n [YARN_CLASSIC, defaultReader]\n ])\n})()\n\ntype EnvBase = {\n agent: Agent\n agentExecPath: string\n agentSupported: boolean\n features: {\n // Fixed by https://github.com/npm/cli/pull/8089.\n // Landed in npm v11.2.0.\n npmBuggyOverrides: boolean\n }\n nodeSupported: boolean\n nodeVersion: SemVer\n npmExecPath: string\n pkgRequirements: {\n agent: string\n node: string\n }\n pkgSupports: {\n agent: boolean\n node: boolean\n }\n}\n\nexport type EnvDetails = Readonly<\n Remap<\n EnvBase & {\n agentVersion: SemVer\n editablePkgJson: EditablePackageJson\n lockName: string\n lockPath: string\n lockSrc: string\n pkgPath: string\n }\n >\n>\n\nexport type PartialEnvDetails = Readonly<\n Remap<\n EnvBase & {\n agentVersion: SemVer | undefined\n editablePkgJson: EditablePackageJson | undefined\n lockName: string | undefined\n lockPath: string | undefined\n lockSrc: string | undefined\n pkgPath: string | undefined\n }\n >\n>\n\nexport type DetectOptions = {\n cwd?: string | undefined\n onUnknown?: (pkgManager: string | undefined) => void\n}\n\nexport async function detectPackageEnvironment({\n cwd = process.cwd(),\n onUnknown\n}: DetectOptions = {}): Promise<EnvDetails | PartialEnvDetails> {\n let lockPath = await findUp(Object.keys(LOCKS), { cwd })\n let lockName = lockPath ? path.basename(lockPath) : undefined\n const isHiddenLockFile = lockName === HIDDEN_PACKAGE_LOCK_JSON\n const pkgJsonPath = lockPath\n ? path.resolve(\n lockPath,\n `${isHiddenLockFile ? '../' : ''}../${PACKAGE_JSON}`\n )\n : await findUp(PACKAGE_JSON, { cwd })\n const pkgPath =\n pkgJsonPath && existsSync(pkgJsonPath)\n ? path.dirname(pkgJsonPath)\n : undefined\n const editablePkgJson = pkgPath\n ? await readPackageJson(pkgPath, { editable: true })\n : undefined\n // Read Corepack `packageManager` field in package.json:\n // https://nodejs.org/api/packages.html#packagemanager\n const pkgManager = isNonEmptyString(editablePkgJson?.content?.packageManager)\n ? editablePkgJson.content.packageManager\n : undefined\n\n let agent: Agent | undefined\n let agentVersion: SemVer | undefined\n if (pkgManager) {\n // A valid \"packageManager\" field value is \"<package manager name>@<version>\".\n // https://nodejs.org/api/packages.html#packagemanager\n const atSignIndex = pkgManager.lastIndexOf('@')\n if (atSignIndex !== -1) {\n const name = pkgManager.slice(0, atSignIndex) as Agent\n const version = pkgManager.slice(atSignIndex + 1)\n if (version && AGENTS.includes(name)) {\n agent = name\n }\n }\n }\n if (\n agent === undefined &&\n !isHiddenLockFile &&\n typeof pkgJsonPath === 'string' &&\n typeof lockName === 'string'\n ) {\n agent = LOCKS[lockName] as Agent\n }\n if (agent === undefined) {\n agent = NPM\n onUnknown?.(pkgManager)\n }\n const agentExecPath = await getAgentExecPath(agent)\n const npmExecPath =\n agent === NPM ? agentExecPath : await getAgentExecPath(NPM)\n if (agentVersion === undefined) {\n agentVersion = await getAgentVersion(agentExecPath, cwd)\n }\n if (agent === YARN_CLASSIC && (agentVersion?.major ?? 0) > 1) {\n agent = YARN_BERRY\n }\n // Lazily access constants.maintainedNodeVersions.\n const { maintainedNodeVersions } = constants\n // Lazily access constants.minimumVersionByAgent.\n const minSupportedAgentVersion = constants.minimumVersionByAgent.get(agent)!\n const minSupportedNodeVersion = maintainedNodeVersions.last\n const nodeVersion = semver.coerce(process.version)!\n let lockSrc: string | undefined\n let pkgAgentRange: string | undefined\n let pkgNodeRange: string | undefined\n let pkgMinAgentVersion = minSupportedAgentVersion\n let pkgMinNodeVersion = minSupportedNodeVersion\n if (editablePkgJson?.content) {\n const { engines } = editablePkgJson.content\n const engineAgentRange = engines?.[agent]\n const engineNodeRange = engines?.['node']\n if (isNonEmptyString(engineAgentRange)) {\n pkgAgentRange = engineAgentRange\n // Roughly check agent range as semver.coerce will strip leading\n // v's, carets (^), comparators (<,<=,>,>=,=), and tildes (~).\n const coerced = semver.coerce(pkgAgentRange)\n if (coerced && semver.lt(coerced, pkgMinAgentVersion)) {\n pkgMinAgentVersion = coerced.version\n }\n }\n if (isNonEmptyString(engineNodeRange)) {\n pkgNodeRange = engineNodeRange\n // Roughly check Node range as semver.coerce will strip leading\n // v's, carets (^), comparators (<,<=,>,>=,=), and tildes (~).\n const coerced = semver.coerce(pkgNodeRange)\n if (coerced && semver.lt(coerced, pkgMinNodeVersion)) {\n pkgMinNodeVersion = coerced.version\n }\n }\n const browserslistQuery = editablePkgJson.content['browserslist'] as\n | string[]\n | undefined\n if (Array.isArray(browserslistQuery)) {\n // List Node targets in ascending version order.\n const browserslistNodeTargets = browserslist(browserslistQuery)\n .filter(v => /^node /i.test(v))\n .map(v => v.slice(5 /*'node '.length*/))\n .sort(naturalCompare)\n if (browserslistNodeTargets.length) {\n // browserslistNodeTargets[0] is the lowest Node target version.\n const coerced = semver.coerce(browserslistNodeTargets[0])\n if (coerced && semver.lt(coerced, pkgMinNodeVersion)) {\n pkgMinNodeVersion = coerced.version\n }\n }\n }\n lockSrc =\n typeof lockPath === 'string'\n ? await readLockFileByAgent.get(agent)!(lockPath, agentExecPath)\n : undefined\n } else {\n lockName = undefined\n lockPath = undefined\n }\n // Does the system agent version meet our minimum supported agent version?\n const agentSupported =\n !!agentVersion &&\n semver.satisfies(agentVersion, `>=${minSupportedAgentVersion}`)\n\n // Does the system Node version meet our minimum supported Node version?\n const nodeSupported = semver.satisfies(\n nodeVersion,\n `>=${minSupportedNodeVersion}`\n )\n\n const npmBuggyOverrides =\n agent === NPM &&\n !!agentVersion &&\n semver.lt(agentVersion, NPM_BUGGY_OVERRIDES_PATCHED_VERSION)\n\n return {\n agent,\n agentExecPath,\n agentSupported,\n agentVersion,\n editablePkgJson,\n features: { npmBuggyOverrides },\n lockName,\n lockPath,\n lockSrc,\n nodeSupported,\n nodeVersion,\n npmExecPath,\n pkgPath,\n pkgRequirements: {\n agent: pkgAgentRange ?? `>=${pkgMinAgentVersion}`,\n node: pkgNodeRange ?? `>=${pkgMinNodeVersion}`\n },\n pkgSupports: {\n // Does our minimum supported agent version meet the package's requirements?\n agent: semver.satisfies(\n minSupportedAgentVersion,\n `>=${pkgMinAgentVersion}`\n ),\n // Does our supported Node versions meet the package's requirements?\n node: maintainedNodeVersions.some(v =>\n semver.satisfies(v, `>=${pkgMinNodeVersion}`)\n )\n }\n }\n}\n\nexport type DetectAndValidateOptions = {\n cmdName?: string | undefined\n logger?: Logger | undefined\n prod?: boolean | undefined\n}\n\nexport async function detectAndValidatePackageEnvironment(\n cwd: string,\n options?: DetectAndValidateOptions | undefined\n): Promise<void | EnvDetails> {\n const {\n cmdName = '',\n logger,\n prod\n } = {\n __proto__: null,\n ...options\n } as DetectAndValidateOptions\n const details = await detectPackageEnvironment({\n cwd,\n onUnknown(pkgManager: string | undefined) {\n logger?.warn(\n cmdPrefixMessage(\n cmdName,\n `Unknown package manager${pkgManager ? ` ${pkgManager}` : ''}, defaulting to npm`\n )\n )\n }\n })\n const { agent, nodeVersion, pkgRequirements } = details\n const agentVersion = details.agentVersion ?? 'unknown'\n if (!details.agentSupported) {\n const minVersion = constants.minimumVersionByAgent.get(agent)!\n logger?.fail(\n cmdPrefixMessage(\n cmdName,\n `Requires ${agent} >=${minVersion}. Current version: ${agentVersion}.`\n )\n )\n return\n }\n if (!details.nodeSupported) {\n const minVersion = constants.maintainedNodeVersions.last\n logger?.fail(\n cmdPrefixMessage(\n cmdName,\n `Requires Node >=${minVersion}. Current version: ${nodeVersion}.`\n )\n )\n return\n }\n if (!details.pkgSupports.agent) {\n logger?.fail(\n cmdPrefixMessage(\n cmdName,\n `Package engine \"${agent}\" requires ${pkgRequirements.agent}. Current version: ${agentVersion}`\n )\n )\n return\n }\n if (!details.pkgSupports.node) {\n logger?.fail(\n cmdPrefixMessage(\n cmdName,\n `Package engine \"node\" requires ${pkgRequirements.node}. Current version: ${nodeVersion}`\n )\n )\n return\n }\n if (agent === VLT) {\n logger?.fail(\n cmdPrefixMessage(\n cmdName,\n `${agent} does not support overrides. Soon, though ⚡`\n )\n )\n return\n }\n const lockName = details.lockName ?? 'lock file'\n if (details.lockName === undefined || details.lockSrc === undefined) {\n logger?.fail(cmdPrefixMessage(cmdName, `No ${lockName} found`))\n return\n }\n if (details.lockSrc.trim() === '') {\n logger?.fail(cmdPrefixMessage(cmdName, `${lockName} is empty`))\n return\n }\n if (details.pkgPath === undefined) {\n logger?.fail(cmdPrefixMessage(cmdName, `No ${PACKAGE_JSON} found`))\n return\n }\n if (prod && (agent === BUN || agent === YARN_BERRY)) {\n logger?.fail(\n cmdPrefixMessage(\n cmdName,\n `--prod not supported for ${agent}${agentVersion ? `@${agentVersion}` : ''}`\n )\n )\n return\n }\n if (\n details.lockPath &&\n path.relative(cwd, details.lockPath).startsWith('.')\n ) {\n logger?.warn(\n cmdPrefixMessage(\n cmdName,\n `Package ${lockName} found at ${details.lockPath}`\n )\n )\n }\n return details as EnvDetails\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { npmFix } from './npm-fix'\nimport { pnpmFix } from './pnpm-fix'\nimport { CMD_NAME, assignDefaultFixOptions } from './shared'\nimport constants from '../../constants'\nimport { detectAndValidatePackageEnvironment } from '../../utils/package-environment'\n\nimport type { FixOptions } from './types'\n\nconst { NPM, PNPM } = constants\n\nexport async function runFix(options_: FixOptions) {\n const options = assignDefaultFixOptions({\n __proto__: null,\n ...options_\n } as FixOptions)\n const pkgEnvDetails = await detectAndValidatePackageEnvironment(options.cwd, {\n cmdName: CMD_NAME,\n logger\n })\n if (!pkgEnvDetails) {\n return\n }\n logger.info(`Fixing packages for ${pkgEnvDetails.agent}`)\n const { agent } = pkgEnvDetails\n if (agent === NPM) {\n await npmFix(pkgEnvDetails, options)\n } else if (agent === PNPM) {\n await pnpmFix(pkgEnvDetails, options)\n }\n}\n","import { codeBlock } from 'common-tags'\nimport terminalLink from 'terminal-link'\n\nimport { joinOr } from '@socketsecurity/registry/lib/arrays'\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { runFix } from './run-fix'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { RangeStyles } from '../../utils/semver'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\nimport type { RangeStyle } from '../../utils/semver'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'fix',\n description: 'Fix \"fixable\" Socket alerts',\n hidden: true,\n flags: {\n ...commonFlags,\n autoPilot: {\n type: 'boolean',\n default: false,\n description: `Shorthand for --autoMerge --test`\n },\n autoMerge: {\n type: 'boolean',\n default: false,\n description: `Enable auto-merge for pull requests that Socket opens.\\n See ${terminalLink(\n 'GitHub documentation',\n 'https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-auto-merge-for-pull-requests-in-your-repository'\n )} for managing auto-merge for pull requests in your repository.`\n },\n purl: {\n type: 'string',\n default: [],\n description: `User provided PURL to fix`,\n isMultiple: true,\n shortFlag: 'p'\n },\n rangeStyle: {\n type: 'string',\n default: 'preserve',\n description: codeBlock`\n Define how updated dependency versions should be written in package.json.\n Available styles:\n *\tcaret - Use ^ range for compatible updates (e.g. ^1.2.3)\n *\tgt - Use >= to allow any newer version (e.g. >=1.2.3)\n *\tlt - Use < to allow only lower versions (e.g. <1.2.3)\n *\tpin - Use the exact version (e.g. 1.2.3)\n *\tpreserve - Retain the existing version range as-is\n *\ttilde - Use ~ range for patch/minor updates (e.g. ~1.2.3)\n `\n },\n test: {\n type: 'boolean',\n default: false,\n description: 'Verify the fix by running unit tests'\n },\n testScript: {\n type: 'string',\n default: 'test',\n description: 'The test script to run for each fix attempt'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command}\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n `\n}\n\nexport const cmdFix = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const wasBadInput = handleBadInput({\n test: RangeStyles.includes(cli.flags['rangeStyle'] as string),\n message: `Expecting range style of ${joinOr(RangeStyles)}`,\n pass: 'ok',\n fail: 'missing'\n })\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n await runFix({\n autoMerge: Boolean(cli.flags['autoMerge']),\n autoPilot: Boolean(cli.flags['autoPilot']),\n purls: Array.isArray(cli.flags['purl']) ? cli.flags['purl'] : [],\n spinner,\n rangeStyle: (cli.flags['rangeStyle'] ?? undefined) as\n | RangeStyle\n | undefined,\n test: Boolean(cli.flags['test']),\n testScript: cli.flags['testScript'] as string | undefined\n })\n}\n","import constants from '../../constants'\nimport { getSeverityCount } from '../../utils/alert/severity'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { getPublicToken, setupSdk } from '../../utils/sdk'\n\nimport type { PackageData } from './handle-package-info'\n\nexport async function fetchPackageInfo(\n pkgName: string,\n pkgVersion: string,\n includeAllIssues: boolean\n): Promise<void | PackageData> {\n const sockSdk = await setupSdk(getPublicToken())\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start(\n pkgVersion === 'latest'\n ? `Looking up data for the latest version of ${pkgName}`\n : `Looking up data for version ${pkgVersion} of ${pkgName}`\n )\n\n const result = await handleApiCall(\n sockSdk.getIssuesByNPMPackage(pkgName, pkgVersion),\n 'looking up package'\n )\n const scoreResult = await handleApiCall(\n sockSdk.getScoreByNPMPackage(pkgName, pkgVersion),\n 'looking up package score'\n )\n\n spinner.successAndStop('Data fetched')\n\n if (result.success === false) {\n handleUnsuccessfulApiResponse('getIssuesByNPMPackage', result)\n }\n\n if (scoreResult.success === false) {\n handleUnsuccessfulApiResponse('getScoreByNPMPackage', scoreResult)\n }\n\n const severityCount = getSeverityCount(\n result.data,\n includeAllIssues ? undefined : 'high'\n )\n\n return {\n data: result.data,\n severityCount,\n score: scoreResult.data\n }\n}\n","import { codeBlock } from 'common-tags'\nimport colors from 'yoctocolors-cjs'\n\nimport constants from '@socketsecurity/registry/lib/constants'\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { hasKeys } from '@socketsecurity/registry/lib/objects'\n\nimport { ALERT_SEVERITY, formatSeverityCount } from '../../utils/alert/severity'\nimport { ColorOrMarkdown } from '../../utils/color-or-markdown'\nimport {\n getSocketDevAlertUrl,\n getSocketDevPackageOverviewUrl\n} from '../../utils/socket-url'\n\nimport type { PackageData } from './handle-package-info'\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nconst { NPM } = constants\n\nfunction formatScore(score: number): string {\n if (score > 80) {\n return colors.green(`${score}`)\n } else if (score < 80 && score > 60) {\n return colors.yellow(`${score}`)\n }\n return colors.red(`${score}`)\n}\n\nfunction outputPackageIssuesDetails(\n packageData: SocketSdkReturnType<'getIssuesByNPMPackage'>['data'],\n outputMarkdown: boolean\n) {\n const issueDetails = packageData.filter(\n d =>\n d.value?.severity === ALERT_SEVERITY.critical ||\n d.value?.severity === ALERT_SEVERITY.high\n )\n const uniqueIssueDetails = issueDetails.reduce((acc, issue) => {\n const { type } = issue\n if (type) {\n const details = acc.get(type)\n if (details) {\n details.count += 1\n } else {\n acc.set(type, {\n label: issue.value?.label ?? '',\n count: 1\n })\n }\n }\n return acc\n }, new Map<string, { count: number; label: string }>())\n const format = new ColorOrMarkdown(outputMarkdown)\n for (const [type, details] of uniqueIssueDetails.entries()) {\n const issueWithLink = format.hyperlink(\n details.label,\n getSocketDevAlertUrl(type),\n { fallbackToUrl: true }\n )\n if (details.count === 1) {\n logger.log(`- ${issueWithLink}`)\n } else {\n logger.log(`- ${issueWithLink}: ${details.count}`)\n }\n }\n}\n\nexport function outputPackageInfo(\n { data, score, severityCount }: PackageData,\n {\n commandName,\n outputKind,\n pkgName,\n pkgVersion\n }: {\n commandName: string\n outputKind: 'json' | 'markdown' | 'print'\n pkgName: string\n pkgVersion: string\n includeAllIssues?: boolean | undefined\n }\n): void {\n if (outputKind === 'json') {\n logger.log(JSON.stringify(data, undefined, 2))\n return\n }\n if (outputKind === 'markdown') {\n logger.log(codeBlock`\n # Package report for ${pkgName}\n\n Package report card:\n `)\n } else {\n logger.log(`Package report card for ${pkgName}:`)\n }\n const scoreResult = {\n 'Supply Chain Risk': Math.floor(score.supplyChainRisk.score * 100),\n Maintenance: Math.floor(score.maintenance.score * 100),\n Quality: Math.floor(score.quality.score * 100),\n Vulnerabilities: Math.floor(score.vulnerability.score * 100),\n License: Math.floor(score.license.score * 100)\n }\n logger.log('\\n')\n Object.entries(scoreResult).map(score =>\n logger.log(`- ${score[0]}: ${formatScore(score[1])}`)\n )\n logger.log('\\n')\n if (hasKeys(severityCount)) {\n if (outputKind === 'markdown') {\n logger.log('# Issues\\n')\n }\n logger.log(\n `Package has these issues: ${formatSeverityCount(severityCount)}\\n`\n )\n outputPackageIssuesDetails(data, outputKind === 'markdown')\n } else {\n logger.log('Package has no issues')\n }\n\n const format = new ColorOrMarkdown(outputKind === 'markdown')\n const url = getSocketDevPackageOverviewUrl(NPM, pkgName, pkgVersion)\n\n logger.log('\\n')\n if (pkgVersion === 'latest') {\n logger.log(\n `Detailed info on socket.dev: ${format.hyperlink(`${pkgName}`, url, { fallbackToUrl: true })}`\n )\n } else {\n logger.log(\n `Detailed info on socket.dev: ${format.hyperlink(`${pkgName} v${pkgVersion}`, url, { fallbackToUrl: true })}`\n )\n }\n if (outputKind !== 'markdown') {\n logger.log(\n colors.dim(\n `\\nOr rerun ${colors.italic(commandName)} using the ${colors.italic('--json')} flag to get full JSON output`\n )\n )\n } else {\n logger.log('')\n }\n}\n","import process from 'node:process'\n\nimport { hasKeys } from '@socketsecurity/registry/lib/objects'\n\nimport { fetchPackageInfo } from './fetch-package-info'\nimport { outputPackageInfo } from './output-package-info'\n\nimport type { SocketSdkAlert } from '../../utils/alert/severity'\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport interface PackageData {\n data: SocketSdkReturnType<'getIssuesByNPMPackage'>['data']\n severityCount: Record<SocketSdkAlert['severity'], number>\n score: SocketSdkReturnType<'getScoreByNPMPackage'>['data']\n}\n\nexport async function handlePackageInfo({\n commandName,\n includeAllIssues,\n outputKind,\n pkgName,\n pkgVersion,\n strict\n}: {\n commandName: string\n includeAllIssues: boolean\n outputKind: 'json' | 'markdown' | 'print'\n pkgName: string\n pkgVersion: string\n strict: boolean\n}) {\n const packageData = await fetchPackageInfo(\n pkgName,\n pkgVersion,\n includeAllIssues\n )\n\n if (packageData) {\n outputPackageInfo(packageData, {\n commandName,\n includeAllIssues,\n outputKind,\n pkgName,\n pkgVersion\n })\n\n if (strict && hasKeys(packageData.severityCount)) {\n // Let NodeJS exit gracefully but with exit(1)\n process.exitCode = 1\n }\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handlePackageInfo } from './handle-package-info'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags, validationFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'info',\n description: 'Look up info regarding a package',\n hidden: true, // Deprecated\n flags: {\n ...commonFlags,\n ...outputFlags,\n ...validationFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <name>\n\n Note: this command will be deprecated in favor of \\`socket package score\\` soon\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} webtorrent\n $ ${command} webtorrent@1.9.1\n `\n}\n\nexport const cmdInfo = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { all, json, markdown, strict } = cli.flags\n const [rawPkgName = ''] = cli.input\n\n const wasBadInput = handleBadInput(\n {\n test: !!rawPkgName,\n message: 'Expecting a package name',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: cli.input.length === 1,\n message: 'Can only accept one package at a time',\n pass: 'ok',\n fail: 'got ' + cli.input.length\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n }\n )\n if (wasBadInput) {\n return\n }\n\n const versionSeparator = rawPkgName.lastIndexOf('@')\n const pkgName =\n versionSeparator < 1 ? rawPkgName : rawPkgName.slice(0, versionSeparator)\n const pkgVersion =\n versionSeparator < 1 ? 'latest' : rawPkgName.slice(versionSeparator + 1)\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handlePackageInfo({\n commandName: `${parentName} ${config.commandName}`,\n includeAllIssues: Boolean(all),\n outputKind: json ? 'json' : markdown ? 'markdown' : 'print',\n pkgName,\n pkgVersion,\n strict: Boolean(strict)\n })\n}\n","import { updateConfigValue } from '../../utils/config'\n\nexport function applyLogin(\n apiToken: string,\n enforcedOrgs: string[],\n apiBaseUrl: string | undefined,\n apiProxy: string | undefined\n) {\n updateConfigValue('enforcedOrgs', enforcedOrgs)\n updateConfigValue('apiToken', apiToken)\n updateConfigValue('apiBaseUrl', apiBaseUrl)\n updateConfigValue('apiProxy', apiProxy)\n}\n","import terminalLink from 'terminal-link'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { confirm, password, select } from '@socketsecurity/registry/lib/prompts'\n\nimport { applyLogin } from './apply-login'\nimport constants from '../../constants'\nimport { handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { getConfigValue, isReadOnlyConfig } from '../../utils/config'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { Choice, Separator } from '@socketsecurity/registry/lib/prompts'\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\ntype OrgChoice = Choice<string>\ntype OrgChoices = Array<Separator | OrgChoice>\nconst { SOCKET_PUBLIC_API_TOKEN } = constants\n\nexport async function attemptLogin(\n apiBaseUrl: string | undefined,\n apiProxy: string | undefined\n) {\n apiBaseUrl ??= getConfigValue('apiBaseUrl') ?? undefined\n apiProxy ??= getConfigValue('apiProxy') ?? undefined\n const apiToken =\n (await password({\n message: `Enter your ${terminalLink(\n 'Socket.dev API key',\n 'https://docs.socket.dev/docs/api-keys'\n )} (leave blank for a public key)`\n })) || SOCKET_PUBLIC_API_TOKEN\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n const sdk = await setupSdk(apiToken, apiBaseUrl, apiProxy)\n\n spinner.start('Verifying API key...')\n\n const result = await sdk.getOrganizations()\n\n spinner.successAndStop('Received response')\n\n if (!result.success) {\n logger.fail('Authentication failed...')\n handleUnsuccessfulApiResponse('getOrganizations', result)\n }\n\n logger.success('API key verified')\n\n const orgs: SocketSdkReturnType<'getOrganizations'>['data'] = result.data\n\n const enforcedChoices: OrgChoices = Object.values(orgs.organizations)\n .filter(org => org?.plan === 'enterprise')\n .map(org => ({\n name: org.name ?? 'undefined',\n value: org.id\n }))\n\n let enforcedOrgs: string[] = []\n if (enforcedChoices.length > 1) {\n const id = (await select({\n message:\n \"Which organization's policies should Socket enforce system-wide?\",\n choices: enforcedChoices.concat({\n name: 'None',\n value: '',\n description: 'Pick \"None\" if this is a personal device'\n })\n })) as string | null\n if (id) {\n enforcedOrgs = [id]\n }\n } else if (enforcedChoices.length) {\n if (\n await confirm({\n message: `Should Socket enforce ${(enforcedChoices[0] as OrgChoice)?.name}'s security policies system-wide?`,\n default: true\n })\n ) {\n const existing = enforcedChoices[0] as OrgChoice\n if (existing) {\n enforcedOrgs = [existing.value]\n }\n }\n }\n\n spinner.stop()\n\n const previousPersistedToken = getConfigValue('apiToken')\n try {\n applyLogin(apiToken, enforcedOrgs, apiBaseUrl, apiProxy)\n logger.success(\n `API credentials ${previousPersistedToken === apiToken ? 'refreshed' : previousPersistedToken ? 'updated' : 'set'}`\n )\n if (isReadOnlyConfig()) {\n logger.log('')\n logger.warn(\n 'Note: config is in read-only mode, at least one key was overridden through flag/env, so the login was not persisted!'\n )\n }\n } catch {\n logger.fail(`API login failed`)\n }\n}\n","import isInteractive from '@socketregistry/is-interactive/index.cjs'\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { attemptLogin } from './attempt-login'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { InputError } from '../../utils/errors'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'login',\n description: 'Socket API login',\n hidden: false,\n flags: {\n ...commonFlags,\n apiBaseUrl: {\n type: 'string',\n description: 'API server to connect to for login'\n },\n apiProxy: {\n type: 'string',\n description: 'Proxy to use when making connection to API server'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command}\n\n API Token Requirements\n - Quota: 1 unit\n\n Logs into the Socket API by prompting for an API key\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command}\n $ ${command} --api-proxy=http://localhost:1234\n `\n}\n\nexport const cmdLogin = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const apiBaseUrl = cli.flags['apiBaseUrl'] as string | undefined\n const apiProxy = cli.flags['apiProxy'] as string | undefined\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n if (!isInteractive()) {\n throw new InputError(\n 'Cannot prompt for credentials in a non-interactive shell'\n )\n }\n\n await attemptLogin(apiBaseUrl, apiProxy)\n}\n","import { updateConfigValue } from '../../utils/config'\n\nexport function applyLogout() {\n updateConfigValue('apiToken', null)\n updateConfigValue('apiBaseUrl', null)\n updateConfigValue('apiProxy', null)\n updateConfigValue('enforcedOrgs', null)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { applyLogout } from './apply-logout'\nimport { isReadOnlyConfig } from '../../utils/config'\n\nexport function attemptLogout() {\n try {\n applyLogout()\n logger.success('Successfully logged out')\n if (isReadOnlyConfig()) {\n logger.log('')\n logger.warn(\n 'Note: config is in read-only mode, at least one key was overridden through flag/env, so the logout was not persisted!'\n )\n }\n } catch {\n logger.fail('Failed to complete logout steps')\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { attemptLogout } from './attempt-logout'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'logout',\n description: 'Socket API logout',\n hidden: false,\n flags: {\n ...commonFlags\n },\n help: (command, _config) => `\n Usage\n $ ${command}\n\n Logs out of the Socket API and clears all Socket credentials from disk\n `\n}\n\nexport const cmdLogout = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n attemptLogout()\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nexport async function convertCondaToRequirements(\n target: string,\n cwd: string,\n verbose: boolean\n): Promise<\n | { ok: true; message: string; data: { contents: string; pip: string } }\n | { ok: false; message: string; data: undefined }\n> {\n let contents: string\n if (target === '-') {\n if (verbose) {\n logger.error(`[VERBOSE] reading input from stdin`)\n }\n\n const buf: string[] = []\n contents = await new Promise((resolve, reject) => {\n process.stdin.on('data', chunk => {\n const input = chunk.toString()\n buf.push(input)\n })\n process.stdin.on('end', () => {\n resolve(buf.join(''))\n })\n process.stdin.on('error', e => {\n if (verbose) {\n logger.error('Unexpected error while reading from stdin:', e)\n }\n reject(e)\n })\n process.stdin.on('close', () => {\n if (buf.length === 0) {\n if (verbose) {\n logger.error('stdin closed explicitly without data received')\n }\n reject(new Error('No data received from stdin'))\n } else {\n if (verbose) {\n logger.error(\n 'warning: stdin closed explicitly with some data received'\n )\n }\n resolve(buf.join(''))\n }\n })\n })\n\n if (!contents) {\n return {\n ok: false,\n message: 'No data received from stdin',\n data: undefined\n }\n }\n } else {\n const f = path.resolve(cwd, target)\n\n if (verbose) {\n logger.error(`[VERBOSE] target file: ${f}`)\n }\n\n if (!fs.existsSync(f)) {\n return {\n ok: false,\n message: `Input file not found at ${f}`,\n data: undefined\n }\n }\n\n contents = fs.readFileSync(target, 'utf8')\n\n if (!contents) {\n return { ok: false, message: 'File is empty', data: undefined }\n }\n }\n\n return {\n ok: true,\n message: '',\n data: {\n contents,\n pip: convertCondaToRequirementsFromInput(contents)\n }\n }\n}\n\n// Just extract the first pip block, if one exists at all.\nexport function convertCondaToRequirementsFromInput(input: string): string {\n const keeping: string[] = []\n let collecting = false\n let delim = '-'\n let indent = ''\n input.split('\\n').some(line => {\n if (!line) {\n // Ignore empty lines\n return\n }\n if (collecting) {\n if (line.startsWith('#')) {\n // Ignore comment lines (keep?)\n return\n }\n if (line.startsWith(delim)) {\n // In this case we have a line with the same indentation as the\n // `- pip:` line, so we have reached the end of the pip block.\n return true // the end\n } else {\n if (!indent) {\n // Store the indentation of the block\n if (line.trim().startsWith('-')) {\n indent = line.split('-')[0] + '-'\n if (indent.length <= delim.length) {\n // The first line after the `pip:` line does not indent further\n // than that so the block is empty?\n return true\n }\n }\n }\n if (line.startsWith(indent)) {\n keeping.push(line.slice(indent.length).trim())\n } else {\n // Unexpected input. bail.\n return true\n }\n }\n } else {\n // Note: the line may end with a line comment so don't === it.\n if (line.trim().startsWith('- pip:')) {\n delim = line.split('-')[0] + '-'\n collecting = true\n }\n }\n })\n\n return keeping.join('\\n')\n}\n","import fs from 'node:fs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nexport async function outputRequirements(\n data: { contents: string; pip: string },\n outputKind: 'json' | 'markdown' | 'text',\n out: string\n) {\n if (outputKind === 'json') {\n const json = JSON.stringify(\n {\n ok: true,\n data: {\n pip: data.pip\n }\n },\n undefined,\n 2\n )\n\n if (out === '-') {\n logger.log(json)\n } else {\n fs.writeFileSync(out, json, 'utf8')\n }\n\n return\n }\n\n if (outputKind === 'markdown') {\n const arr = []\n arr.push('# Converted Conda file')\n arr.push('')\n arr.push(\n 'This is the Conda `environment.yml` file converted to python `requirements.txt`:'\n )\n arr.push('')\n arr.push('```file=requirements.txt')\n arr.push(data.pip)\n arr.push('```')\n arr.push('')\n const md = arr.join('\\n')\n\n if (out === '-') {\n logger.log(md)\n } else {\n fs.writeFileSync(out, md, 'utf8')\n }\n return\n }\n\n if (out === '-') {\n logger.log(data.pip)\n logger.log('')\n } else {\n fs.writeFileSync(out, data.pip, 'utf8')\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { convertCondaToRequirements } from './convert-conda-to-requirements'\nimport { outputRequirements } from './output-requirements'\n\nexport async function handleManifestConda(\n target: string,\n out: string,\n outputKind: 'json' | 'markdown' | 'text',\n cwd: string,\n verbose: boolean\n): Promise<void> {\n const data = await convertCondaToRequirements(target, cwd, verbose)\n if (!data) {\n return\n }\n if (!data.ok) {\n logger.fail(data.message)\n return\n }\n\n await outputRequirements(data.data, outputKind, out)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleManifestConda } from './handle-manifest-conda'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'conda',\n description:\n '[beta] Convert a Conda environment.yml file to a python requirements.txt',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n cwd: {\n type: 'string',\n description: 'Set the cwd, defaults to process.cwd()'\n },\n out: {\n type: 'string',\n default: '-',\n description: 'Output target (use `-` or omit to print to stdout)'\n },\n verbose: {\n type: 'boolean',\n description: 'Print debug messages'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} FILE\n\n Note: FILE can be a dash (-) to indicate stdin. This way you can pipe the\n contents of a file to have it processed.\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n\n $ ${command} ./environment.yml\n `\n}\n\nexport const cmdManifestConda = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const {\n cwd = process.cwd(),\n json = false,\n markdown = false,\n out = '-',\n verbose = false\n } = cli.flags\n const [target = ''] = cli.input\n\n if (verbose) {\n logger.group('- ', parentName, config.commandName, ':')\n logger.group('- flags:', cli.flags)\n logger.groupEnd()\n logger.log('- target:', target)\n logger.log('- output:', out)\n logger.groupEnd()\n }\n\n const wasBadInput = handleBadInput(\n {\n test: !!target,\n message: 'The FILE arg is required',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: cli.input.length <= 1,\n message: 'Can only accept one DIR (make sure to escape spaces!)',\n pass: 'ok',\n fail: 'received ' + cli.input.length\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleManifestConda(\n target,\n String(out || ''),\n json ? 'json' : markdown ? 'markdown' : 'text',\n String(cwd),\n Boolean(verbose)\n )\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\n\nimport colors from 'yoctocolors-cjs'\n\nimport { isDebug } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport constants from '../../constants'\n\nexport async function convertGradleToMaven(\n target: string,\n bin: string,\n cwd: string,\n verbose: boolean,\n gradleOpts: string[]\n) {\n if (verbose) {\n logger.log('[VERBOSE] Resolving:', [cwd, bin])\n }\n const rbin = path.resolve(cwd, bin)\n if (verbose) {\n logger.log('[VERBOSE] Resolving:', [cwd, target])\n }\n const rtarget = path.resolve(cwd, target)\n\n const binExists = fs.existsSync(rbin)\n\n const targetExists = fs.existsSync(rtarget)\n\n logger.group('gradle2maven:')\n if (verbose || isDebug()) {\n logger.log(\n `[VERBOSE] - Absolute bin path: \\`${rbin}\\` (${binExists ? 'found' : colors.red('not found!')})`\n )\n logger.log(\n `[VERBOSE] - Absolute target path: \\`${rtarget}\\` (${targetExists ? 'found' : colors.red('not found!')})`\n )\n } else {\n logger.log(`- executing: \\`${rbin}\\``)\n if (!binExists) {\n logger.warn(\n 'Warning: It appears the executable could not be found at this location. An error might be printed later because of that.'\n )\n }\n logger.log(`- src dir: \\`${rtarget}\\``)\n if (!targetExists) {\n logger.warn(\n 'Warning: It appears the src dir could not be found at this location. An error might be printed later because of that.'\n )\n }\n }\n logger.groupEnd()\n\n try {\n // Run gradlew with the init script we provide which should yield zero or more\n // pom files. We have to figure out where to store those pom files such that\n // we can upload them and predict them through the GitHub API. We could do a\n // .socket folder. We could do a socket.pom.gz with all the poms, although\n // I'd prefer something plain-text if it is to be committed.\n\n // Note: init.gradle will be exported by .config/rollup.dist.config.mjs\n const initLocation = path.join(constants.rootDistPath, 'init.gradle')\n const commandArgs = ['--init-script', initLocation, ...gradleOpts, 'pom']\n\n if (verbose) {\n logger.log('[VERBOSE] Executing:', [bin], ', args:', commandArgs)\n }\n\n logger.log(\n `Converting gradle to maven from \\`${bin}\\` on \\`${target}\\` ...`\n )\n const output = await execGradleWithSpinner(rbin, commandArgs, rtarget, cwd)\n\n if (verbose) {\n logger.group('[VERBOSE] gradle stdout:')\n logger.log(output)\n logger.groupEnd()\n }\n if (output.code !== 0) {\n process.exitCode = 1\n logger.fail(`Gradle exited with exit code ${output.code}`)\n // (In verbose mode, stderr was printed above, no need to repeat it)\n if (!verbose) {\n logger.group('stderr:')\n logger.error(output.stderr)\n logger.groupEnd()\n }\n return\n }\n logger.success('Executed gradle successfully')\n logger.log('Reported exports:')\n output.stdout.replace(\n /^POM file copied to: (.*)/gm,\n (_all: string, fn: string) => {\n logger.log('- ', fn)\n return fn\n }\n )\n logger.log('')\n logger.log(\n 'Next step is to generate a Scan by running the `socket scan create` command on the same directory'\n )\n } catch (e) {\n process.exitCode = 1\n logger.fail(\n 'There was an unexpected error while generating manifests' +\n (verbose ? '' : ' (use --verbose for details)')\n )\n if (verbose) {\n logger.group('[VERBOSE] error:')\n logger.log(e)\n logger.groupEnd()\n }\n }\n}\n\nasync function execGradleWithSpinner(\n bin: string,\n commandArgs: string[],\n target: string,\n cwd: string\n): Promise<{ code: number; stdout: string; stderr: string }> {\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n let pass = false\n try {\n spinner.start(\n `Running gradlew... (this can take a while, it depends on how long gradlew has to run)`\n )\n const output = await spawn(bin, commandArgs, {\n // We can pipe the output through to have the user see the result\n // of running gradlew, but then we can't (easily) gather the output\n // to discover the generated files... probably a flag we should allow?\n // stdio: isDebug() ? 'inherit' : undefined,\n cwd: target || cwd\n })\n pass = true\n const { code, stderr, stdout } = output\n return { code, stdout, stderr }\n } finally {\n if (pass) {\n spinner.successAndStop('Completed gradlew execution')\n } else {\n spinner.failAndStop('There was an error while trying to run gradlew.')\n }\n }\n}\n","import path from 'node:path'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { convertGradleToMaven } from './convert_gradle_to_maven'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'gradle',\n description:\n '[beta] Use Gradle to generate a manifest file (`pom.xml`) for a Gradle/Java/Kotlin/etc project',\n hidden: false,\n flags: {\n ...commonFlags,\n bin: {\n type: 'string',\n description: 'Location of gradlew binary to use, default: CWD/gradlew'\n },\n cwd: {\n type: 'string',\n description: 'Set the cwd, defaults to process.cwd()'\n },\n gradleOpts: {\n type: 'string',\n default: '',\n description:\n 'Additional options to pass on to ./gradlew, see `./gradlew --help`'\n },\n task: {\n type: 'string',\n default: 'all',\n description: 'Task to target. By default targets all'\n },\n verbose: {\n type: 'boolean',\n description: 'Print debug messages'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} [--bin=path/to/gradle/binary] [--out=path/to/result] DIR\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Uses gradle, preferably through your local project \\`gradlew\\`, to generate a\n \\`pom.xml\\` file for each task. If you have no \\`gradlew\\` you can try the\n global \\`gradle\\` binary but that may not work (hard to predict).\n\n The \\`pom.xml\\` is a manifest file similar to \\`package.json\\` for npm or\n or requirements.txt for PyPi), but specifically for Maven, which is Java's\n dependency repository. Languages like Kotlin and Scala piggy back on it too.\n\n There are some caveats with the gradle to \\`pom.xml\\` conversion:\n\n - each task will generate its own xml file and by default it generates one xml\n for every task.\n\n - it's possible certain features don't translate well into the xml. If you\n think something is missing that could be supported please reach out.\n\n - it works with your \\`gradlew\\` from your repo and local settings and config\n\n Support is beta. Please report issues or give us feedback on what's missing.\n\n Examples\n\n $ ${command} .\n $ ${command} --bin=../gradlew .\n `\n}\n\nexport const cmdManifestGradle = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const verbose = Boolean(cli.flags['verbose'])\n\n if (verbose) {\n logger.group('- ', parentName, config.commandName, ':')\n logger.group('- flags:', cli.flags)\n logger.groupEnd()\n logger.log('- input:', cli.input)\n logger.groupEnd()\n }\n\n const [target = ''] = cli.input\n\n // TODO: I'm not sure it's feasible to parse source file from stdin. We could\n // try, store contents in a file in some folder, target that folder... what\n // would the file name be?\n\n const wasBadInput = handleBadInput(\n {\n test: !!target && target !== '-',\n message: 'The DIR arg is required',\n pass: 'ok',\n fail: target === '-' ? 'stdin is not supported' : 'missing'\n },\n {\n nook: true,\n test: cli.input.length <= 1,\n message: 'Can only accept one DIR (make sure to escape spaces!)',\n pass: 'ok',\n fail: 'received ' + cli.input.length\n }\n )\n if (wasBadInput) {\n return\n }\n\n const { bin = path.join(target, 'gradlew'), cwd = process.cwd() } = cli.flags\n\n if (verbose) {\n logger.group()\n logger.log('- target:', target)\n logger.log('- gradle bin:', bin)\n logger.groupEnd()\n }\n\n let gradleOpts: string[] = []\n if (cli.flags['gradleOpts']) {\n gradleOpts = (cli.flags['gradleOpts'] as string)\n .split(' ')\n .map(s => s.trim())\n .filter(Boolean)\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await convertGradleToMaven(\n target,\n String(bin),\n String(cwd),\n verbose,\n gradleOpts\n )\n}\n","import path from 'node:path'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport constants from '../../constants'\nimport { safeReadFile } from '../../utils/fs'\n\nexport async function convertSbtToMaven(\n target: string,\n bin: string,\n out: string,\n verbose: boolean,\n sbtOpts: string[]\n) {\n // Lazily access constants.spinner.\n const { spinner } = constants\n const rbin = path.resolve(bin)\n const rtarget = path.resolve(target)\n\n if (verbose) {\n logger.group('sbt2maven:')\n logger.log(`[VERBOSE] - Absolute bin path: \\`${rbin}\\``)\n logger.log(`[VERBOSE] - Absolute target path: \\`${rtarget}\\``)\n // logger.log(`[VERBOSE] - Absolute out path: \\`${rout}\\``)\n logger.groupEnd()\n } else {\n logger.group('sbt2maven:')\n logger.log(`- executing: \\`${bin}\\``)\n logger.log(`- src dir: \\`${target}\\``)\n // logger.log(`- dst dir: \\`${out}\\``)\n logger.groupEnd()\n }\n\n try {\n spinner.start(`Converting sbt to maven from \\`${bin}\\` on \\`${target}\\`...`)\n\n // Run sbt with the init script we provide which should yield zero or more\n // pom files. We have to figure out where to store those pom files such that\n // we can upload them and predict them through the GitHub API. We could do a\n // .socket folder. We could do a socket.pom.gz with all the poms, although\n // I'd prefer something plain-text if it is to be committed.\n const output = await spawn(bin, ['makePom'].concat(sbtOpts), {\n cwd: target || '.'\n })\n\n spinner.stop()\n\n if (verbose) {\n logger.group('[VERBOSE] sbt stdout:')\n logger.log(output)\n logger.groupEnd()\n }\n if (output.stderr) {\n process.exitCode = 1\n logger.fail('There were errors while running sbt')\n // (In verbose mode, stderr was printed above, no need to repeat it)\n if (!verbose) {\n logger.group('[VERBOSE] stderr:')\n logger.error(output.stderr)\n logger.groupEnd()\n }\n return\n }\n const poms: string[] = []\n output.stdout.replace(/Wrote (.*?.pom)\\n/g, (_all: string, fn: string) => {\n poms.push(fn)\n return fn\n })\n if (!poms.length) {\n process.exitCode = 1\n logger.fail(\n 'There were no errors from sbt but it seems to not have generated any poms either'\n )\n return\n }\n // Move the pom file to ...? initial cwd? loc will be an absolute path, or dump to stdout\n // TODO: what to do with multiple output files? Do we want to dump them to stdout? Raw or with separators or ?\n // TODO: maybe we can add an option to target a specific file to dump to stdout\n if (out === '-' && poms.length === 1) {\n logger.log('Result:\\n```')\n logger.log(await safeReadFile(poms[0]!))\n logger.log('```')\n logger.success(`OK`)\n } else if (out === '-') {\n process.exitCode = 1\n logger.fail(\n 'Requested out target was stdout but there are multiple generated files'\n )\n poms.forEach(fn => logger.error('-', fn))\n logger.error('Exiting now...')\n return\n } else {\n // if (verbose) {\n // logger.log(\n // `Moving manifest file from \\`${loc.replace(/^\\/home\\/[^/]*?\\//, '~/')}\\` to \\`${out}\\``\n // )\n // } else {\n // logger.log('Moving output pom file')\n // }\n // TODO: do we prefer fs-extra? renaming can be gnarly on windows and fs-extra's version is better\n // await renamep(loc, out)\n logger.success(`Generated ${poms.length} pom files`)\n poms.forEach(fn => logger.log('-', fn))\n logger.success(`OK`)\n }\n } catch (e) {\n process.exitCode = 1\n spinner.stop()\n logger.fail(\n 'There was an unexpected error while running this' +\n (verbose ? '' : ' (use --verbose for details)')\n )\n if (verbose) {\n logger.group('[VERBOSE] error:')\n logger.log(e)\n logger.groupEnd()\n }\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { convertSbtToMaven } from './convert_sbt_to_maven'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'scala',\n description:\n \"[beta] Generate a manifest file (`pom.xml`) from Scala's `build.sbt` file\",\n hidden: false,\n flags: {\n ...commonFlags,\n bin: {\n type: 'string',\n default: 'sbt',\n description: 'Location of sbt binary to use'\n },\n cwd: {\n type: 'string',\n description: 'Set the cwd, defaults to process.cwd()'\n },\n out: {\n type: 'string',\n default: './socket.pom.xml',\n description:\n 'Path of output file; where to store the resulting manifest, see also --stdout'\n },\n stdout: {\n type: 'boolean',\n description: 'Print resulting pom.xml to stdout (supersedes --out)'\n },\n sbtOpts: {\n type: 'string',\n default: '',\n description: 'Additional options to pass on to sbt, as per `sbt --help`'\n },\n verbose: {\n type: 'boolean',\n description: 'Print debug messages'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} [--bin=path/to/sbt/binary] [--out=path/to/result] FILE|DIR\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Uses \\`sbt makePom\\` to generate a \\`pom.xml\\` from your \\`build.sbt\\` file.\n This xml file is the dependency manifest (like a package.json\n for Node.js or requirements.txt for PyPi), but specifically for Scala.\n\n There are some caveats with \\`build.sbt\\` to \\`pom.xml\\` conversion:\n\n - the xml is exported as socket.pom.xml as to not confuse existing build tools\n but it will first hit your /target/sbt<version> folder (as a different name)\n\n - the pom.xml format (standard by Scala) does not support certain sbt features\n - \\`excludeAll()\\`, \\`dependencyOverrides\\`, \\`force()\\`, \\`relativePath\\`\n - For details: https://www.scala-sbt.org/1.x/docs/Library-Management.html\n\n - it uses your sbt settings and local configuration verbatim\n\n - it can only export one target per run, so if you have multiple targets like\n development and production, you must run them separately.\n\n You can optionally configure the path to the \\`sbt\\` bin to invoke.\n\n Support is beta. Please report issues or give us feedback on what's missing.\n\n This is only for SBT. If your Scala setup uses gradle, please see the help\n sections for \\`socket manifest gradle\\` or \\`socket cdxgen\\`.\n\n Examples\n\n $ ${command} ./build.sbt\n $ ${command} --bin=/usr/bin/sbt ./build.sbt\n `\n}\n\nexport const cmdManifestScala = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const verbose = Boolean(cli.flags['verbose'])\n\n if (verbose) {\n logger.group('- ', parentName, config.commandName, ':')\n logger.group('- flags:', cli.flags)\n logger.groupEnd()\n logger.log('- input:', cli.input)\n logger.groupEnd()\n }\n\n const [target = ''] = cli.input\n\n // TODO: I'm not sure it's feasible to parse source file from stdin. We could\n // try, store contents in a file in some folder, target that folder... what\n // would the file name be?\n\n const wasBadInput = handleBadInput(\n {\n test: !!target && target !== '-',\n message: 'The DIR arg is required',\n pass: 'ok',\n fail: target === '-' ? 'stdin is not supported' : 'missing'\n },\n {\n nook: true,\n test: cli.input.length <= 1,\n message: 'Can only accept one DIR (make sure to escape spaces!)',\n pass: 'ok',\n fail: 'received ' + cli.input.length\n }\n )\n if (wasBadInput) {\n return\n }\n\n let bin: string = 'sbt'\n if (cli.flags['bin']) {\n bin = cli.flags['bin'] as string\n }\n\n let out: string = './socket.pom.xml'\n if (cli.flags['out']) {\n out = cli.flags['out'] as string\n }\n if (cli.flags['stdout']) {\n out = '-'\n }\n\n if (verbose) {\n logger.group()\n logger.log('- target:', target)\n logger.log('- gradle bin:', bin)\n logger.log('- out:', out)\n logger.groupEnd()\n }\n\n let sbtOpts: string[] = []\n if (cli.flags['sbtOpts']) {\n sbtOpts = (cli.flags['sbtOpts'] as string)\n .split(' ')\n .map(s => s.trim())\n .filter(Boolean)\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await convertSbtToMaven(target, bin, out, verbose, sbtOpts)\n}\n","import { existsSync } from 'node:fs'\nimport path from 'node:path'\n\nimport meow from 'meow'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { cmdManifestConda } from './cmd-manifest-conda'\nimport { cmdManifestGradle } from './cmd-manifest-gradle'\nimport { cmdManifestScala } from './cmd-manifest-scala'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'auto',\n description: 'Auto-detect build and attempt to generate manifest file',\n hidden: false,\n flags: {\n ...commonFlags,\n cwd: {\n type: 'string',\n description: 'Set the cwd, defaults to process.cwd()'\n },\n verbose: {\n type: 'boolean',\n default: false,\n description: 'Enable debug output, may help when running into errors'\n }\n // TODO: support output flags\n },\n help: (command, config) => `\n Usage\n $ ${command}\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Tries to figure out what language your current repo uses. If it finds a\n supported case then it will try to generate the manifest file for that\n language with the default or detected settings.\n `\n}\n\nexport const cmdManifestAuto = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n const verbose = !!cli.flags['verbose']\n const cwd = (cli.flags['cwd'] as string) ?? process.cwd()\n\n if (verbose) {\n logger.group('- ', parentName, config.commandName, ':')\n logger.group('- flags:', cli.flags)\n logger.groupEnd()\n logger.log('- input:', cli.input)\n logger.log('- cwd:', cwd)\n logger.groupEnd()\n }\n\n const subArgs = []\n if (verbose) {\n subArgs.push('--verbose')\n }\n\n const dir = cwd\n\n if (existsSync(path.join(dir, 'build.sbt'))) {\n logger.log('Detected a Scala sbt build, running default Scala generator...')\n if (cwd) {\n subArgs.push('--cwd', cwd)\n }\n subArgs.push(dir)\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n await cmdManifestScala.run(subArgs, importMeta, { parentName })\n return\n }\n\n if (existsSync(path.join(dir, 'gradlew'))) {\n logger.log('Detected a gradle build, running default gradle generator...')\n if (cwd) {\n // This command takes the cwd as first arg.\n subArgs.push(cwd)\n }\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n await cmdManifestGradle.run(subArgs, importMeta, { parentName })\n return\n }\n\n const envyml = path.join(dir, 'environment.yml')\n const hasEnvyml = existsSync(envyml)\n const envyaml = path.join(dir, 'environment.yaml')\n const hasEnvyaml = !hasEnvyml && existsSync(envyaml)\n if (hasEnvyml || hasEnvyaml) {\n logger.log(\n 'Detected an environment.yml file, running default Conda generator...'\n )\n // This command takes the TARGET as first arg.\n subArgs.push(hasEnvyml ? envyml : hasEnvyaml ? envyaml : '')\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n await cmdManifestConda.run(subArgs, importMeta, { parentName })\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n // Show new help screen and exit.\n meow(\n `\n $ ${parentName} ${config.commandName}\n\n Unfortunately this script did not discover a supported language in the\n current folder.\n\n - Make sure this script would work with your target build\n - Make sure to run it from the correct folder\n - Make sure the necessary build tools are available (\\`PATH\\`)\n\n If that doesn't work, see \\`${parentName} <lang> --help\\` for config details for\n your target language.\n `,\n {\n argv: [],\n description: config.description,\n importMeta\n }\n ).showHelp()\n}\n","import path from 'node:path'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { convertGradleToMaven } from './convert_gradle_to_maven'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\n// TODO: we may want to dedupe some pieces for all gradle languages. I think it\n// makes sense to have separate commands for them and I think it makes\n// sense for the help panels to note the requested language, rather than\n// `socket manifest kotlin` to print help screens with `gradle` as the\n// command. Room for improvement.\nconst config: CliCommandConfig = {\n commandName: 'kotlin',\n description:\n '[beta] Use Gradle to generate a manifest file (`pom.xml`) for a Kotlin project',\n hidden: false,\n flags: {\n ...commonFlags,\n bin: {\n type: 'string',\n description: 'Location of gradlew binary to use, default: CWD/gradlew'\n },\n cwd: {\n type: 'string',\n description: 'Set the cwd, defaults to process.cwd()'\n },\n gradleOpts: {\n type: 'string',\n default: '',\n description:\n 'Additional options to pass on to ./gradlew, see `./gradlew --help`'\n },\n task: {\n type: 'string',\n default: 'all',\n description: 'Task to target. By default targets all'\n },\n verbose: {\n type: 'boolean',\n description: 'Print debug messages'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} [--bin=path/to/gradle/binary] [--out=path/to/result] DIR\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Uses gradle, preferably through your local project \\`gradlew\\`, to generate a\n \\`pom.xml\\` file for each task. If you have no \\`gradlew\\` you can try the\n global \\`gradle\\` binary but that may not work (hard to predict).\n\n The \\`pom.xml\\` is a manifest file similar to \\`package.json\\` for npm or\n or requirements.txt for PyPi), but specifically for Maven, which is Java's\n dependency repository. Languages like Kotlin and Scala piggy back on it too.\n\n There are some caveats with the gradle to \\`pom.xml\\` conversion:\n\n - each task will generate its own xml file and by default it generates one xml\n for every task. (This may be a good thing!)\n\n - it's possible certain features don't translate well into the xml. If you\n think something is missing that could be supported please reach out.\n\n - it works with your \\`gradlew\\` from your repo and local settings and config\n\n Support is beta. Please report issues or give us feedback on what's missing.\n\n Examples\n\n $ ${command} .\n $ ${command} --bin=../gradlew .\n `\n}\n\nexport const cmdManifestKotlin = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const verbose = Boolean(cli.flags['verbose'])\n\n if (verbose) {\n logger.group('- ', parentName, config.commandName, ':')\n logger.group('- flags:', cli.flags)\n logger.groupEnd()\n logger.log('- input:', cli.input)\n logger.groupEnd()\n }\n\n const [target = ''] = cli.input\n\n // TODO: I'm not sure it's feasible to parse source file from stdin. We could\n // try, store contents in a file in some folder, target that folder... what\n // would the file name be?\n\n const wasBadInput = handleBadInput(\n {\n test: !!target && target !== '-',\n message: 'The DIR arg is required',\n pass: 'ok',\n fail: target === '-' ? 'stdin is not supported' : 'missing'\n },\n {\n nook: true,\n test: cli.input.length <= 1,\n message: 'Can only accept one DIR (make sure to escape spaces!)',\n pass: 'ok',\n fail: 'received ' + cli.input.length\n }\n )\n if (wasBadInput) {\n return\n }\n\n const { bin = path.join(target, 'gradlew'), cwd = process.cwd() } = cli.flags\n\n if (verbose) {\n logger.group()\n logger.log('- target:', target)\n logger.log('- gradle bin:', bin)\n logger.groupEnd()\n }\n\n let gradleOpts: string[] = []\n if (cli.flags['gradleOpts']) {\n gradleOpts = (cli.flags['gradleOpts'] as string)\n .split(' ')\n .map(s => s.trim())\n .filter(Boolean)\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await convertGradleToMaven(\n target,\n String(bin),\n String(cwd),\n verbose,\n gradleOpts\n )\n}\n","import { cmdManifestAuto } from './cmd-manifest-auto'\nimport { cmdManifestConda } from './cmd-manifest-conda'\nimport { cmdManifestGradle } from './cmd-manifest-gradle'\nimport { cmdManifestKotlin } from './cmd-manifest-kotlin'\nimport { cmdManifestScala } from './cmd-manifest-scala'\nimport { commonFlags } from '../../flags'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst config: CliCommandConfig = {\n commandName: 'manifest',\n description: 'Generate a dependency manifest for given file or dir',\n hidden: false,\n flags: {\n ...commonFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <language> <target>\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Generates a declarative dependency manifest (like a package.json for Node.JS\n or requirements.txt for PyPi), but for certain supported ecosystems\n where it's common to use a dynamic manifest, like Scala's sbt.\n\n Only certain languages are supported and there may be language specific\n configurations available. See \\`manifest <language> --help\\` for usage details\n per language.\n\n Currently supported language: scala [beta], gradle [beta], kotlin (through\n gradle) [beta].\n\n Examples\n\n $ ${command} scala .\n\n To have it auto-detect and attempt to run:\n\n $ ${command} yolo\n `\n}\n\nexport const cmdManifest = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n await meowWithSubcommands(\n {\n auto: cmdManifestAuto,\n conda: cmdManifestConda,\n scala: cmdManifestScala,\n gradle: cmdManifestGradle,\n kotlin: cmdManifestKotlin\n },\n {\n argv,\n aliases: {\n yolo: {\n description: config.description,\n hidden: true,\n argv: ['auto']\n }\n },\n description: config.description,\n importMeta,\n flags: config.flags,\n name: `${parentName} ${config.commandName}`\n }\n )\n}\n","import constants from '../../constants'\n\nconst { NPM } = constants\n\nexport async function wrapNpm(argv: readonly string[]) {\n // Lazily access constants.distShadowNpmBinPath.\n const shadowBin = require(constants.distShadowNpmBinPath)\n await shadowBin(NPM, argv)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { wrapNpm } from './wrap-npm'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT, NPM } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'npm',\n description: `${NPM} wrapper functionality`,\n hidden: false,\n flags: {\n ...commonFlags\n },\n help: (command, _config) => `\n Usage\n $ ${command}\n `\n}\n\nexport const cmdNpm = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n allowUnknownFlags: true,\n argv,\n config,\n importMeta,\n parentName\n })\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await wrapNpm(argv)\n}\n","import constants from '../../constants'\n\nconst { NPX } = constants\n\nexport async function wrapNpx(argv: readonly string[]) {\n // Lazily access constants.distShadowNpmBinPath.\n const shadowBin = require(constants.distShadowNpmBinPath)\n await shadowBin(NPX, argv)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { wrapNpx } from './wrap-npx'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT, NPX } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'npx',\n description: `${NPX} wrapper functionality`,\n hidden: false,\n flags: {\n ...commonFlags\n },\n help: (command, _config) => `\n Usage\n $ ${command}\n `\n}\n\nexport const cmdNpx = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n allowUnknownFlags: true,\n argv,\n config,\n importMeta,\n parentName\n })\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await wrapNpx(argv)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'oops',\n description: 'Trigger an intentional error (for development)',\n hidden: true,\n flags: {\n ...commonFlags\n },\n help: (parentName, config) => `\n Usage\n $ ${parentName} ${config.commandName}\n\n Don't run me.\n `\n}\n\nexport const cmdOops = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n throw new Error('This error was intentionally left blank')\n}\n","import constants from '../../constants'\n\nimport type { Agent } from '../../utils/package-environment'\n\ntype AgentDepsIncludesFn = (stdout: string, name: string) => boolean\n\nconst { BUN, NPM, PNPM, VLT, YARN_BERRY, YARN_CLASSIC } = constants\n\nfunction matchLsCmdViewHumanStdout(stdout: string, name: string) {\n return stdout.includes(` ${name}@`)\n}\n\nfunction matchQueryCmdStdout(stdout: string, name: string) {\n return stdout.includes(`\"${name}\"`)\n}\n\nexport const depsIncludesByAgent = new Map<Agent, AgentDepsIncludesFn>([\n [BUN, matchLsCmdViewHumanStdout],\n [NPM, matchQueryCmdStdout],\n [PNPM, matchQueryCmdStdout],\n [VLT, matchQueryCmdStdout],\n [YARN_BERRY, matchLsCmdViewHumanStdout],\n [YARN_CLASSIC, matchLsCmdViewHumanStdout]\n])\n","import type { EnvDetails } from '../../utils/package-environment'\n\nexport function getDependencyEntries(pkgEnvDetails: EnvDetails) {\n const {\n dependencies,\n devDependencies,\n optionalDependencies,\n peerDependencies\n } = pkgEnvDetails.editablePkgJson.content\n return [\n [\n 'dependencies',\n dependencies ? { __proto__: null, ...dependencies } : undefined\n ],\n [\n 'devDependencies',\n devDependencies ? { __proto__: null, ...devDependencies } : undefined\n ],\n [\n 'peerDependencies',\n peerDependencies ? { __proto__: null, ...peerDependencies } : undefined\n ],\n [\n 'optionalDependencies',\n optionalDependencies\n ? { __proto__: null, ...optionalDependencies }\n : undefined\n ]\n ].filter(({ 1: o }) => o) as Array<[string, NonNullable<typeof dependencies>]>\n}\n","import constants from '../../constants'\n\nimport type { NpmOverrides, Overrides, PnpmOrYarnOverrides } from './types'\nimport type { Agent, EnvDetails } from '../../utils/package-environment'\n\nconst {\n BUN,\n NPM,\n OVERRIDES,\n PNPM,\n RESOLUTIONS,\n VLT,\n YARN_BERRY,\n YARN_CLASSIC\n} = constants\n\nfunction getOverridesDataBun(pkgEnvDetails: EnvDetails) {\n const overrides =\n pkgEnvDetails.editablePkgJson.content?.[RESOLUTIONS] ??\n ({} as PnpmOrYarnOverrides)\n return { type: YARN_BERRY, overrides }\n}\n\n// npm overrides documentation:\n// https://docs.npmjs.com/cli/v10/configuring-npm/package-json#overrides\nfunction getOverridesDataNpm(pkgEnvDetails: EnvDetails) {\n const overrides =\n pkgEnvDetails.editablePkgJson.content?.[OVERRIDES] ?? ({} as NpmOverrides)\n return { type: NPM, overrides }\n}\n\n// pnpm overrides documentation:\n// https://pnpm.io/package_json#pnpmoverrides\nfunction getOverridesDataPnpm(pkgEnvDetails: EnvDetails) {\n const overrides =\n (pkgEnvDetails.editablePkgJson.content as any)?.[PNPM]?.[OVERRIDES] ??\n ({} as PnpmOrYarnOverrides)\n return { type: PNPM, overrides }\n}\n\nfunction getOverridesDataVlt(pkgEnvDetails: EnvDetails) {\n const overrides =\n pkgEnvDetails.editablePkgJson.content?.[OVERRIDES] ?? ({} as NpmOverrides)\n return { type: VLT, overrides }\n}\n\n// Yarn resolutions documentation:\n// https://yarnpkg.com/configuration/manifest#resolutions\nfunction getOverridesDataYarn(pkgEnvDetails: EnvDetails) {\n const overrides =\n pkgEnvDetails.editablePkgJson.content?.[RESOLUTIONS] ??\n ({} as PnpmOrYarnOverrides)\n return { type: YARN_BERRY, overrides }\n}\n\n// Yarn resolutions documentation:\n// https://classic.yarnpkg.com/en/docs/selective-version-resolutions\nfunction getOverridesDataYarnClassic(pkgEnvDetails: EnvDetails) {\n const overrides =\n pkgEnvDetails.editablePkgJson.content?.[RESOLUTIONS] ??\n ({} as PnpmOrYarnOverrides)\n return { type: YARN_CLASSIC, overrides }\n}\n\nexport type GetOverrides = (pkgEnvDetails: EnvDetails) => GetOverridesResult\n\nexport type GetOverridesResult = { type: Agent; overrides: Overrides }\n\nexport const overridesDataByAgent = new Map<Agent, GetOverrides>([\n [BUN, getOverridesDataBun],\n [NPM, getOverridesDataNpm],\n [PNPM, getOverridesDataPnpm],\n [VLT, getOverridesDataVlt],\n [YARN_BERRY, getOverridesDataYarn],\n [YARN_CLASSIC, getOverridesDataYarnClassic]\n] as ReadonlyArray<[Agent, GetOverrides]>)\n","import { escapeRegExp } from '@socketsecurity/registry/lib/regexps'\n\nimport constants from '../../constants'\n\nimport type { Agent } from '../../utils/package-environment'\n\nexport type AgentLockIncludesFn = (\n lockSrc: string,\n name: string,\n ext?: string | undefined\n) => boolean\n\nconst { BUN, LOCK_EXT, NPM, PNPM, VLT, YARN_BERRY, YARN_CLASSIC } = constants\n\nfunction includesNpm(lockSrc: string, name: string) {\n // Detects the package name in the following cases:\n // \"name\":\n return lockSrc.includes(`\"${name}\":`)\n}\n\nfunction includesBun(lockSrc: string, name: string, lockName?: string) {\n // This is a bit counterintuitive. When lockName ends with a .lockb\n // we treat it as a yarn.lock. When lockName ends with a .lock we\n // treat it as a package-lock.json. The bun.lock format is not identical\n // package-lock.json, however it close enough for npmLockIncludes to work.\n const lockfileScanner = lockName?.endsWith(LOCK_EXT)\n ? includesNpm\n : includesYarn\n return lockfileScanner(lockSrc, name)\n}\n\nfunction includesPnpm(lockSrc: string, name: string) {\n const escapedName = escapeRegExp(name)\n return new RegExp(\n // Detects the package name in the following cases:\n // /name/\n // 'name'\n // name:\n // name@\n `(?<=^\\\\s*)(?:(['/])${escapedName}\\\\1|${escapedName}(?=[:@]))`,\n 'm'\n ).test(lockSrc)\n}\n\nfunction includesVlt(lockSrc: string, name: string) {\n // Detects the package name in the following cases:\n // \"name\"\n return lockSrc.includes(`\"${name}\"`)\n}\n\nfunction includesYarn(lockSrc: string, name: string) {\n const escapedName = escapeRegExp(name)\n return new RegExp(\n // Detects the package name in the following cases:\n // \"name@\n // , \"name@\n // name@\n // , name@\n `(?<=(?:^\\\\s*|,\\\\s*)\"?)${escapedName}(?=@)`,\n 'm'\n ).test(lockSrc)\n}\n\nexport const lockfileIncludesByAgent = new Map<Agent, AgentLockIncludesFn>([\n [BUN, includesBun],\n [NPM, includesNpm],\n [PNPM, includesPnpm],\n [VLT, includesVlt],\n [YARN_BERRY, includesYarn],\n [YARN_CLASSIC, includesYarn]\n])\n","import { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport constants from '../../constants'\n\nimport type { Agent, EnvDetails } from '../../utils/package-environment'\n\nconst { BUN, NPM, PNPM, VLT, YARN_BERRY, YARN_CLASSIC } = constants\n\nfunction cleanupQueryStdout(stdout: string): string {\n if (stdout === '') {\n return ''\n }\n let pkgs\n try {\n pkgs = JSON.parse(stdout)\n } catch {}\n if (!Array.isArray(pkgs)) {\n return ''\n }\n const names = new Set<string>()\n for (const { _id, name, pkgid } of pkgs) {\n // `npm query` results may not have a \"name\" property, in which case we\n // fallback to \"_id\" and then \"pkgid\".\n // `vlt ls --view json` results always have a \"name\" property.\n const fallback = _id ?? pkgid ?? ''\n const resolvedName = name ?? fallback.slice(0, fallback.indexOf('@', 1))\n // Add package names, except for those under the `@types` scope as those\n // are known to only be dev dependencies.\n if (resolvedName && !resolvedName.startsWith('@types/')) {\n names.add(resolvedName)\n }\n }\n return JSON.stringify([...names], null, 2)\n}\n\nfunction parsableToQueryStdout(stdout: string) {\n if (stdout === '') {\n return ''\n }\n // Convert the parsable stdout into a json array of unique names.\n // The matchAll regexp looks for a forward (posix) or backward (win32) slash\n // and matches one or more non-slashes until the newline.\n const names = new Set(stdout.matchAll(/(?<=[/\\\\])[^/\\\\]+(?=\\n)/g))\n return JSON.stringify([...names], null, 2)\n}\n\nasync function npmQuery(npmExecPath: string, cwd: string): Promise<string> {\n let stdout = ''\n try {\n stdout = (await spawn(npmExecPath, ['query', ':not(.dev)'], { cwd })).stdout\n } catch {}\n return cleanupQueryStdout(stdout)\n}\n\nasync function lsBun(pkgEnvDetails: EnvDetails, cwd: string): Promise<string> {\n try {\n // Bun does not support filtering by production packages yet.\n // https://github.com/oven-sh/bun/issues/8283\n return (\n await spawn(pkgEnvDetails.agentExecPath, ['pm', 'ls', '--all'], { cwd })\n ).stdout\n } catch {}\n return ''\n}\n\nasync function lsNpm(pkgEnvDetails: EnvDetails, cwd: string): Promise<string> {\n return await npmQuery(pkgEnvDetails.agentExecPath, cwd)\n}\n\nasync function lsPnpm(\n pkgEnvDetails: EnvDetails,\n cwd: string,\n options?: AgentListDepsOptions | undefined\n): Promise<string> {\n const npmExecPath = options?.npmExecPath\n if (npmExecPath && npmExecPath !== NPM) {\n const result = await npmQuery(npmExecPath, cwd)\n if (result) {\n return result\n }\n }\n let stdout = ''\n try {\n stdout = (\n await spawn(\n pkgEnvDetails.agentExecPath,\n // Pnpm uses the alternative spelling of parsable.\n // https://en.wiktionary.org/wiki/parsable\n ['ls', '--parseable', '--prod', '--depth', 'Infinity'],\n { cwd }\n )\n ).stdout\n } catch {}\n return parsableToQueryStdout(stdout)\n}\n\nasync function lsVlt(pkgEnvDetails: EnvDetails, cwd: string): Promise<string> {\n let stdout = ''\n try {\n // See https://docs.vlt.sh/cli/commands/list#options.\n stdout = (\n await spawn(\n pkgEnvDetails.agentExecPath,\n ['ls', '--view', 'human', ':not(.dev)'],\n {\n cwd\n }\n )\n ).stdout\n } catch {}\n return cleanupQueryStdout(stdout)\n}\n\nasync function lsYarnBerry(\n pkgEnvDetails: EnvDetails,\n cwd: string\n): Promise<string> {\n try {\n return (\n // Yarn Berry does not support filtering by production packages yet.\n // https://github.com/yarnpkg/berry/issues/5117\n (\n await spawn(\n pkgEnvDetails.agentExecPath,\n ['info', '--recursive', '--name-only'],\n {\n cwd\n }\n )\n ).stdout.trim()\n )\n } catch {}\n return ''\n}\n\nasync function lsYarnClassic(\n pkgEnvDetails: EnvDetails,\n cwd: string\n): Promise<string> {\n try {\n // However, Yarn Classic does support it.\n // https://github.com/yarnpkg/yarn/releases/tag/v1.0.0\n // > Fix: Excludes dev dependencies from the yarn list output when the\n // environment is production\n return (\n await spawn(pkgEnvDetails.agentExecPath, ['list', '--prod'], { cwd })\n ).stdout.trim()\n } catch {}\n return ''\n}\n\nexport type AgentListDepsOptions = { npmExecPath?: string }\n\nexport type AgentListDepsFn = (\n pkgEnvDetails: EnvDetails,\n cwd: string,\n options?: AgentListDepsOptions | undefined\n) => Promise<string>\n\nexport const lsByAgent = new Map<Agent, AgentListDepsFn>([\n [BUN, lsBun],\n [NPM, lsNpm],\n [PNPM, lsPnpm],\n [VLT, lsVlt],\n [YARN_BERRY, lsYarnBerry],\n [YARN_CLASSIC, lsYarnClassic]\n])\n","export const CMD_NAME = 'socket optimize'\n","import { hasKeys, isObject } from '@socketsecurity/registry/lib/objects'\n\nimport constants from '../../constants'\n\nimport type { Overrides } from './types'\nimport type { Agent, EnvDetails } from '../../utils/package-environment'\nimport type { EditablePackageJson } from '@socketsecurity/registry/lib/packages'\n\nconst {\n BUN,\n NPM,\n OVERRIDES,\n PNPM,\n RESOLUTIONS,\n VLT,\n YARN_BERRY,\n YARN_CLASSIC\n} = constants\n\nconst depFields = [\n 'dependencies',\n 'devDependencies',\n 'peerDependencies',\n 'peerDependenciesMeta',\n 'optionalDependencies',\n 'bundleDependencies'\n]\n\nfunction getEntryIndexes(\n entries: Array<[string | symbol, any]>,\n keys: Array<string | symbol>\n): number[] {\n return keys\n .map(n => entries.findIndex(p => p[0] === n))\n .filter(n => n !== -1)\n .sort((a, b) => a - b)\n}\n\nfunction getLowestEntryIndex(\n entries: Array<[string | symbol, any]>,\n keys: Array<string | symbol>\n) {\n return getEntryIndexes(entries, keys)?.[0] ?? -1\n}\n\nfunction getHighestEntryIndex(\n entries: Array<[string | symbol, any]>,\n keys: Array<string | symbol>\n) {\n return getEntryIndexes(entries, keys).at(-1) ?? -1\n}\n\nfunction updatePkgJsonField(\n editablePkgJson: EditablePackageJson,\n field: string,\n value: any\n) {\n const oldValue = editablePkgJson.content[field]\n if (oldValue) {\n // The field already exists so we simply update the field value.\n if (field === PNPM) {\n const isPnpmObj = isObject(oldValue)\n if (hasKeys(value)) {\n editablePkgJson.update({\n [field]: {\n ...(isPnpmObj ? oldValue : {}),\n overrides: {\n ...(isPnpmObj ? (oldValue as any)[OVERRIDES] : {}),\n ...value\n }\n }\n })\n } else {\n // Properties with undefined values are omitted when saved as JSON.\n editablePkgJson.update(\n (hasKeys(oldValue)\n ? {\n [field]: {\n ...(isPnpmObj ? oldValue : {}),\n overrides: undefined\n }\n }\n : { [field]: undefined }) as typeof editablePkgJson.content\n )\n }\n } else if (field === OVERRIDES || field === RESOLUTIONS) {\n // Properties with undefined values are omitted when saved as JSON.\n editablePkgJson.update({\n [field]: hasKeys(value) ? value : undefined\n } as typeof editablePkgJson.content)\n } else {\n editablePkgJson.update({ [field]: value })\n }\n return\n }\n if (\n (field === OVERRIDES || field === PNPM || field === RESOLUTIONS) &&\n !hasKeys(value)\n ) {\n return\n }\n // Since the field doesn't exist we want to insert it into the package.json\n // in a place that makes sense, e.g. close to the \"dependencies\" field. If\n // we can't find a place to insert the field we'll add it to the bottom.\n const entries = Object.entries(editablePkgJson.content)\n let insertIndex = -1\n let isPlacingHigher = false\n if (field === OVERRIDES) {\n insertIndex = getLowestEntryIndex(entries, [RESOLUTIONS])\n if (insertIndex === -1) {\n isPlacingHigher = true\n insertIndex = getHighestEntryIndex(entries, [...depFields, PNPM])\n }\n } else if (field === RESOLUTIONS) {\n isPlacingHigher = true\n insertIndex = getHighestEntryIndex(entries, [...depFields, OVERRIDES, PNPM])\n } else if (field === PNPM) {\n insertIndex = getLowestEntryIndex(entries, [OVERRIDES, RESOLUTIONS])\n if (insertIndex === -1) {\n isPlacingHigher = true\n insertIndex = getHighestEntryIndex(entries, depFields)\n }\n }\n if (insertIndex === -1) {\n insertIndex = getLowestEntryIndex(entries, ['engines', 'files'])\n }\n if (insertIndex === -1) {\n isPlacingHigher = true\n insertIndex = getHighestEntryIndex(entries, ['exports', 'imports', 'main'])\n }\n if (insertIndex === -1) {\n insertIndex = entries.length\n } else if (isPlacingHigher) {\n insertIndex += 1\n }\n entries.splice(insertIndex, 0, [\n field,\n field === PNPM ? { [OVERRIDES]: value } : value\n ])\n editablePkgJson.fromJSON(\n `${JSON.stringify(Object.fromEntries(entries), null, 2)}\\n`\n )\n}\n\nfunction updateOverridesField(pkgEnvDetails: EnvDetails, overrides: Overrides) {\n updatePkgJsonField(pkgEnvDetails.editablePkgJson, OVERRIDES, overrides)\n}\n\nfunction updateResolutionsField(\n pkgEnvDetails: EnvDetails,\n overrides: Overrides\n) {\n updatePkgJsonField(pkgEnvDetails.editablePkgJson, RESOLUTIONS, overrides)\n}\n\nfunction updatePnpmField(pkgEnvDetails: EnvDetails, overrides: Overrides) {\n updatePkgJsonField(pkgEnvDetails.editablePkgJson, PNPM, overrides)\n}\n\nexport type AgentModifyManifestFn = (\n pkgEnvDetails: EnvDetails,\n overrides: Overrides\n) => void\n\nexport const updateManifestByAgent = new Map<Agent, AgentModifyManifestFn>([\n [BUN, updateResolutionsField],\n [NPM, updateOverridesField],\n [PNPM, updatePnpmField],\n [VLT, updateOverridesField],\n [YARN_BERRY, updateResolutionsField],\n [YARN_CLASSIC, updateResolutionsField]\n])\n","import path from 'node:path'\n\nimport npa from 'npm-package-arg'\nimport semver from 'semver'\n\nimport { getManifestData } from '@socketsecurity/registry'\nimport { hasOwn, toSortedObject } from '@socketsecurity/registry/lib/objects'\nimport { fetchPackageManifest } from '@socketsecurity/registry/lib/packages'\nimport { pEach } from '@socketsecurity/registry/lib/promises'\nimport { Spinner } from '@socketsecurity/registry/lib/spinner'\n\nimport { depsIncludesByAgent } from './deps-includes-by-agent'\nimport { getDependencyEntries } from './get-dependency-entries'\nimport { overridesDataByAgent } from './get-overrides-by-agent'\nimport { lockfileIncludesByAgent } from './lockfile-includes-by-agent'\nimport { lsByAgent } from './ls-by-agent'\nimport { CMD_NAME } from './shared'\nimport { updateManifestByAgent } from './update-manifest-by-agent'\nimport constants from '../../constants'\nimport { cmdPrefixMessage } from '../../utils/cmd'\nimport { globWorkspace } from '../../utils/glob'\n\nimport type { GetOverridesResult } from './get-overrides-by-agent'\nimport type { AgentLockIncludesFn } from './lockfile-includes-by-agent'\nimport type { EnvDetails } from '../../utils/package-environment'\nimport type { Logger } from '@socketsecurity/registry/lib/logger'\nimport type { PackageJson } from '@socketsecurity/registry/lib/packages'\n\ntype AddOverridesOptions = {\n logger?: Logger | undefined\n pin?: boolean | undefined\n prod?: boolean | undefined\n spinner?: Spinner | undefined\n state?: AddOverridesState | undefined\n}\ntype AddOverridesState = {\n added: Set<string>\n addedInWorkspaces: Set<string>\n updated: Set<string>\n updatedInWorkspaces: Set<string>\n warnedPnpmWorkspaceRequiresNpm: boolean\n workspacePkgJsonPaths: string[]\n}\n\nconst { NPM, PNPM, YARN_CLASSIC } = constants\n\nconst manifestNpmOverrides = getManifestData(NPM)\n\nexport async function addOverrides(\n pkgEnvDetails: EnvDetails,\n pkgPath: string,\n options?: AddOverridesOptions | undefined\n): Promise<AddOverridesState> {\n const {\n agent,\n lockName,\n lockSrc,\n npmExecPath,\n pkgPath: rootPath\n } = pkgEnvDetails\n const {\n logger,\n pin,\n prod,\n spinner,\n state = {\n added: new Set(),\n addedInWorkspaces: new Set(),\n updated: new Set(),\n updatedInWorkspaces: new Set(),\n warnedPnpmWorkspaceRequiresNpm: false,\n workspacePkgJsonPaths: await globWorkspace(pkgEnvDetails)\n }\n } = { __proto__: null, ...options } as AddOverridesOptions\n const isWorkspace = state.workspacePkgJsonPaths.length > 0\n const isWorkspaceRoot = pkgPath === rootPath\n const isLockScanned = isWorkspaceRoot && !prod\n const workspaceName = isWorkspaceRoot ? '' : path.relative(rootPath, pkgPath)\n if (\n isWorkspace &&\n agent === PNPM &&\n // npmExecPath will === the agent name IF it CANNOT be resolved.\n npmExecPath === NPM &&\n !state.warnedPnpmWorkspaceRequiresNpm\n ) {\n state.warnedPnpmWorkspaceRequiresNpm = true\n logger?.warn(\n cmdPrefixMessage(\n CMD_NAME,\n `${agent} workspace support requires \\`npm ls\\`, falling back to \\`${agent} list\\``\n )\n )\n }\n\n const overridesDataObjects = [] as GetOverridesResult[]\n if (isWorkspace || pkgEnvDetails.editablePkgJson.content['private']) {\n overridesDataObjects.push(overridesDataByAgent.get(agent)!(pkgEnvDetails))\n } else {\n overridesDataObjects.push(\n overridesDataByAgent.get(NPM)!(pkgEnvDetails),\n overridesDataByAgent.get(YARN_CLASSIC)!(pkgEnvDetails)\n )\n }\n\n spinner?.setText(\n `Adding overrides${workspaceName ? ` to ${workspaceName}` : ''}...`\n )\n\n const depAliasMap = new Map<string, string>()\n const depEntries = getDependencyEntries(pkgEnvDetails)\n\n const manifestEntries = manifestNpmOverrides.filter(({ 1: data }) =>\n semver.satisfies(\n // Roughly check Node range as semver.coerce will strip leading\n // v's, carets (^), comparators (<,<=,>,>=,=), and tildes (~).\n semver.coerce(data.engines.node)!,\n pkgEnvDetails.pkgRequirements.node\n )\n )\n\n // Chunk package names to process them in parallel 3 at a time.\n await pEach(manifestEntries, 3, async ({ 1: data }) => {\n const { name: sockRegPkgName, package: origPkgName, version } = data\n const major = semver.major(version)\n const sockOverridePrefix = `${NPM}:${sockRegPkgName}@`\n const sockOverrideSpec = `${sockOverridePrefix}${pin ? version : `^${major}`}`\n for (const { 1: depObj } of depEntries) {\n const sockSpec = hasOwn(depObj, sockRegPkgName)\n ? depObj[sockRegPkgName]\n : undefined\n if (sockSpec) {\n depAliasMap.set(sockRegPkgName, sockSpec)\n }\n const origSpec = hasOwn(depObj, origPkgName)\n ? depObj[origPkgName]\n : undefined\n if (origSpec) {\n let thisSpec = origSpec\n // Add package aliases for direct dependencies to avoid npm EOVERRIDE\n // errors...\n // https://docs.npmjs.com/cli/v8/using-npm/package-spec#aliases\n if (\n // ...if the spec doesn't start with a valid Socket override.\n !(\n thisSpec.startsWith(sockOverridePrefix) &&\n // Check the validity of the spec by passing it through npa and\n // seeing if it will coerce to a version.\n semver.coerce(npa(thisSpec).rawSpec)?.version\n )\n ) {\n thisSpec = sockOverrideSpec\n depObj[origPkgName] = thisSpec\n state.added.add(sockRegPkgName)\n if (workspaceName) {\n state.addedInWorkspaces.add(workspaceName)\n }\n }\n depAliasMap.set(origPkgName, thisSpec)\n }\n }\n if (isWorkspaceRoot) {\n // The AgentDepsIncludesFn and AgentLockIncludesFn types overlap in their\n // first two parameters. AgentLockIncludesFn accepts an optional third\n // parameter which AgentDepsIncludesFn will ignore so we cast thingScanner\n // as an AgentLockIncludesFn type.\n const thingScanner = (\n isLockScanned\n ? lockfileIncludesByAgent.get(agent)\n : depsIncludesByAgent.get(agent)\n ) as AgentLockIncludesFn\n const thingToScan = isLockScanned\n ? lockSrc\n : await lsByAgent.get(agent)!(pkgEnvDetails, pkgPath, { npmExecPath })\n // Chunk package names to process them in parallel 3 at a time.\n await pEach(overridesDataObjects, 3, async ({ overrides, type }) => {\n const overrideExists = hasOwn(overrides, origPkgName)\n if (\n overrideExists ||\n thingScanner(thingToScan, origPkgName, lockName)\n ) {\n const oldSpec = overrideExists ? overrides[origPkgName]! : undefined\n const origDepAlias = depAliasMap.get(origPkgName)\n const sockRegDepAlias = depAliasMap.get(sockRegPkgName)\n const depAlias = sockRegDepAlias ?? origDepAlias\n let newSpec = sockOverrideSpec\n if (type === NPM && depAlias) {\n // With npm one may not set an override for a package that one directly\n // depends on unless both the dependency and the override itself share\n // the exact same spec. To make this limitation easier to deal with,\n // overrides may also be defined as a reference to a spec for a direct\n // dependency by prefixing the name of the package to match the version\n // of with a $.\n // https://docs.npmjs.com/cli/v8/configuring-npm/package-json#overrides\n newSpec = `$${sockRegDepAlias ? sockRegPkgName : origPkgName}`\n } else if (typeof oldSpec === 'string') {\n const thisSpec = oldSpec.startsWith('$')\n ? depAlias || newSpec\n : oldSpec || newSpec\n if (thisSpec.startsWith(sockOverridePrefix)) {\n if (\n pin &&\n semver.major(\n // Check the validity of the spec by passing it through npa\n // and seeing if it will coerce to a version. semver.coerce\n // will strip leading v's, carets (^), comparators (<,<=,>,>=,=),\n // and tildes (~). If not coerced to a valid version then\n // default to the manifest entry version.\n semver.coerce(npa(thisSpec).rawSpec)?.version ?? version\n ) !== major\n ) {\n const otherVersion = (await fetchPackageManifest(thisSpec))\n ?.version\n if (otherVersion && otherVersion !== version) {\n newSpec = `${sockOverridePrefix}${pin ? otherVersion : `^${semver.major(otherVersion)}`}`\n }\n }\n } else {\n newSpec = oldSpec\n }\n }\n if (newSpec !== oldSpec) {\n overrides[origPkgName] = newSpec\n const addedOrUpdated = overrideExists ? 'updated' : 'added'\n state[addedOrUpdated].add(sockRegPkgName)\n }\n }\n })\n }\n })\n\n if (isWorkspace) {\n // Chunk package names to process them in parallel 3 at a time.\n await pEach(state.workspacePkgJsonPaths, 3, async workspacePkgJsonPath => {\n const otherState = await addOverrides(\n pkgEnvDetails,\n path.dirname(workspacePkgJsonPath),\n {\n logger,\n pin,\n prod,\n spinner,\n state\n }\n )\n for (const key of [\n 'added',\n 'addedInWorkspaces',\n 'updated',\n 'updatedInWorkspaces'\n ] satisfies\n // Here we're just telling TS that we're looping over key names\n // of the type and that they're all Set<string> props. This allows\n // us to do the SetA.add(setB.get) pump type-safe without casts.\n Array<\n keyof Pick<\n AddOverridesState,\n 'added' | 'addedInWorkspaces' | 'updated' | 'updatedInWorkspaces'\n >\n >) {\n for (const value of otherState[key]) {\n state[key].add(value)\n }\n }\n })\n }\n\n if (state.added.size > 0 || state.updated.size > 0) {\n pkgEnvDetails.editablePkgJson.update(\n Object.fromEntries(depEntries) as PackageJson\n )\n for (const { overrides, type } of overridesDataObjects) {\n updateManifestByAgent.get(type)!(pkgEnvDetails, toSortedObject(overrides))\n }\n await pkgEnvDetails.editablePkgJson.save()\n }\n\n return state\n}\n","import { Spinner } from '@socketsecurity/registry/lib/spinner'\n\nimport constants from '../../constants'\nimport { runAgentInstall } from '../../utils/agent'\nimport { cmdPrefixMessage } from '../../utils/cmd'\n\nimport type { EnvDetails } from '../../utils/package-environment'\nimport type { Logger } from '@socketsecurity/registry/lib/logger'\n\nconst { NPM_BUGGY_OVERRIDES_PATCHED_VERSION } = constants\n\nexport type UpdateLockfileOptions = {\n cmdName?: string | undefined\n logger?: Logger | undefined\n spinner?: Spinner | undefined\n}\n\nexport async function updateLockfile(\n pkgEnvDetails: EnvDetails,\n options: UpdateLockfileOptions\n) {\n const {\n cmdName = '',\n logger,\n spinner\n } = {\n __proto__: null,\n ...options\n } as UpdateLockfileOptions\n const isSpinning = !!spinner?.['isSpinning']\n if (!isSpinning) {\n spinner?.start()\n }\n spinner?.setText(`Updating ${pkgEnvDetails.lockName}...`)\n try {\n await runAgentInstall(pkgEnvDetails, { spinner })\n if (pkgEnvDetails.features.npmBuggyOverrides) {\n logger?.log(\n `💡 Re-run ${cmdName ? `${cmdName} ` : ''}whenever ${pkgEnvDetails.lockName} changes.\\n This can be skipped for ${pkgEnvDetails.agent} >=${NPM_BUGGY_OVERRIDES_PATCHED_VERSION}.`\n )\n }\n } catch (e) {\n spinner?.stop()\n logger?.fail(\n cmdPrefixMessage(\n cmdName,\n `${pkgEnvDetails.agent} install failed to update ${pkgEnvDetails.lockName}`\n )\n )\n logger?.error(e)\n }\n if (isSpinning) {\n spinner?.start()\n } else {\n spinner?.stop()\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\nimport { pluralize } from '@socketsecurity/registry/lib/words'\n\nimport { addOverrides } from './add-overrides'\nimport { CMD_NAME } from './shared'\nimport { updateLockfile } from './update-lockfile'\nimport constants from '../../constants'\nimport { detectAndValidatePackageEnvironment } from '../../utils/package-environment'\n\nfunction createActionMessage(\n verb: string,\n overrideCount: number,\n workspaceCount: number\n): string {\n return `${verb} ${overrideCount} Socket.dev optimized ${pluralize('override', overrideCount)}${workspaceCount ? ` in ${workspaceCount} ${pluralize('workspace', workspaceCount)}` : ''}`\n}\n\nexport async function applyOptimization(\n cwd: string,\n pin: boolean,\n prod: boolean\n) {\n const pkgEnvDetails = await detectAndValidatePackageEnvironment(cwd, {\n cmdName: CMD_NAME,\n logger,\n prod\n })\n if (!pkgEnvDetails) {\n return\n }\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Socket optimizing...')\n\n const state = await addOverrides(pkgEnvDetails, pkgEnvDetails.pkgPath, {\n logger,\n pin,\n prod,\n spinner\n })\n\n const addedCount = state.added.size\n const updatedCount = state.updated.size\n const pkgJsonChanged = addedCount > 0 || updatedCount > 0\n\n if (pkgJsonChanged || pkgEnvDetails.features.npmBuggyOverrides) {\n await updateLockfile(pkgEnvDetails, { cmdName: CMD_NAME, logger, spinner })\n }\n\n spinner.stop()\n\n if (pkgJsonChanged) {\n if (updatedCount > 0) {\n logger?.log(\n `${createActionMessage('Updated', updatedCount, state.updatedInWorkspaces.size)}${addedCount ? '.' : '🚀'}`\n )\n }\n if (addedCount > 0) {\n logger?.log(\n `${createActionMessage('Added', addedCount, state.addedInWorkspaces.size)} 🚀`\n )\n }\n } else {\n logger?.log('Congratulations! Already Socket.dev optimized 🎉')\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { applyOptimization } from './apply-optimization'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'optimize',\n description: 'Optimize dependencies with @socketregistry overrides',\n hidden: false,\n flags: {\n ...commonFlags,\n pin: {\n type: 'boolean',\n default: false,\n description: 'Pin overrides to their latest version'\n },\n prod: {\n type: 'boolean',\n default: false,\n description: 'Only add overrides for production dependencies'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command}\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command}\n $ ${command} --pin\n `\n}\n\nexport const cmdOptimize = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const cwd = process.cwd()\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await applyOptimization(\n cwd,\n Boolean(cli.flags['pin']),\n Boolean(cli.flags['prod'])\n )\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchOrganization(): Promise<\n SocketSdkReturnType<'getOrganizations'>['data'] | undefined\n> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching organization list...')\n\n const result = await handleApiCall(\n sockSdk.getOrganizations(),\n 'looking up organizations'\n )\n\n spinner.successAndStop('Received organization list response.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getOrganizations', result)\n }\n\n return result.data\n}\n","import colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { getLastFiveOfApiToken } from '../../utils/api'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputOrganizationList(\n data: SocketSdkReturnType<'getOrganizations'>['data'],\n outputKind: 'text' | 'json' | 'markdown' = 'text'\n): Promise<void> {\n const organizations = Object.values(data.organizations)\n const apiToken = getDefaultToken()\n const lastFiveOfApiToken = getLastFiveOfApiToken(apiToken ?? '?????')\n\n switch (outputKind) {\n case 'json': {\n logger.log(\n JSON.stringify(\n organizations.map(o => ({\n name: o.name,\n id: o.id,\n plan: o.plan\n })),\n null,\n 2\n )\n )\n return\n }\n case 'markdown': {\n // | Syntax | Description |\n // | ----------- | ----------- |\n // | Header | Title |\n // | Paragraph | Text |\n let mw1 = 4\n let mw2 = 2\n let mw3 = 4\n for (const o of organizations) {\n mw1 = Math.max(mw1, o.name?.length ?? 0)\n mw2 = Math.max(mw2, o.id.length)\n mw3 = Math.max(mw3, o.plan.length)\n }\n logger.log('# Organizations\\n')\n logger.log(\n `List of organizations associated with your API key, ending with: ${colors.italic(lastFiveOfApiToken)}\\n`\n )\n logger.log(\n `| Name${' '.repeat(mw1 - 4)} | ID${' '.repeat(mw2 - 2)} | Plan${' '.repeat(mw3 - 4)} |`\n )\n logger.log(\n `| ${'-'.repeat(mw1)} | ${'-'.repeat(mw2)} | ${'-'.repeat(mw3)} |`\n )\n for (const o of organizations) {\n logger.log(\n `| ${(o.name || '').padEnd(mw1, ' ')} | ${(o.id || '').padEnd(mw2, ' ')} | ${(o.plan || '').padEnd(mw3, ' ')} |`\n )\n }\n logger.log(\n `| ${'-'.repeat(mw1)} | ${'-'.repeat(mw2)} | ${'-'.repeat(mw3)} |`\n )\n return\n }\n default: {\n logger.log(\n `List of organizations associated with your API key, ending with: ${colors.italic(lastFiveOfApiToken)}\\n`\n )\n // Just dump\n for (const o of organizations) {\n logger.log(\n `- Name: ${colors.bold(o.name ?? 'undefined')}, ID: ${colors.bold(o.id)}, Plan: ${colors.bold(o.plan)}`\n )\n }\n }\n }\n}\n","import { fetchOrganization } from './fetch-organization-list'\nimport { outputOrganizationList } from './output-organization-list'\n\nexport async function handleOrganizationList(\n outputKind: 'text' | 'json' | 'markdown' = 'text'\n): Promise<void> {\n const data = await fetchOrganization()\n if (!data) {\n return\n }\n\n await outputOrganizationList(data, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleOrganizationList } from './handle-organization-list'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'list',\n description: 'List organizations associated with the API key used',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, _config) => `\n Usage\n $ ${command}\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: none (does need a token)\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n `\n}\n\nexport const cmdOrganizationList = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleOrganizationList(json ? 'json' : markdown ? 'markdown' : 'text')\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchLicensePolicy(\n orgSlug: string\n): Promise<SocketSdkReturnType<'getOrgLicensePolicy'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching organization license policy...')\n\n const result = await handleApiCall(\n sockSdk.getOrgLicensePolicy(orgSlug),\n 'looking up organization quota'\n )\n\n spinner.successAndStop('Received organization license policy response.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getOrgLicensePolicy', result)\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { mdTableOfPairs } from '../../utils/markdown'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputLicensePolicy(\n data: SocketSdkReturnType<'getOrgLicensePolicy'>['data'],\n outputKind: 'text' | 'json' | 'markdown'\n): Promise<void> {\n if (outputKind === 'json') {\n let json\n try {\n json = JSON.stringify(data, null, 2)\n } catch {\n console.error(\n 'Failed to convert the server response to json, try running the same command without --json'\n )\n return\n }\n\n logger.log(json)\n logger.log('')\n return\n }\n\n logger.error('Use --json to get the full result')\n logger.log('# License policy')\n logger.log('')\n logger.log('This is the license policy for your organization:')\n logger.log('')\n const rules = data.license_policy!\n const entries = rules ? Object.entries(rules) : []\n const mapped: Array<[string, string]> = entries.map(\n ([key, value]) => [key, value.allowed ? ' yes' : ' no'] as const\n )\n mapped.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n logger.log(mdTableOfPairs(mapped, ['License Name', 'Allowed']))\n logger.log('')\n}\n","import { fetchLicensePolicy } from './fetch-license-policy'\nimport { outputLicensePolicy } from './output-license-policy'\n\nexport async function handleLicensePolicy(\n orgSlug: string,\n outputKind: 'text' | 'json' | 'markdown'\n): Promise<void> {\n const data = await fetchLicensePolicy(orgSlug)\n if (!data) {\n return\n }\n\n await outputLicensePolicy(data, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleLicensePolicy } from './handle-license-policy'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\n// TODO: secret toplevel alias `socket license policy`?\nconst config: CliCommandConfig = {\n commandName: 'license',\n description: 'Retrieve the license policy of an organization',\n hidden: true,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, _config) => `\n Usage\n $ ${command} <org slug>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: license-policy:read\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Your API token will need the \\`license-policy:read\\` permission otherwise\n the request will fail with an authentication error.\n\n Examples\n $ ${command} mycorp\n $ ${command} mycorp --json\n `\n}\n\nexport const cmdOrganizationPolicyLicense = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const json = Boolean(cli.flags['json'])\n const markdown = Boolean(cli.flags['markdown'])\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !!orgSlug,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleLicensePolicy(\n orgSlug,\n json ? 'json' : markdown ? 'markdown' : 'text'\n )\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchSecurityPolicy(\n orgSlug: string\n): Promise<SocketSdkReturnType<'getOrgSecurityPolicy'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching organization security policy...')\n\n const result = await handleApiCall(\n sockSdk.getOrgSecurityPolicy(orgSlug),\n 'looking up organization quota'\n )\n\n spinner.successAndStop('Received organization security policy response.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getOrgSecurityPolicy', result)\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { mdTableOfPairs } from '../../utils/markdown'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputSecurityPolicy(\n data: SocketSdkReturnType<'getOrgSecurityPolicy'>['data'],\n outputKind: 'text' | 'json' | 'markdown'\n): Promise<void> {\n if (outputKind === 'json') {\n let json\n try {\n json = JSON.stringify(data, null, 2)\n } catch {\n console.error(\n 'Failed to convert the server response to json, try running the same command without --json'\n )\n return\n }\n\n logger.log(json)\n logger.log('')\n return\n }\n\n logger.log('# Security policy')\n logger.log('')\n logger.log(\n `The default security policy setting is: \"${data.securityPolicyDefault}\"`\n )\n logger.log('')\n logger.log(\n 'These are the security policies per setting for your organization:'\n )\n logger.log('')\n const rules = data.securityPolicyRules\n const entries: Array<\n [string, { action: 'defer' | 'error' | 'warn' | 'monitor' | 'ignore' }]\n > = rules ? Object.entries(rules) : []\n const mapped: Array<[string, string]> = entries.map(([key, value]) => [\n key,\n value.action\n ])\n mapped.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n logger.log(mdTableOfPairs(mapped, ['name', 'action']))\n logger.log('')\n}\n","import { fetchSecurityPolicy } from './fetch-security-policy'\nimport { outputSecurityPolicy } from './output-security-policy'\n\nexport async function handleSecurityPolicy(\n orgSlug: string,\n outputKind: 'text' | 'json' | 'markdown'\n): Promise<void> {\n const data = await fetchSecurityPolicy(orgSlug)\n if (!data) {\n return\n }\n\n await outputSecurityPolicy(data, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleSecurityPolicy } from './handle-security-policy'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\n// TODO: secret toplevel alias `socket security policy`?\nconst config: CliCommandConfig = {\n commandName: 'security',\n description: 'Retrieve the security policy of an organization',\n hidden: true,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, _config) => `\n Usage\n $ ${command} <org slug>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: security-policy:read\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Your API token will need the \\`security-policy:read\\` permission otherwise\n the request will fail with an authentication error.\n\n Examples\n $ ${command} mycorp\n $ ${command} mycorp --json\n `\n}\n\nexport const cmdOrganizationPolicyPolicy = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const json = Boolean(cli.flags['json'])\n const markdown = Boolean(cli.flags['markdown'])\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !!orgSlug,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleSecurityPolicy(\n orgSlug,\n json ? 'json' : markdown ? 'markdown' : 'text'\n )\n}\n","import { cmdOrganizationPolicyLicense } from './cmd-organization-policy-license'\nimport { cmdOrganizationPolicyPolicy } from './cmd-organization-policy-security'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\n\nimport type { CliSubcommand } from '../../utils/meow-with-subcommands'\n\nconst description = 'Organization policy details'\n\nexport const cmdOrganizationPolicy: CliSubcommand = {\n description,\n // Hidden because it was broken all this time (nobody could be using it)\n // and we're not sure if it's useful to anyone in its current state.\n // Until we do, we'll hide this to keep the help tidier.\n // And later, we may simply move this under `scan`, anyways.\n hidden: true,\n async run(argv, importMeta, { parentName }) {\n await meowWithSubcommands(\n {\n security: cmdOrganizationPolicyPolicy,\n license: cmdOrganizationPolicyLicense\n },\n {\n argv,\n description,\n defaultSub: 'list', // Backwards compat\n importMeta,\n name: parentName + ' policy'\n }\n )\n }\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchQuota(): Promise<\n SocketSdkReturnType<'getQuota'>['data'] | undefined\n> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching organization quota...')\n\n const result = await handleApiCall(\n sockSdk.getQuota(),\n 'looking up organization quota'\n )\n\n spinner.successAndStop('Received organization quota response.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getQuota', result)\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputQuota(\n data: SocketSdkReturnType<'getQuota'>['data'],\n outputKind: 'text' | 'json' | 'markdown' = 'text'\n): Promise<void> {\n if (outputKind === 'json') {\n let json\n try {\n json = JSON.stringify(data, null, 2)\n } catch {\n console.error(\n 'Failed to convert the server response to json, try running the same command without --json'\n )\n return\n }\n\n logger.log(json)\n logger.log('')\n return\n }\n\n if (outputKind === 'markdown') {\n logger.log('# Quota')\n logger.log('')\n logger.log(`Quota left on the current API token: ${data.quota}`)\n logger.log('')\n return\n }\n\n logger.log(`Quota left on the current API token: ${data.quota}`)\n logger.log('')\n}\n","import { fetchQuota } from './fetch-quota'\nimport { outputQuota } from './output-quota'\n\nexport async function handleQuota(\n outputKind: 'text' | 'json' | 'markdown' = 'text'\n): Promise<void> {\n const data = await fetchQuota()\n if (!data) {\n return\n }\n\n await outputQuota(data, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleQuota } from './handle-quota'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'quota',\n description: 'List organizations associated with the API key used',\n hidden: true,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, _config) => `\n Usage\n $ ${command}\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n `\n}\n\nexport const cmdOrganizationQuota = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const json = Boolean(cli.flags['json'])\n const markdown = Boolean(cli.flags['markdown'])\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleQuota(json ? 'json' : markdown ? 'markdown' : 'text')\n}\n","import { cmdOrganizationList } from './cmd-organization-list'\nimport { cmdOrganizationPolicy } from './cmd-organization-policy'\nimport { cmdOrganizationQuota } from './cmd-organization-quota'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\n\nimport type { CliSubcommand } from '../../utils/meow-with-subcommands'\n\nconst description = 'Account details'\n\nexport const cmdOrganization: CliSubcommand = {\n description,\n // Hidden because it was broken all this time (nobody could be using it)\n // and we're not sure if it's useful to anyone in its current state.\n // Until we do, we'll hide this to keep the help tidier.\n // And later, we may simply move this under `scan`, anyways.\n hidden: true,\n async run(argv, importMeta, { parentName }) {\n await meowWithSubcommands(\n {\n list: cmdOrganizationList,\n quota: cmdOrganizationQuota,\n policy: cmdOrganizationPolicy\n },\n {\n argv,\n description,\n defaultSub: 'list', // Backwards compat\n importMeta,\n name: parentName + ' organization'\n }\n )\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { handleApiCall, handleApiError, queryApi } from '../../utils/api'\nimport { AuthError } from '../../utils/errors'\nimport { failMsgWithBadge } from '../../utils/fail-msg-with-badge'\nimport { getDefaultToken } from '../../utils/sdk'\n\nconst { SOCKET_CLI_ISSUES_URL } = constants\n\nexport async function fetchPurlDeepScore(purl: string) {\n logger.info(`Requesting deep score data for this purl: ${purl}`)\n\n const apiToken = getDefaultToken()\n if (!apiToken) {\n throw new AuthError(\n 'User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.'\n )\n }\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Getting deep package score...')\n\n let result\n try {\n result = await queryApi(`purl/score/${encodeURIComponent(purl)}`, apiToken)\n spinner.successAndStop('Received deep package score response.')\n } catch (e) {\n spinner.failAndStop('The request was unsuccessful.')\n const msg = (e as undefined | { message: string })?.message\n if (msg) {\n logger.fail(msg)\n logger.log(\n 'Please report this if the error persists or use the cli version that includes error reporting to automate that'\n )\n } else {\n logger.log(\n 'An error happened but no reason was given. If this persists please let us know about it and what you were trying to achieve. Thank you.'\n )\n }\n return\n }\n\n if (!result.ok) {\n const err = await handleApiError(result.status)\n logger.fail(failMsgWithBadge(result.statusText, err))\n process.exitCode = 1\n return\n }\n\n const data = await handleApiCall(await result.text(), 'Reading text')\n\n try {\n return JSON.parse(data)\n } catch (e) {\n throw new Error(\n `Unable to parse JSON response from the Socket API.\\nPlease report to ${SOCKET_CLI_ISSUES_URL}`\n )\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { mdTable } from '../../utils/markdown'\n\nexport async function outputPurlScore(\n purl: string,\n data: unknown,\n outputKind: 'json' | 'markdown' | 'text'\n) {\n if (outputKind === 'json') {\n let json\n try {\n json = JSON.stringify(data, null, 2)\n } catch {\n console.error(\n 'Failed to convert the server response to JSON... Please try again or reach out to customer support.'\n )\n process.exitCode = 1\n return\n }\n\n logger.error(`Score report for \"${purl}\":\\n`)\n logger.log(json)\n logger.log('')\n return\n }\n\n if (outputKind === 'markdown') {\n const {\n purl: requestedPurl,\n self: {\n alerts: selfAlerts,\n capabilities: selfCaps,\n purl,\n score: selfScore\n },\n transitively: {\n alerts,\n capabilities,\n dependencyCount,\n func,\n lowest,\n score\n }\n } = data as {\n purl: string\n self: {\n purl: string\n score: {\n license: number\n maintenance: number\n overall: number\n quality: number\n supplyChain: number\n vulnerability: number\n }\n capabilities: string[]\n alerts: Array<{\n name: string\n severity: string\n category: string\n example: string\n }>\n }\n transitively: {\n dependencyCount: number\n func: string\n score: {\n license: number\n maintenance: number\n overall: number\n quality: number\n supplyChain: number\n vulnerability: number\n }\n lowest: {\n license: string\n maintenance: string\n overall: string\n quality: string\n supplyChain: string\n vulnerability: string\n }\n capabilities: string[]\n alerts: Array<{\n name: string\n severity: string\n category: string\n example: string\n }>\n }\n }\n\n logger.error(`Score report for \"${requestedPurl}\" (\"${purl}\"):\\n`)\n logger.log('# Complete Package Score')\n logger.log('')\n if (dependencyCount) {\n logger.log(\n `This is a Socket report for the package *\"${purl}\"* and its *${dependencyCount}* direct/transitive dependencies.`\n )\n } else {\n logger.log(\n `This is a Socket report for the package *\"${purl}\"*. It has *no dependencies*.`\n )\n }\n logger.log('')\n if (dependencyCount) {\n logger.log(\n `It will show you the shallow score for just the package itself and a deep score for all the transitives combined. Additionally you can see which capabilities were found and the top alerts as well as a package that was responsible for it.`\n )\n } else {\n logger.log(\n `It will show you the shallow score for the package itself, which capabilities were found, and its top alerts.`\n )\n logger.log('')\n logger.log(\n 'Since it has no dependencies, the shallow score is also the deep score.'\n )\n }\n logger.log('')\n if (dependencyCount) {\n // This doesn't make much sense if there are no dependencies. Better to omit it.\n logger.log(\n 'The report should give you a good insight into the status of this package.'\n )\n logger.log('')\n logger.log('## Package itself')\n logger.log('')\n logger.log(\n 'Here are results for the package itself (excluding data from dependencies).'\n )\n } else {\n logger.log('## Report')\n logger.log('')\n logger.log(\n 'The report should give you a good insight into the status of this package.'\n )\n }\n logger.log('')\n logger.log('### Shallow Score')\n logger.log('')\n logger.log('This score is just for the package itself:')\n logger.log('')\n logger.log('- Overall: ' + selfScore.overall)\n logger.log('- Maintenance: ' + selfScore.maintenance)\n logger.log('- Quality: ' + selfScore.quality)\n logger.log('- Supply Chain: ' + selfScore.supplyChain)\n logger.log('- Vulnerability: ' + selfScore.vulnerability)\n logger.log('- License: ' + selfScore.license)\n logger.log('')\n logger.log('### Capabilities')\n logger.log('')\n if (selfCaps.length) {\n logger.log('These are the capabilities detected in the package itself:')\n logger.log('')\n selfCaps.forEach(cap => {\n logger.log(`- ${cap}`)\n })\n } else {\n logger.log('No capabilities were found in the package.')\n }\n logger.log('')\n logger.log('### Alerts for this package')\n logger.log('')\n if (selfAlerts.length) {\n if (dependencyCount) {\n logger.log('These are the alerts found for the package itself:')\n } else {\n logger.log('These are the alerts found for this package:')\n }\n logger.log('')\n logger.log(\n mdTable(selfAlerts, ['severity', 'name'], ['Severity', 'Alert Name'])\n )\n } else {\n logger.log('There are currently no alerts for this package.')\n }\n logger.log('')\n if (dependencyCount) {\n logger.log('## Transitive Package Results')\n logger.log('')\n logger.log(\n 'Here are results for the package and its direct/transitive dependencies.'\n )\n logger.log('')\n logger.log('### Deep Score')\n logger.log('')\n logger.log(\n 'This score represents the package and and its direct/transitive dependencies:'\n )\n logger.log(\n `The function used to calculate the values in aggregate is: *\"${func}\"*`\n )\n logger.log('')\n logger.log('- Overall: ' + score.overall)\n logger.log('- Maintenance: ' + score.maintenance)\n logger.log('- Quality: ' + score.quality)\n logger.log('- Supply Chain: ' + score.supplyChain)\n logger.log('- Vulnerability: ' + score.vulnerability)\n logger.log('- License: ' + score.license)\n logger.log('')\n logger.log('### Capabilities')\n logger.log('')\n logger.log(\n 'These are the packages with the lowest recorded score. If there is more than one with the lowest score, just one is shown here. This may help you figure out the source of low scores.'\n )\n logger.log('')\n logger.log('- Overall: ' + lowest.overall)\n logger.log('- Maintenance: ' + lowest.maintenance)\n logger.log('- Quality: ' + lowest.quality)\n logger.log('- Supply Chain: ' + lowest.supplyChain)\n logger.log('- Vulnerability: ' + lowest.vulnerability)\n logger.log('- License: ' + lowest.license)\n logger.log('')\n logger.log('### Capabilities')\n logger.log('')\n if (capabilities.length) {\n logger.log(\n 'These are the capabilities detected in at least one package:'\n )\n logger.log('')\n capabilities.forEach(cap => {\n logger.log(`- ${cap}`)\n })\n } else {\n logger.log(\n 'This package had no capabilities and neither did any of its direct/transitive dependencies.'\n )\n }\n logger.log('')\n logger.log('### Alerts')\n logger.log('')\n if (alerts.length) {\n logger.log('These are the alerts found:')\n logger.log('')\n\n logger.log(\n mdTable(\n alerts,\n ['severity', 'name', 'example'],\n ['Severity', 'Alert Name', 'Example package reporting it']\n )\n )\n } else {\n logger.log(\n 'This package had no alerts and neither did any of its direct/transitive dependencies'\n )\n }\n logger.log('')\n }\n return\n }\n\n logger.log(\n `Score report for \"${purl}\" (use --json for raw and --markdown for formatted reports):`\n )\n logger.log(data)\n logger.log('')\n}\n","import { fetchPurlDeepScore } from './fetch-purl-deep-score'\nimport { outputPurlScore } from './output-purl-score'\n\nexport async function handlePurlDeepScore(\n purl: string,\n outputKind: 'json' | 'markdown' | 'text'\n) {\n const data = await fetchPurlDeepScore(purl)\n if (!data) {\n return\n }\n\n await outputPurlScore(purl, data, outputKind)\n}\n","// Either an ecosystem was given or all args must be (namespaced) purls\n// The `pkg:` part is optional here. We'll scan for `eco/name@version`.\n// Not hardcoding the namespace since we don't know what the server accepts.\n// The ecosystem is considered as the first package if it is not an a-z string.\nexport function parsePackageSpecifiers(\n ecosystem: string,\n pkgs: string[]\n): { purls: string[]; valid: boolean } {\n let valid = true\n const purls = []\n if (!ecosystem) {\n valid = false\n } else if (/^[a-zA-Z]+$/.test(ecosystem)) {\n for (let i = 0; i < pkgs.length; ++i) {\n const pkg = pkgs[i] ?? ''\n if (!pkg) {\n valid = false\n break\n } else if (pkg.startsWith('pkg:')) {\n // keep\n purls.push(pkg)\n } else {\n purls.push('pkg:' + ecosystem + '/' + pkg)\n }\n }\n if (!purls.length) {\n valid = false\n }\n } else {\n // Assume ecosystem is a purl, too\n pkgs.unshift(ecosystem)\n\n for (let i = 0; i < pkgs.length; ++i) {\n const pkg = pkgs[i] ?? ''\n if (!/^(?:pkg:)?[a-zA-Z]+\\/./.test(pkg)) {\n // At least one purl did not start with `pkg:eco/x` or `eco/x`\n valid = false\n break\n } else if (pkg.startsWith('pkg:')) {\n purls.push(pkg)\n } else {\n purls.push('pkg:' + pkg)\n }\n }\n\n if (!purls.length) {\n valid = false\n }\n }\n\n return { purls, valid }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handlePurlDeepScore } from './handle-purl-deep-score'\nimport { parsePackageSpecifiers } from './parse-package-specifiers'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'score',\n description:\n '[beta] Look up score for one package which reflects all of its transitive dependencies as well',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <<ecosystem> <name> | <purl>>\n\n API Token Requirements\n - Quota: 100 units\n - Permissions: packages:list\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Show deep scoring details for one package. The score will reflect the package\n itself, any of its dependencies, and any of its transitive dependencies.\n\n When you want to know whether to trust a package, this is the command to run.\n\n See also the \\`socket package shallow\\` command, which returns the shallow\n score for any number of packages. That will not reflect the dependency scores.\n\n Only a few ecosystems are supported like npm, golang, and maven.\n\n A \"purl\" is a standard package name formatting: \\`pkg:eco/name@version\\`\n This command will automatically prepend \"pkg:\" when not present.\n\n The version is optional but when given should be a direct match.\n\n Examples\n $ ${command} npm babel-cli\n $ ${command} npm babel-cli@1.9.1\n $ ${command} npm/babel-cli@1.9.1\n $ ${command} pkg:npm/babel-cli@1.9.1\n `\n}\n\nexport const cmdPackageScore = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const [ecosystem = '', purl] = cli.input\n const apiToken = getDefaultToken()\n\n const { purls, valid } = parsePackageSpecifiers(ecosystem, purl ? [purl] : [])\n\n const wasBadInput = handleBadInput(\n {\n test: valid,\n message: 'First parameter must be an ecosystem or the whole purl',\n pass: 'ok',\n fail: 'bad'\n },\n {\n test: purls.length === 1,\n message: 'Expecting at least one package',\n pass: 'ok',\n fail: purls.length === 0 ? 'missing' : 'too many'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handlePurlDeepScore(\n purls[0] || '',\n json ? 'json' : markdown ? 'markdown' : 'text'\n )\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { getPublicToken, setupSdk } from '../../utils/sdk'\n\nimport type {\n SocketSdkResultType,\n SocketSdkReturnType\n} from '@socketsecurity/sdk'\n\nexport async function fetchPurlsShallowScore(\n purls: string[]\n): Promise<SocketSdkReturnType<'batchPackageFetch'> | undefined> {\n logger.info(\n `Requesting shallow score data for ${purls.length} package urls (purl): ${purls.join(', ')}`\n )\n\n const sockSdk = await setupSdk(getPublicToken())\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start(`Requesting data ...`)\n\n const result: Awaited<SocketSdkResultType<'batchPackageFetch'>> =\n await handleApiCall(\n sockSdk.batchPackageFetch(\n {\n alerts: 'true'\n },\n { components: purls.map(purl => ({ purl })) }\n ),\n 'looking up package'\n )\n\n spinner.successAndStop('Request completed')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('batchPackageFetch', result)\n }\n\n return result\n}\n","import { codeBlock } from 'common-tags'\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { components } from '@socketsecurity/sdk/types/api'\n\nexport function outputPurlsShallowScore(\n purls: string[],\n packageData: Array<components['schemas']['SocketArtifact']>,\n outputKind: 'json' | 'markdown' | 'text'\n): void {\n if (outputKind === 'json') {\n // In JSON simply return what the server responds with. Don't bother trying\n // to match the response with the requested packages/purls.\n logger.log(JSON.stringify(packageData, undefined, 2))\n return\n }\n\n // Make some effort to match the requested data with the response\n\n const set = new Set()\n packageData.forEach(data => {\n set.add('pkg:' + data.type + '/' + data.name + '@' + data.version)\n set.add('pkg:' + data.type + '/' + data.name)\n })\n const missing = purls.filter(purl => {\n if (set.has(purl)) {\n return false\n }\n if (purl.endsWith('@latest') && set.has(purl.slice(0, -'@latest'.length))) {\n return false\n }\n return true // not found\n })\n\n if (outputKind === 'markdown') {\n logger.log(codeBlock`\n # Shallow Package Report\n\n This report contains the response for requesting data on some package url(s).\n\n Please note: The listed scores are ONLY for the package itself. It does NOT\n reflect the scores of any dependencies, transitive or otherwise.\n\n ${missing.length ? `\\n## Missing response\\n\\nAt least one package had no response or the purl was not canonical:\\n\\n${missing.map(purl => '- ' + purl + '\\n').join('')}` : ''}\n\n ${packageData.map(data => '## ' + formatReportCard(data, false)).join('\\n\\n\\n')}\n `)\n return\n }\n\n logger.log('\\n' + colors.bold('Shallow Package Score') + '\\n')\n logger.log(\n 'Please note: The listed scores are ONLY for the package itself. It does NOT\\n' +\n ' reflect the scores of any dependencies, transitive or otherwise.'\n )\n\n if (missing.length) {\n logger.log(\n `\\nAt least one package had no response or the purl was not canonical:\\n${missing.map(purl => '\\n- ' + colors.bold(purl)).join('')}`\n )\n }\n\n packageData.forEach(data => {\n logger.log('\\n')\n logger.log(formatReportCard(data, true))\n })\n logger.log('')\n}\n\nfunction formatReportCard(\n data: components['schemas']['SocketArtifact'],\n color: boolean\n): string {\n const scoreResult = {\n 'Supply Chain Risk': Math.floor((data.score?.supplyChain ?? 0) * 100),\n Maintenance: Math.floor((data.score?.maintenance ?? 0) * 100),\n Quality: Math.floor((data.score?.quality ?? 0) * 100),\n Vulnerabilities: Math.floor((data.score?.vulnerability ?? 0) * 100),\n License: Math.floor((data.score?.license ?? 0) * 100)\n }\n const alertString = getAlertString(data.alerts, !color)\n const purl = 'pkg:' + data.type + '/' + data.name + '@' + data.version\n\n return [\n 'Package: ' + (color ? colors.bold(purl) : purl),\n '',\n ...Object.entries(scoreResult).map(\n score =>\n `- ${score[0]}:`.padEnd(20, ' ') +\n ` ${formatScore(score[1], !color, true)}`\n ),\n alertString\n ].join('\\n')\n}\n\nfunction formatScore(score: number, noColor = false, pad = false): string {\n const padded = String(score).padStart(pad ? 3 : 0, ' ')\n if (noColor) {\n return padded\n }\n if (score >= 80) {\n return colors.green(padded)\n }\n if (score >= 60) {\n return colors.yellow(padded)\n }\n return colors.red(padded)\n}\n\nfunction getAlertString(\n alerts: Array<components['schemas']['SocketAlert']> | undefined,\n noColor = false\n) {\n if (!alerts?.length) {\n return noColor ? `- Alerts: none!` : `- Alerts: ${colors.green('none')}!`\n }\n const bad = alerts\n .filter(alert => alert.severity !== 'low' && alert.severity !== 'middle')\n .sort((a, b) => (a.type < b.type ? -1 : a.type > b.type ? 1 : 0))\n const mid = alerts\n .filter(alert => alert.severity === 'middle')\n .sort((a, b) => (a.type < b.type ? -1 : a.type > b.type ? 1 : 0))\n const low = alerts\n .filter(alert => alert.severity === 'low')\n .sort((a, b) => (a.type < b.type ? -1 : a.type > b.type ? 1 : 0))\n\n // We need to create the no-color string regardless because the actual string\n // contains a bunch of invisible ANSI chars which would screw up length checks.\n const colorless = `- Alerts (${bad.length}/${mid.length.toString()}/${low.length}):`\n\n if (noColor) {\n return (\n colorless +\n ' '.repeat(Math.max(0, 20 - colorless.length)) +\n ' ' +\n [\n bad.map(alert => `[${alert.severity}] ` + alert.type).join(', '),\n mid.map(alert => `[${alert.severity}] ` + alert.type).join(', '),\n low.map(alert => `[${alert.severity}] ` + alert.type).join(', ')\n ]\n .filter(Boolean)\n .join(', ')\n )\n }\n return (\n `- Alerts (${colors.red(bad.length.toString())}/${colors.yellow(mid.length.toString())}/${low.length}):` +\n ' '.repeat(Math.max(0, 20 - colorless.length)) +\n ' ' +\n [\n bad\n .map(alert =>\n colors.red(colors.dim(`[${alert.severity}] `) + alert.type)\n )\n .join(', '),\n mid\n .map(alert =>\n colors.yellow(colors.dim(`[${alert.severity}] `) + alert.type)\n )\n .join(', '),\n low\n .map(alert => colors.dim(`[${alert.severity}] `) + alert.type)\n .join(', ')\n ]\n .filter(Boolean)\n .join(', ')\n )\n}\n","import { fetchPurlsShallowScore } from './fetch-purls-shallow-score'\nimport { outputPurlsShallowScore } from './output-purls-shallow-score'\n\nimport type { components } from '@socketsecurity/sdk/types/api'\n\nexport async function handlePurlsShallowScore({\n outputKind,\n purls\n}: {\n outputKind: 'json' | 'markdown' | 'text'\n purls: string[]\n}) {\n const packageData = await fetchPurlsShallowScore(purls)\n if (!packageData) {\n return\n }\n\n outputPurlsShallowScore(\n purls,\n packageData.data as Array<components['schemas']['SocketArtifact']>,\n outputKind\n )\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handlePurlsShallowScore } from './handle-purls-shallow-score'\nimport { parsePackageSpecifiers } from './parse-package-specifiers'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'shallow',\n description:\n '[beta] Look up info regarding one or more packages but not their transitives',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <<ecosystem> <name> [<name> ...] | <purl> [<purl> ...]>\n\n API Token Requirements\n - Quota: 100 units\n - Permissions: packages:list\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Show scoring details for one or more packages purely based on their own package.\n This means that any dependency scores are not reflected by the score. You can\n use the \\`socket package score <pkg>\\` command to get its full transitive score.\n\n Only a few ecosystems are supported like npm, golang, and maven.\n\n A \"purl\" is a standard package name formatting: \\`pkg:eco/name@version\\`\n This command will automatically prepend \"pkg:\" when not present.\n\n If the first arg is an ecosystem, remaining args that are not a purl are\n assumed to be scoped to that ecosystem.\n\n Examples\n $ ${command} npm webtorrent\n $ ${command} npm webtorrent@1.9.1\n $ ${command} npm/webtorrent@1.9.1\n $ ${command} pkg:npm/webtorrent@1.9.1\n $ ${command} maven webtorrent babel\n $ ${command} npm/webtorrent golang/babel\n $ ${command} npm npm/webtorrent@1.0.1 babel\n `\n}\n\nexport const cmdPackageShallow = {\n description: config.description,\n hidden: config.hidden,\n alias: {\n shallowScore: {\n description: config.description,\n hidden: true,\n argv: []\n }\n },\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const [ecosystem = '', ...pkgs] = cli.input\n\n const { purls, valid } = parsePackageSpecifiers(ecosystem, pkgs)\n\n const wasBadInput = handleBadInput(\n {\n test: valid,\n message:\n 'First parameter should be an ecosystem or all args must be purls',\n pass: 'ok',\n fail: 'bad'\n },\n {\n test: purls.length > 0,\n message: 'Expecting at least one package',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handlePurlsShallowScore({\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text',\n purls\n })\n}\n","import { cmdPackageScore } from './cmd-package-score'\nimport { cmdPackageShallow } from './cmd-package-shallow'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\n\nimport type { CliSubcommand } from '../../utils/meow-with-subcommands'\n\nconst description = 'Commands relating to looking up published packages'\n\nexport const cmdPackage: CliSubcommand = {\n description,\n hidden: false,\n async run(argv, importMeta, { parentName }) {\n await meowWithSubcommands(\n {\n score: cmdPackageScore,\n shallow: cmdPackageShallow\n },\n {\n aliases: {\n deep: {\n description,\n hidden: true,\n argv: ['score']\n }\n },\n argv,\n description,\n importMeta,\n name: parentName + ' package'\n }\n )\n }\n}\n","import process from 'node:process'\n\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport { getNpmBinPath } from '../../shadow/npm/paths'\n\nexport async function runRawNpm(\n argv: string[] | readonly string[]\n): Promise<void> {\n const spawnPromise = spawn(getNpmBinPath(), argv as string[], {\n stdio: 'inherit'\n })\n // See https://nodejs.org/api/all.html#all_child_process_event-exit.\n spawnPromise.process.on('exit', (code, signalName) => {\n if (signalName) {\n process.kill(process.pid, signalName)\n } else if (code !== null) {\n // eslint-disable-next-line n/no-process-exit\n process.exit(code)\n }\n })\n await spawnPromise\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { runRawNpm } from './run-raw-npm'\nimport constants from '../../constants'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT, NPM } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'raw-npm',\n description: `Temporarily disable the Socket ${NPM} wrapper`,\n hidden: false,\n flags: {},\n help: command => `\n Usage\n $ ${command} <command>\n\n Examples\n $ ${command} install\n `\n}\n\nexport const cmdRawNpm = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n allowUnknownFlags: true,\n argv,\n config,\n importMeta,\n parentName\n })\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await runRawNpm(argv)\n}\n","import process from 'node:process'\n\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport { getNpxBinPath } from '../../shadow/npm/paths'\n\nexport async function runRawNpx(\n argv: string[] | readonly string[]\n): Promise<void> {\n const spawnPromise = spawn(getNpxBinPath(), argv as string[], {\n stdio: 'inherit'\n })\n // See https://nodejs.org/api/all.html#all_child_process_event-exit.\n spawnPromise.process.on('exit', (code, signalName) => {\n if (signalName) {\n process.kill(process.pid, signalName)\n } else if (code !== null) {\n // eslint-disable-next-line n/no-process-exit\n process.exit(code)\n }\n })\n await spawnPromise\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { runRawNpx } from './run-raw-npx'\nimport constants from '../../constants'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT, NPX } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'raw-npx',\n description: `Temporarily disable the Socket ${NPX} wrapper`,\n hidden: false,\n flags: {},\n help: command => `\n Usage\n $ ${command} <command>\n\n Examples\n $ ${command} install\n `\n}\n\nexport const cmdRawNpx = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n allowUnknownFlags: true,\n argv,\n config,\n importMeta,\n parentName\n })\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await runRawNpx(argv)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { commonFlags, outputFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst config: CliCommandConfig = {\n commandName: 'create',\n description: '[Deprecated] Create a project report',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: () => `\n This command is deprecated in favor of \\`socket scan view\\`.\n It will be removed in the next major release of the CLI.\n `\n}\n\nexport const cmdReportCreate = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n logger.fail(\n 'This command has been sunset. Instead, please look at `socket scan create` to create scans and `socket scan report` to view a report of your scans.'\n )\n\n process.exitCode = 1\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { commonFlags, outputFlags } from '../../flags'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst config: CliCommandConfig = {\n commandName: 'view',\n description: '[Deprecated] View a project report',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: () => `\n This command is deprecated in favor of \\`socket scan view\\`.\n It will be removed in the next major release of the CLI.\n `\n}\n\nexport const cmdReportView = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n logger.fail(\n 'This command has been sunset. Instead, please look at `socket scan create` to create scans and `socket scan report` to view a report of your scans.'\n )\n\n process.exitCode = 1\n}\n","import { cmdReportCreate } from './cmd-report-create'\nimport { cmdReportView } from './cmd-report-view'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\n\nimport type { CliSubcommand } from '../../utils/meow-with-subcommands'\n\nconst description = '[Deprecated] Project report related commands'\n\nexport const cmdReport: CliSubcommand = {\n description,\n hidden: true, // Deprecated in favor of `scan`\n async run(argv, importMeta, { parentName }) {\n await meowWithSubcommands(\n {\n create: cmdReportCreate,\n view: cmdReportView\n },\n {\n argv,\n description,\n importMeta,\n name: parentName + ' report'\n }\n )\n }\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchCreateRepo({\n default_branch,\n description,\n homepage,\n orgSlug,\n repoName,\n visibility\n}: {\n orgSlug: string\n repoName: string\n description: string\n homepage: string\n default_branch: string\n visibility: string\n}): Promise<SocketSdkReturnType<'createOrgRepo'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Sending request ot create a repository...')\n\n const result = await handleApiCall(\n sockSdk.createOrgRepo(orgSlug, {\n name: repoName,\n description,\n homepage,\n default_branch,\n visibility\n }),\n 'creating repository'\n )\n\n spinner.successAndStop('Received response requesting to create a repository.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('createOrgRepo', result)\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\nexport async function outputCreateRepo(\n _data: SocketSdkReturnType<'createOrgRepo'>['data']\n): Promise<void> {\n logger.success('Repository created successfully')\n}\n","import { fetchCreateRepo } from './fetch-create-repo'\nimport { outputCreateRepo } from './output-create-repo'\n\nexport async function handleCreateRepo({\n default_branch,\n description,\n homepage,\n orgSlug,\n repoName,\n visibility\n}: {\n orgSlug: string\n repoName: string\n description: string\n homepage: string\n default_branch: string\n visibility: string\n}): Promise<void> {\n const data = await fetchCreateRepo({\n default_branch,\n description,\n homepage,\n orgSlug,\n repoName,\n visibility\n })\n if (!data) {\n return\n }\n\n await outputCreateRepo(data)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleCreateRepo } from './handle-create-repo'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'create',\n description: 'Create a repository in an organization',\n hidden: false,\n flags: {\n ...commonFlags,\n repoName: {\n type: 'string',\n shortFlag: 'n',\n default: '',\n description: 'Repository name'\n },\n repoDescription: {\n type: 'string',\n shortFlag: 'd',\n default: '',\n description: 'Repository description'\n },\n homepage: {\n type: 'string',\n shortFlag: 'h',\n default: '',\n description: 'Repository url'\n },\n defaultBranch: {\n type: 'string',\n shortFlag: 'b',\n default: 'main',\n description: 'Repository default branch'\n },\n visibility: {\n type: 'string',\n shortFlag: 'v',\n default: 'private',\n description: 'Repository visibility (Default Private)'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> --repo-name=<name>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: repo:create\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg --repoName=test-repo\n `\n}\n\nexport const cmdReposCreate = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const repoName = cli.flags['repoName']\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !!orgSlug,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n test: !!repoName,\n message: 'Repository name using --repoNam',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleCreateRepo({\n orgSlug,\n repoName: String(repoName),\n description: String(cli.flags['repoDescription'] || ''),\n homepage: String(cli.flags['homepage'] || ''),\n default_branch: String(cli.flags['defaultBranch'] || ''),\n visibility: String(cli.flags['visibility'] || 'private')\n })\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nexport async function handleDeleteRepo(\n orgSlug: string,\n repoName: string\n): Promise<void> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Deleting repository...')\n\n const result = await handleApiCall(\n sockSdk.deleteOrgRepo(orgSlug, repoName),\n 'deleting repository'\n )\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('deleteOrgRepo', result)\n }\n\n spinner.successAndStop('Repository deleted successfully')\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleDeleteRepo } from './handle-delete-repo'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'del',\n description: 'Delete a repository in an organization',\n hidden: false,\n flags: {\n ...commonFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> <repo slug>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: repo:delete\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg test-repo\n `\n}\n\nexport const cmdReposDel = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const repoName = (defaultOrgSlug ? cli.input[0] : cli.input[1]) || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !!orgSlug,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n test: !!repoName,\n message: 'Repository name argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleDeleteRepo(orgSlug, repoName)\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchListRepos({\n direction,\n orgSlug,\n page,\n per_page,\n sort\n}: {\n direction: string\n orgSlug: string\n page: number\n per_page: number\n sort: string\n}): Promise<SocketSdkReturnType<'getOrgRepoList'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching list of repositories...')\n\n const result = await handleApiCall(\n sockSdk.getOrgRepoList(orgSlug, {\n sort,\n direction,\n per_page: String(per_page),\n page: String(page)\n }),\n 'listing repositories'\n )\n\n spinner.successAndStop('Received response for repository list.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getOrgRepoList', result)\n }\n\n return result.data\n}\n","// @ts-ignore\nimport chalkTable from 'chalk-table'\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputListRepos(\n data: SocketSdkReturnType<'getOrgRepoList'>['data'],\n outputKind: 'json' | 'markdown' | 'print'\n): Promise<void> {\n if (outputKind === 'json') {\n const json = data.results.map(o => ({\n id: o.id,\n name: o.name,\n visibility: o.visibility,\n defaultBranch: o.default_branch,\n archived: o.archived\n }))\n logger.log(JSON.stringify(json, null, 2))\n return\n }\n\n const options = {\n columns: [\n { field: 'id', name: colors.magenta('ID') },\n { field: 'name', name: colors.magenta('Name') },\n { field: 'visibility', name: colors.magenta('Visibility') },\n { field: 'default_branch', name: colors.magenta('Default branch') },\n { field: 'archived', name: colors.magenta('Archived') }\n ]\n }\n\n logger.log(chalkTable(options, data.results))\n}\n","import { fetchListRepos } from './fetch-list-repos'\nimport { outputListRepos } from './output-list-repos'\n\nexport async function handleListRepos({\n direction,\n orgSlug,\n outputKind,\n page,\n per_page,\n sort\n}: {\n direction: string\n orgSlug: string\n outputKind: 'json' | 'markdown' | 'print'\n page: number\n per_page: number\n sort: string\n}): Promise<void> {\n const data = await fetchListRepos({\n direction,\n orgSlug,\n page,\n per_page,\n sort\n })\n if (!data) {\n return\n }\n\n await outputListRepos(data, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleListRepos } from './handle-list-repos'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'list',\n description: 'List repositories in an organization',\n hidden: false,\n flags: {\n ...commonFlags,\n sort: {\n type: 'string',\n shortFlag: 's',\n default: 'created_at',\n description: 'Sorting option'\n },\n direction: {\n type: 'string',\n default: 'desc',\n description: 'Direction option'\n },\n perPage: {\n type: 'number',\n shortFlag: 'pp',\n default: 30,\n description: 'Number of results per page'\n },\n page: {\n type: 'number',\n shortFlag: 'p',\n default: 1,\n description: 'Page number'\n },\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: repo:list\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg\n `\n}\n\nexport const cmdReposList = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !!orgSlug,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleListRepos({\n direction: cli.flags['direction'] === 'asc' ? 'asc' : 'desc',\n orgSlug,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'print',\n page: Number(cli.flags['page']) || 1,\n per_page: Number(cli.flags['perPage']) || 30,\n sort: String(cli.flags['sort'] || 'created_at')\n })\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchUpdateRepo({\n default_branch,\n description,\n homepage,\n orgSlug,\n repoName,\n visibility\n}: {\n orgSlug: string\n repoName: string\n description: string\n homepage: string\n default_branch: string\n visibility: string\n}): Promise<SocketSdkReturnType<'updateOrgRepo'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Sending request to update a repository...')\n\n const result = await handleApiCall(\n sockSdk.updateOrgRepo(orgSlug, repoName, {\n orgSlug,\n name: repoName,\n description,\n homepage,\n default_branch,\n visibility\n }),\n 'updating repository'\n )\n\n spinner.successAndStop('Received response trying to update a repository')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('updateOrgRepo', result)\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputUpdateRepo(\n _data: SocketSdkReturnType<'updateOrgRepo'>['data']\n): Promise<void> {\n logger.success('Repository updated successfully')\n}\n","import { fetchUpdateRepo } from './fetch-update-repo'\nimport { outputUpdateRepo } from './output-update-repo'\n\nexport async function handleUpdateRepo({\n default_branch,\n description,\n homepage,\n orgSlug,\n repoName,\n visibility\n}: {\n orgSlug: string\n repoName: string\n description: string\n homepage: string\n default_branch: string\n visibility: string\n}): Promise<void> {\n const data = await fetchUpdateRepo({\n default_branch,\n description,\n homepage,\n orgSlug,\n repoName,\n visibility\n })\n if (!data) {\n return\n }\n\n await outputUpdateRepo(data)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleUpdateRepo } from './handle-update-repo'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'update',\n description: 'Update a repository in an organization',\n hidden: false,\n flags: {\n ...commonFlags,\n repoName: {\n type: 'string',\n shortFlag: 'n',\n default: '',\n description: 'Repository name'\n },\n repoDescription: {\n type: 'string',\n shortFlag: 'd',\n default: '',\n description: 'Repository description'\n },\n homepage: {\n type: 'string',\n shortFlag: 'h',\n default: '',\n description: 'Repository url'\n },\n defaultBranch: {\n type: 'string',\n shortFlag: 'b',\n default: 'main',\n description: 'Repository default branch'\n },\n visibility: {\n type: 'string',\n shortFlag: 'v',\n default: 'private',\n description: 'Repository visibility (Default Private)'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> --repo-name=<name>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: repo:update\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg\n `\n}\n\nexport const cmdReposUpdate = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const repoName = cli.flags['repoName']\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !!orgSlug,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n test: !!repoName,\n message: 'Repository name using --repoName',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleUpdateRepo({\n orgSlug,\n repoName: String(repoName),\n description: String(cli.flags['repoDescription'] || ''),\n homepage: String(cli.flags['homepage'] || ''),\n default_branch: String(cli.flags['defaultBranch'] || ''),\n visibility: String(cli.flags['visibility'] || 'private')\n })\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchViewRepo(\n orgSlug: string,\n repoName: string\n): Promise<SocketSdkReturnType<'getOrgRepo'>['data'] | undefined> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching repository data...')\n\n const result = await handleApiCall(\n sockSdk.getOrgRepo(orgSlug, repoName),\n 'fetching repository'\n )\n\n spinner.successAndStop('Received response while fetched repository data.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getOrgRepo', result)\n }\n\n return result.data\n}\n","// @ts-ignore\nimport chalkTable from 'chalk-table'\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputViewRepo(\n data: SocketSdkReturnType<'createOrgRepo'>['data'],\n outputKind: 'json' | 'markdown' | 'text'\n): Promise<void> {\n if (outputKind === 'json') {\n const {\n archived,\n created_at,\n default_branch,\n homepage,\n id,\n name,\n visibility\n } = data\n logger.log(\n JSON.stringify(\n {\n id,\n name,\n visibility,\n default_branch,\n homepage,\n archived,\n created_at\n },\n null,\n 2\n )\n )\n return\n }\n\n const options = {\n columns: [\n { field: 'id', name: colors.magenta('ID') },\n { field: 'name', name: colors.magenta('Name') },\n { field: 'visibility', name: colors.magenta('Visibility') },\n { field: 'default_branch', name: colors.magenta('Default branch') },\n { field: 'homepage', name: colors.magenta('Homepage') },\n { field: 'archived', name: colors.magenta('Archived') },\n { field: 'created_at', name: colors.magenta('Created at') }\n ]\n }\n\n logger.log(chalkTable(options, [data]))\n}\n","import { fetchViewRepo } from './fetch-view-repo'\nimport { outputViewRepo } from './output-view-repo'\n\nexport async function handleViewRepo(\n orgSlug: string,\n repoName: string,\n outputKind: 'json' | 'markdown' | 'text'\n): Promise<void> {\n const data = await fetchViewRepo(orgSlug, repoName)\n if (!data) {\n return\n }\n\n await outputViewRepo(data, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleViewRepo } from './handle-view-repo'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'view',\n description: 'View repositories in an organization',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n repoName: {\n description: 'The repository to check',\n default: '',\n type: 'string'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> --repo-name=<name>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: repo:list\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg\n `\n}\n\nexport const cmdReposView = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown, repoName } = cli.flags\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !!orgSlug,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n test: !!repoName,\n message: 'Repository name using --repoName',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleViewRepo(\n orgSlug,\n String(repoName),\n json ? 'json' : markdown ? 'markdown' : 'text'\n )\n}\n","import { cmdReposCreate } from './cmd-repos-create'\nimport { cmdReposDel } from './cmd-repos-del'\nimport { cmdReposList } from './cmd-repos-list'\nimport { cmdReposUpdate } from './cmd-repos-update'\nimport { cmdReposView } from './cmd-repos-view'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\n\nimport type { CliSubcommand } from '../../utils/meow-with-subcommands'\n\nconst description = 'Repositories related commands'\n\nexport const cmdRepos: CliSubcommand = {\n description,\n async run(argv, importMeta, { parentName }) {\n await meowWithSubcommands(\n {\n create: cmdReposCreate,\n view: cmdReposView,\n list: cmdReposList,\n del: cmdReposDel,\n update: cmdReposUpdate\n },\n {\n argv,\n description,\n importMeta,\n name: `${parentName} repos`\n }\n )\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\nimport { select } from '@socketsecurity/registry/lib/prompts'\n\nimport { handleApiCall } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nexport async function suggestOrgSlug(): Promise<string | void> {\n const sockSdk = await setupSdk()\n const result = await handleApiCall(\n sockSdk.getOrganizations(),\n 'looking up organizations'\n )\n // Ignore a failed request here. It was not the primary goal of\n // running this command and reporting it only leads to end-user confusion.\n if (result.success) {\n const proceed = await select<string>({\n message:\n 'Missing org name; do you want to use any of these orgs for this scan?',\n choices: [\n ...Object.values(result.data.organizations).map(org => {\n const slug = org.name ?? 'undefined'\n return {\n name: `Yes [${slug}]`,\n value: slug,\n description: `Use \"${slug}\" as the organization`\n }\n }),\n {\n name: 'No',\n value: '',\n description:\n 'Do not use any of these organizations (will end in a no-op)'\n }\n ]\n })\n if (proceed) {\n return proceed\n }\n } else {\n logger.fail(\n 'Failed to lookup organization list from API, unable to suggest'\n )\n }\n}\n","import { select } from '@socketsecurity/registry/lib/prompts'\n\nexport async function suggestTarget(): Promise<string[] | void> {\n // We could prefill this with sub-dirs of the current\n // dir ... but is that going to be useful?\n const proceed = await select<boolean>({\n message: 'No TARGET given. Do you want to use the current directory?',\n choices: [\n {\n name: 'Yes',\n value: true,\n description: 'Target the current directory'\n },\n {\n name: 'No',\n value: false,\n description:\n 'Do not use the current directory (this will end in a no-op)'\n }\n ]\n })\n if (proceed) {\n return ['.']\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleCreateNewScan } from './handle-create-new-scan'\nimport { suggestOrgSlug } from './suggest-org-slug'\nimport { suggestTarget } from './suggest_target'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'create',\n description: 'Create a scan',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n branch: {\n type: 'string',\n shortFlag: 'b',\n default: 'socket-default-branch',\n description: 'Branch name'\n },\n commitMessage: {\n type: 'string',\n shortFlag: 'm',\n default: '',\n description: 'Commit message'\n },\n commitHash: {\n type: 'string',\n shortFlag: 'ch',\n default: '',\n description: 'Commit hash'\n },\n committers: {\n type: 'string',\n shortFlag: 'c',\n default: '',\n description: 'Committers'\n },\n cwd: {\n type: 'string',\n description: 'working directory, defaults to process.cwd()'\n },\n defaultBranch: {\n type: 'boolean',\n default: false,\n description:\n 'Set the default branch of the repository to the branch of this full-scan. Should only need to be done once, for example for the \"main\" or \"master\" branch.'\n },\n interactive: {\n type: 'boolean',\n default: true,\n description:\n 'Allow for interactive elements, asking for input. Use --no-interactive to prevent any input questions, defaulting them to cancel/no.'\n },\n pendingHead: {\n type: 'boolean',\n default: true,\n description:\n 'Designate this full-scan as the latest scan of a given branch. This must be set to have it show up in the dashboard.'\n },\n pullRequest: {\n type: 'number',\n shortFlag: 'pr',\n description: 'Commit hash'\n },\n readOnly: {\n type: 'boolean',\n default: false,\n description:\n 'Similar to --dry-run except it can read from remote, stops before it would create an actual report'\n },\n repo: {\n type: 'string',\n shortFlag: 'r',\n default: 'socket-default-repository',\n description: 'Repository name'\n },\n report: {\n type: 'boolean',\n default: false,\n description:\n 'Wait for the scan creation to complete, then basically run `socket scan report` on it'\n },\n tmp: {\n type: 'boolean',\n shortFlag: 't',\n default: false,\n description:\n 'Set the visibility (true/false) of the scan in your dashboard. Can not be used when --pendingHead is set.'\n }\n },\n // TODO: your project's \"socket.yml\" file's \"projectIgnorePaths\"\n help: (command, config) => `\n Usage\n $ ${command} [...options] <org> <TARGET> [TARGET...]\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: full-scans:create\n\n Uploads the specified \"package.json\" and lock files for JavaScript, Python,\n Go, Scala, Gradle, and Kotlin dependency manifests.\n If any folder is specified, the ones found in there recursively are uploaded.\n\n Supports globbing such as \"**/package.json\", \"**/requirements.txt\", etc.\n\n Ignores any file specified in your project's \".gitignore\" and also has a\n sensible set of default ignores from the \"ignore-by-default\" module.\n\n TARGET should be a FILE or DIR that _must_ be inside the CWD.\n\n When a FILE is given only that FILE is targeted. Otherwise any eligible\n files in the given DIR will be considered.\n\n The --repo and --branch flags tell Socket to associate this Scan with that\n repo/branch. The names will show up on your dashboard on the Socket website.\n\n Note: for a first run you probably want to set --defaultBranch to indicate\n the default branch name, like \"main\" or \"master\".\n\n Note: --pendingHead is enabled by default and makes a scan show up in your\n dashboard. You can use \\`--no-pendingHead\\` to have it not show up.\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} --repo=test-repo --branch=main FakeOrg ./package.json\n `\n}\n\nexport const cmdScanCreate = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const {\n branch: branchName = 'socket-default-branch',\n commitHash,\n commitMessage,\n committers,\n cwd: cwdOverride,\n defaultBranch,\n dryRun,\n interactive = true,\n json,\n markdown,\n pendingHead,\n pullRequest,\n readOnly,\n repo: repoName = 'socket-default-repository',\n report,\n tmp\n } = cli.flags as {\n branch: string\n cwd: string\n commitHash: string\n commitMessage: string\n committers: string\n defaultBranch: boolean\n dryRun: boolean\n interactive: boolean\n json: boolean\n markdown: boolean\n pendingHead: boolean\n pullRequest: number\n readOnly: boolean\n repo: string\n report: boolean\n tmp: boolean\n }\n const defaultOrgSlug = getConfigValue('defaultOrg')\n let orgSlug = defaultOrgSlug || cli.input[0] || ''\n let targets = cli.input.slice(defaultOrgSlug ? 0 : 1)\n\n const cwd =\n cwdOverride && cwdOverride !== 'process.cwd()'\n ? String(cwdOverride)\n : process.cwd()\n\n // We're going to need an api token to suggest data because those suggestions\n // must come from data we already know. Don't error on missing api token yet.\n // If the api-token is not set, ignore it for the sake of suggestions.\n const apiToken = getDefaultToken()\n\n // If we updated any inputs then we should print the command line to repeat\n // the command without requiring user input, as a suggestion.\n let updatedInput = false\n\n if (!targets.length && !dryRun && interactive) {\n const received = await suggestTarget()\n targets = received ?? []\n updatedInput = true\n }\n\n // If the current cwd is unknown and is used as a repo slug anyways, we will\n // first need to register the slug before we can use it.\n // Only do suggestions with an apiToken and when not in dryRun mode\n if (apiToken && !dryRun && interactive) {\n if (!orgSlug) {\n const suggestion = await suggestOrgSlug()\n if (suggestion) {\n orgSlug = suggestion\n }\n updatedInput = true\n }\n }\n\n if (updatedInput && orgSlug && targets?.length) {\n logger.error(\n 'Note: You can invoke this command next time to skip the interactive questions:'\n )\n logger.error('```')\n logger.error(\n ` socket scan create [other flags...] ${defaultOrgSlug ? '' : orgSlug} ${targets.join(' ')}`\n )\n logger.error('```\\n')\n }\n\n const wasBadInput = handleBadInput(\n {\n nook: !!defaultOrgSlug,\n test: !!orgSlug && orgSlug !== '.',\n message: 'Org name as the first argument',\n pass: 'ok',\n fail:\n orgSlug === '.'\n ? 'dot is an invalid org, most likely you forgot the org name here?'\n : 'missing'\n },\n {\n test: !!targets.length,\n message: 'At least one TARGET (e.g. `.` or `./package.json`)',\n pass: 'ok',\n fail: 'missing (or perhaps you forgot the org slug?)'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message: 'This command requires an API token for access',\n pass: 'ok',\n fail: 'missing (try `socket login`)'\n },\n {\n nook: true,\n test: !pendingHead || !tmp,\n message: 'Can not use --pendingHead and --tmp at the same time',\n pass: 'ok',\n fail: 'remove at least one flag'\n },\n {\n nook: true,\n test: !pendingHead || !!branchName,\n message: 'When --pendingHead is set, --branch is mandatory',\n pass: 'ok',\n fail: 'missing branch name'\n },\n {\n nook: true,\n test: !defaultBranch || !!branchName,\n message: 'When --defaultBranch is set, --branch is mandatory',\n pass: 'ok',\n fail: 'missing branch name'\n }\n )\n if (wasBadInput) {\n return\n }\n\n // Note exiting earlier to skirt a hidden auth requirement\n if (dryRun) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleCreateNewScan({\n branchName: branchName as string,\n commitHash: (commitHash && String(commitHash)) || '',\n commitMessage: (commitMessage && String(commitMessage)) || '',\n committers: (committers && String(committers)) || '',\n cwd,\n defaultBranch: Boolean(defaultBranch),\n interactive: Boolean(interactive),\n orgSlug,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text',\n pendingHead: Boolean(pendingHead),\n pullRequest: Number(pullRequest),\n readOnly: Boolean(readOnly),\n repoName: repoName,\n report,\n targets,\n tmp: Boolean(tmp)\n })\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchDeleteOrgFullScan(\n orgSlug: string,\n scanId: string\n): Promise<SocketSdkReturnType<'deleteOrgFullScan'>['data'] | void> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Requesting the scan to be deleted...')\n\n const result = await handleApiCall(\n sockSdk.deleteOrgFullScan(orgSlug, scanId),\n 'Deleting scan'\n )\n\n spinner.successAndStop('Received response for deleting a scan.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('deleteOrgFullScan', result)\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputDeleteScan(\n _data: SocketSdkReturnType<'deleteOrgFullScan'>['data']\n): Promise<void> {\n logger.success('Scan deleted successfully')\n}\n","import { fetchDeleteOrgFullScan } from './fetch-delete-org-full-scan'\nimport { outputDeleteScan } from './output-delete-scan'\n\nexport async function handleDeleteScan(\n orgSlug: string,\n scanId: string\n): Promise<void> {\n const data = await fetchDeleteOrgFullScan(orgSlug, scanId)\n if (!data) {\n return\n }\n\n await outputDeleteScan(data)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleDeleteScan } from './handle-delete-scan'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'del',\n description: 'Delete a scan',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> <scan ID>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: full-scans:delete\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg 000aaaa1-0000-0a0a-00a0-00a0000000a0\n `\n}\n\nexport const cmdScanDel = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const scanId = (defaultOrgSlug ? cli.input[0] : cli.input[1]) || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: !!defaultOrgSlug,\n test: !!orgSlug && orgSlug !== '.',\n message: 'Org name as the first argument',\n pass: 'ok',\n fail:\n orgSlug === '.'\n ? 'dot is an invalid org, most likely you forgot the org name here?'\n : 'missing'\n },\n {\n test: !!scanId,\n message: 'Scan ID to delete',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleDeleteScan(orgSlug, scanId)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { handleApiCall, handleApiError, queryApi } from '../../utils/api'\nimport { failMsgWithBadge } from '../../utils/fail-msg-with-badge'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchDiffScan({\n id1,\n id2,\n orgSlug\n}: {\n id1: string\n id2: string\n orgSlug: string\n}): Promise<SocketSdkReturnType<'GetOrgDiffScan'>['data'] | undefined> {\n const apiToken = getDefaultToken()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n logger.error('Scan ID 1:', id1)\n logger.error('Scan ID 2:', id2)\n\n spinner.start('Fetching scan diff... (this may take a while)')\n\n const response = await queryApi(\n `orgs/${orgSlug}/full-scans/diff?before=${encodeURIComponent(id1)}&after=${encodeURIComponent(id2)}`,\n apiToken || ''\n )\n\n spinner.successAndStop('Received scan diff response')\n\n if (!response.ok) {\n const err = await handleApiError(response.status)\n logger.fail(failMsgWithBadge(response.statusText, err))\n return\n }\n\n const result = await handleApiCall(\n (await response.json()) as Promise<\n SocketSdkReturnType<'GetOrgDiffScan'>['data']\n >,\n 'Deserializing json'\n )\n\n return result\n}\n","import fs from 'node:fs'\nimport util from 'node:util'\n\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nconst SOCKET_SBOM_URL_PREFIX =\n 'https://socket.dev/dashboard/org/SocketDev/sbom/'\n\nexport async function outputDiffScan(\n result: SocketSdkReturnType<'GetOrgDiffScan'>['data'],\n {\n depth,\n file,\n outputKind\n }: {\n depth: number\n file: string\n outputKind: 'json' | 'markdown' | 'text'\n }\n): Promise<void> {\n const dashboardUrl = result.diff_report_url\n const dashboardMessage = dashboardUrl\n ? `\\n View this diff scan in the Socket dashboard: ${colors.cyan(dashboardUrl)}`\n : ''\n\n // When forcing json, or dumping to file, serialize to string such that it\n // won't get truncated. The only way to dump the full raw JSON to stdout is\n // to use `--json --file -` (the dash is a standard notation for stdout)\n if (outputKind === 'json' || file) {\n let json\n try {\n json = JSON.stringify(result, null, 2)\n } catch (e) {\n process.exitCode = 1\n // Most likely caused by a circular reference (or OOM)\n logger.fail('There was a problem converting the data to JSON')\n logger.error(e)\n return\n }\n\n if (file && file !== '-') {\n logger.log(`Writing json to \\`${file}\\``)\n fs.writeFile(file, JSON.stringify(result, null, 2), err => {\n if (err) {\n logger.fail(`Writing to \\`${file}\\` failed...`)\n logger.error(err)\n } else {\n logger.log(`Data successfully written to \\`${file}\\``)\n }\n logger.error(dashboardMessage)\n })\n } else {\n // TODO: expose different method for writing to stderr when simply dodging stdout\n logger.error(`\\n Diff scan result: \\n`)\n logger.log(json)\n logger.error(dashboardMessage)\n }\n\n return\n }\n\n if (outputKind === 'markdown') {\n logger.log('# Scan diff result')\n logger.log('')\n logger.log('This Socket.dev report shows the changes between two scans:')\n logger.log(\n `- [${result.before.id}](${SOCKET_SBOM_URL_PREFIX}${result.before.id})`\n )\n logger.log(\n `- [${result.after.id}](${SOCKET_SBOM_URL_PREFIX}${result.after.id})`\n )\n logger.log('')\n logger.log(\n `You can [view this report in your dashboard](${result.diff_report_url})`\n )\n logger.log('')\n logger.log('## Changes')\n logger.log('')\n logger.log(\n `- directDependenciesChanged: ${result.directDependenciesChanged}`\n )\n logger.log(`- Added packages: ${result.artifacts.added.length}`)\n if (result.artifacts.added.length > 0) {\n result.artifacts.added.slice(0, 10).forEach(artifact => {\n logger.log(` - ${artifact.type} ${artifact.name}@${artifact.version}`)\n })\n if (result.artifacts.added.length > 10) {\n logger.log(` ... and ${result.artifacts.added.length - 10} more`)\n }\n }\n logger.log(`- Removed packages: ${result.artifacts.removed.length}`)\n if (result.artifacts.removed.length > 0) {\n result.artifacts.removed.slice(0, 10).forEach(artifact => {\n logger.log(` - ${artifact.type} ${artifact.name}@${artifact.version}`)\n })\n if (result.artifacts.removed.length > 10) {\n logger.log(` ... and ${result.artifacts.removed.length - 10} more`)\n }\n }\n logger.log(`- Replaced packages: ${result.artifacts.replaced.length}`)\n if (result.artifacts.replaced.length > 0) {\n result.artifacts.replaced.slice(0, 10).forEach(artifact => {\n logger.log(` - ${artifact.type} ${artifact.name}@${artifact.version}`)\n })\n if (result.artifacts.replaced.length > 10) {\n logger.log(` ... and ${result.artifacts.replaced.length - 10} more`)\n }\n }\n logger.log(`- Updated packages: ${result.artifacts.updated.length}`)\n if (result.artifacts.updated.length > 0) {\n result.artifacts.updated.slice(0, 10).forEach(artifact => {\n logger.log(` - ${artifact.type} ${artifact.name}@${artifact.version}`)\n })\n if (result.artifacts.updated.length > 10) {\n logger.log(` ... and ${result.artifacts.updated.length - 10} more`)\n }\n }\n logger.log(`- Unchanged packages: ${result.artifacts.unchanged.length}`)\n if (result.artifacts.unchanged.length > 0) {\n result.artifacts.unchanged.slice(0, 10).forEach(artifact => {\n logger.log(` - ${artifact.type} ${artifact.name}@${artifact.version}`)\n })\n if (result.artifacts.unchanged.length > 10) {\n logger.log(` ... and ${result.artifacts.unchanged.length - 10} more`)\n }\n }\n logger.log('')\n logger.log(`## Scan ${result.before.id}`)\n logger.log('')\n logger.log(\n 'This Scan was considered to be the \"base\" / \"from\" / \"before\" Scan.'\n )\n logger.log('')\n for (const [key, value] of Object.entries(result.before)) {\n if (key === 'pull_request' && !value) {\n continue\n }\n if (!['id', 'organization_id', 'repository_id'].includes(key)) {\n logger.group(\n `- ${key === 'repository_slug' ? 'repo' : key === 'organization_slug' ? 'org' : key}: ${value}`\n )\n logger.groupEnd()\n }\n }\n logger.log('')\n logger.log(`## Scan ${result.after.id}`)\n logger.log('')\n logger.log(\n 'This Scan was considered to be the \"head\" / \"to\" / \"after\" Scan.'\n )\n logger.log('')\n for (const [key, value] of Object.entries(result.after)) {\n if (key === 'pull_request' && !value) {\n continue\n }\n if (!['id', 'organization_id', 'repository_id'].includes(key)) {\n logger.group(\n `- ${key === 'repository_slug' ? 'repo' : key === 'organization_slug' ? 'org' : key}: ${value}`\n )\n logger.groupEnd()\n }\n }\n logger.log('')\n\n return\n }\n\n // In this case neither the --json nor the --file flag was passed\n // Dump the JSON to CLI and let NodeJS deal with truncation\n\n logger.log('Diff scan result:')\n logger.log(\n util.inspect(result, {\n showHidden: false,\n depth: depth > 0 ? depth : null,\n colors: true,\n maxArrayLength: null\n })\n )\n logger.error(\n `\\n 📝 To display the detailed report in the terminal, use the --json flag. For a friendlier report, use the --markdown flag.\\n`\n )\n logger.log(dashboardMessage)\n}\n","import { fetchDiffScan } from './fetch-diff-scan'\nimport { outputDiffScan } from './output-diff-scan'\n\nexport async function handleDiffScan({\n depth,\n file,\n id1,\n id2,\n orgSlug,\n outputKind\n}: {\n depth: number\n file: string\n id1: string\n id2: string\n orgSlug: string\n outputKind: 'json' | 'markdown' | 'text'\n}): Promise<void> {\n const data = await fetchDiffScan({\n id1,\n id2,\n orgSlug\n })\n if (!data) {\n return\n }\n\n await outputDiffScan(data, {\n depth,\n file,\n outputKind\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleDiffScan } from './handle-diff-scan'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst SOCKET_SBOM_URL_PREFIX =\n 'https://socket.dev/dashboard/org/SocketDev/sbom/'\n\nconst config: CliCommandConfig = {\n commandName: 'diff',\n description: 'See what changed between two Scans',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n depth: {\n type: 'number',\n default: 2,\n description:\n 'Max depth of JSON to display before truncating, use zero for no limit (without --json/--file)'\n },\n file: {\n type: 'string',\n shortFlag: 'f',\n default: '',\n description:\n 'Path to a local file where the output should be saved. Use `-` to force stdout.'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> <ID1> <ID2>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: full-scans:list\n\n This command displays the package changes between two scans. The full output\n can be pretty large depending on the size of your repo and time range. It is\n best stored to disk (with --json) to be further analyzed by other tools.\n\n Note: First Scan ID is assumed to be the older ID. This is only relevant for\n the added/removed list (similar to diffing two files with git).\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeCorp aaa0aa0a-aaaa-0000-0a0a-0000000a00a0 aaa1aa1a-aaaa-1111-1a1a-1111111a11a1\n $ ${command} FakeCorp aaa0aa0a-aaaa-0000-0a0a-0000000a00a0 aaa1aa1a-aaaa-1111-1a1a-1111111a11a1 --json\n `\n}\n\nexport const cmdScanDiff = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { depth, file, json, markdown } = cli.flags\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n\n let id1 = cli.input[defaultOrgSlug ? 0 : 1] || ''\n let id2 = cli.input[defaultOrgSlug ? 1 : 2] || ''\n if (id1.startsWith(SOCKET_SBOM_URL_PREFIX)) {\n id1 = id1.slice(SOCKET_SBOM_URL_PREFIX.length)\n }\n if (id2.startsWith(SOCKET_SBOM_URL_PREFIX)) {\n id2 = id2.slice(SOCKET_SBOM_URL_PREFIX.length)\n }\n\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n test: !!(id1 && id2),\n message:\n 'Specify two Scan IDs.\\nA Scan ID looks like `aaa0aa0a-aaaa-0000-0a0a-0000000a00a0`.',\n pass: 'ok',\n fail:\n !id1 && !id2\n ? 'missing both Scan IDs'\n : !id2\n ? 'missing second Scan ID'\n : 'missing first Scan ID' // Not sure how this can happen but ok.\n },\n {\n test: !!orgSlug,\n nook: true,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleDiffScan({\n id1: String(id1 || ''),\n id2: String(id2 || ''),\n depth: Number(depth),\n orgSlug,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text',\n file: String(file || '')\n })\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchListScans({\n branch,\n direction,\n from_time,\n orgSlug,\n page,\n per_page,\n repo,\n sort\n}: {\n branch: string\n direction: string\n from_time: string\n orgSlug: string\n page: number\n per_page: number\n repo: string\n sort: string\n}): Promise<SocketSdkReturnType<'getOrgFullScanList'>['data'] | void> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching list of scans...')\n\n const result = await handleApiCall(\n sockSdk.getOrgFullScanList(orgSlug, {\n ...(branch ? { branch } : {}),\n ...(repo ? { repo } : {}),\n sort,\n direction,\n per_page: String(per_page),\n page: String(page),\n from: from_time\n }),\n 'Listing scans'\n )\n\n spinner.successAndStop(`Received response for list of scans.`)\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getOrgFullScanList', result)\n }\n\n return result.data\n}\n","// @ts-ignore\nimport chalkTable from 'chalk-table'\nimport colors from 'yoctocolors-cjs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputListScans(\n data: SocketSdkReturnType<'getOrgFullScanList'>['data'],\n outputKind: 'json' | 'markdown' | 'print'\n): Promise<void> {\n if (outputKind === 'json') {\n logger.log(data)\n return\n }\n\n const options = {\n columns: [\n { field: 'id', name: colors.magenta('ID') },\n { field: 'report_url', name: colors.magenta('Scan URL') },\n { field: 'repo', name: colors.magenta('Repo') },\n { field: 'branch', name: colors.magenta('Branch') },\n { field: 'created_at', name: colors.magenta('Created at') }\n ]\n }\n\n const formattedResults = data.results.map(d => {\n return {\n id: d.id,\n report_url: colors.underline(`${d.html_report_url}`),\n created_at: d.created_at\n ? new Date(d.created_at).toLocaleDateString('en-us', {\n year: 'numeric',\n month: 'numeric',\n day: 'numeric'\n })\n : '',\n repo: d.repo,\n branch: d.branch\n }\n })\n\n logger.log(chalkTable(options, formattedResults))\n}\n","import { fetchListScans } from './fetch-list-scans'\nimport { outputListScans } from './output-list-scans'\n\nexport async function handleListScans({\n branch,\n direction,\n from_time,\n orgSlug,\n outputKind,\n page,\n per_page,\n repo,\n sort\n}: {\n branch: string\n direction: string\n from_time: string\n orgSlug: string\n outputKind: 'json' | 'markdown' | 'print'\n page: number\n per_page: number\n repo: string\n sort: string\n}): Promise<void> {\n const data = await fetchListScans({\n branch,\n direction,\n from_time,\n orgSlug,\n page,\n per_page,\n repo,\n sort\n })\n if (!data) {\n return\n }\n\n await outputListScans(data, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleListScans } from './handle-list-scans'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type {\n CliCommandConfig,\n CliSubcommand\n} from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'list',\n description: 'List the scans for an organization',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n branch: {\n type: 'string',\n description: 'Filter to show only scans with this branch name'\n },\n direction: {\n type: 'string',\n shortFlag: 'd',\n default: 'desc',\n description: 'Direction option (`desc` or `asc`) - Default is `desc`'\n },\n fromTime: {\n type: 'string',\n shortFlag: 'f',\n default: '',\n description: 'From time - as a unix timestamp'\n },\n page: {\n type: 'number',\n shortFlag: 'p',\n default: 1,\n description: 'Page number - Default is 1'\n },\n perPage: {\n type: 'number',\n shortFlag: 'pp',\n default: 30,\n description: 'Results per page - Default is 30'\n },\n repo: {\n type: 'string',\n description: 'Filter to show only scans with this repository name'\n },\n sort: {\n type: 'string',\n shortFlag: 's',\n default: 'created_at',\n description:\n 'Sorting option (`name` or `created_at`) - default is `created_at`'\n },\n untilTime: {\n type: 'string',\n shortFlag: 'u',\n default: '',\n description: 'Until time - as a unix timestamp'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: full-scans:list\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg\n `\n}\n\nexport const cmdScanList: CliSubcommand = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n) {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { branch, json, markdown, repo } = cli.flags\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: !!defaultOrgSlug,\n test: !!orgSlug && orgSlug !== '.',\n message: 'Org name as the first argument',\n pass: 'ok',\n fail:\n orgSlug === '.'\n ? 'dot is an invalid org, most likely you forgot the org name here?'\n : 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleListScans({\n branch: branch ? String(branch) : '',\n direction: String(cli.flags['direction'] || ''),\n from_time: String(cli.flags['fromTime'] || ''),\n orgSlug,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'print',\n page: Number(cli.flags['page'] || 1),\n per_page: Number(cli.flags['perPage'] || 30),\n repo: repo ? String(repo) : '',\n sort: String(cli.flags['sort'] || '')\n })\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function fetchScanMetadata(\n orgSlug: string,\n scanId: string\n): Promise<SocketSdkReturnType<'getOrgFullScanMetadata'>['data'] | void> {\n const sockSdk = await setupSdk()\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching meta data for a full scan...')\n\n const result = await handleApiCall(\n sockSdk.getOrgFullScanMetadata(orgSlug, scanId),\n 'Listing scans'\n )\n\n spinner.successAndStop('Received response for scan meta data.')\n\n if (!result.success) {\n handleUnsuccessfulApiResponse('getOrgFullScanMetadata', result)\n }\n\n return result.data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport type { SocketSdkReturnType } from '@socketsecurity/sdk'\n\nexport async function outputScanMetadata(\n data: SocketSdkReturnType<'getOrgFullScanMetadata'>['data'],\n scanId: string,\n outputKind: 'json' | 'markdown' | 'text'\n): Promise<void> {\n if (outputKind === 'json') {\n logger.log(data)\n } else {\n // Markdown = print\n if (outputKind === 'markdown') {\n logger.log('# Scan meta data\\n')\n }\n logger.log(`Scan ID: ${scanId}\\n`)\n for (const [key, value] of Object.entries(data)) {\n if (\n [\n 'id',\n 'updated_at',\n 'organization_id',\n 'repository_id',\n 'commit_hash',\n 'html_report_url'\n ].includes(key)\n ) {\n continue\n }\n logger.log(`- ${key}:`, value)\n }\n if (outputKind === 'markdown') {\n logger.log(\n `\\nYou can view this report at: [${data.html_report_url}](${data.html_report_url})\\n`\n )\n } else {\n logger.log(`\\nYou can view this report at: ${data.html_report_url}]\\n`)\n }\n }\n}\n","import { fetchScanMetadata } from './fetch-scan-metadata'\nimport { outputScanMetadata } from './output-scan-metadata'\n\nexport async function handleOrgScanMetadata(\n orgSlug: string,\n scanId: string,\n outputKind: 'json' | 'markdown' | 'text'\n): Promise<void> {\n const data = await fetchScanMetadata(orgSlug, scanId)\n if (!data) {\n return\n }\n\n await outputScanMetadata(data, scanId, outputKind)\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleOrgScanMetadata } from './handle-scan-metadata'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type {\n CliCommandConfig,\n CliSubcommand\n} from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'metadata',\n description: \"Get a scan's metadata\",\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> <scan ID>\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: full-scans:list\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg 000aaaa1-0000-0a0a-00a0-00a0000000a0\n `\n}\n\nexport const cmdScanMetadata: CliSubcommand = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const scanId = (defaultOrgSlug ? cli.input[0] : cli.input[1]) || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: !!defaultOrgSlug,\n test: !!orgSlug && orgSlug !== '.',\n message: 'Org name as the first argument',\n pass: 'ok',\n fail:\n orgSlug === '.'\n ? 'dot is an invalid org, most likely you forgot the org name here?'\n : 'missing'\n },\n {\n test: !!scanId,\n message: 'Scan ID to inspect as argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleOrgScanMetadata(\n orgSlug,\n scanId,\n json ? 'json' : markdown ? 'markdown' : 'text'\n )\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleScanReport } from './handle-scan-report'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type {\n CliCommandConfig,\n CliSubcommand\n} from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'report',\n description:\n 'Check whether a scan result passes the organizational policies (security, license)',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n fold: {\n type: 'string',\n default: 'none',\n description: 'Fold reported alerts to some degree'\n },\n reportLevel: {\n type: 'string',\n default: 'warn',\n description: 'Which policy level alerts should be reported'\n },\n short: {\n type: 'boolean',\n default: false,\n description: 'Report only the healthy status'\n },\n license: {\n type: 'boolean',\n default: false,\n description: 'Also report the license policy status. Default: false'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> <scan ID> [path to output file]\n\n API Token Requirements\n - Quota: 2 units\n - Permissions: full-scans:list security-policy:read\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n By default the result is a nested object that looks like this:\n \\`{[ecosystem]: {[pkgName]: {[version]: {[file]: {[type:loc]: policy}}}}\\`\n You can fold this up to given level: 'pkg', 'version', 'file', and 'none'.\n\n By default only the warn and error policy level alerts are reported. You can\n override this and request more ('defer' < 'ignore' < 'monitor' < 'warn' < 'error')\n\n Short responses: JSON: \\`{healthy:bool}\\`, markdown: \\`healthy = bool\\`, text: \\`OK/ERR\\`\n\n Examples\n $ ${command} FakeOrg 000aaaa1-0000-0a0a-00a0-00a0000000a0 --json --fold=version\n $ ${command} FakeOrg 000aaaa1-0000-0a0a-00a0-00a0000000a0 --license --markdown --short\n `\n}\n\nexport const cmdScanReport: CliSubcommand = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const {\n fold = 'none',\n json,\n license,\n markdown,\n reportLevel = 'warn'\n } = cli.flags\n\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const scanId = (defaultOrgSlug ? cli.input[0] : cli.input[1]) || ''\n const file = (defaultOrgSlug ? cli.input[1] : cli.input[2]) || '-'\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: !!defaultOrgSlug,\n test: !!orgSlug && orgSlug !== '.',\n message: 'Org name as the first argument',\n pass: 'ok',\n fail:\n orgSlug === '.'\n ? 'dot is an invalid org, most likely you forgot the org name here?'\n : 'missing'\n },\n {\n test: !!scanId,\n message: 'Scan ID to fetch',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleScanReport({\n orgSlug,\n scanId: scanId,\n includeLicensePolicy: !!license,\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text',\n filePath: file,\n fold: fold as 'none' | 'file' | 'pkg' | 'version',\n short: !!cli.flags['short'],\n reportLevel: reportLevel as\n | 'warn'\n | 'error'\n | 'defer'\n | 'ignore'\n | 'monitor'\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\nimport { handleApiError, queryApi } from '../../utils/api'\nimport { AuthError } from '../../utils/errors'\nimport { failMsgWithBadge } from '../../utils/fail-msg-with-badge'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { components } from '@socketsecurity/sdk/types/api'\n\nexport async function fetchScan(\n orgSlug: string,\n scanId: string\n): Promise<Array<components['schemas']['SocketArtifact']> | undefined> {\n const apiToken = getDefaultToken()\n if (!apiToken) {\n throw new AuthError(\n 'User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.'\n )\n }\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching scan data...')\n\n const response = await queryApi(\n `orgs/${orgSlug}/full-scans/${encodeURIComponent(scanId)}`,\n apiToken\n )\n\n spinner.successAndStop('Received response while fetching scan data.')\n\n if (!response.ok) {\n const err = await handleApiError(response.status)\n logger.fail(failMsgWithBadge(response.statusText, `Fetch error: ${err}`))\n return\n }\n\n // This is nd-json; each line is a json object\n const jsons = await response.text()\n const lines = jsons.split('\\n').filter(Boolean)\n const data = lines.map(line => {\n try {\n return JSON.parse(line)\n } catch {\n console.error(\n 'At least one line item was returned that could not be parsed as JSON...'\n )\n return {}\n }\n }) as unknown as Array<components['schemas']['SocketArtifact']>\n\n return data\n}\n","import fs from 'node:fs/promises'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { mdTable } from '../../utils/markdown'\n\nimport type { components } from '@socketsecurity/sdk/types/api'\n\nexport async function outputScanView(\n artifacts: Array<components['schemas']['SocketArtifact']>,\n orgSlug: string,\n scanId: string,\n filePath: string\n): Promise<void> {\n const display = artifacts.map(art => {\n const author = Array.isArray(art.author)\n ? `${art.author[0]}${art.author.length > 1 ? ' et.al.' : ''}`\n : art.author\n return {\n type: art.type,\n name: art.name,\n version: art.version,\n author,\n score: JSON.stringify(art.score)\n }\n })\n\n const md = mdTable<any>(display, [\n 'type',\n 'version',\n 'name',\n 'author',\n 'score'\n ])\n\n const report =\n `\n# Scan Details\n\nThese are the artifacts and their scores found.\n\nScan ID: ${scanId}\n\n${md}\n\nView this report at: https://socket.dev/dashboard/org/${orgSlug}/sbom/${scanId}\n `.trim() + '\\n'\n\n if (filePath && filePath !== '-') {\n try {\n await fs.writeFile(filePath, report, 'utf8')\n logger.log(`Data successfully written to ${filePath}`)\n } catch (e) {\n process.exitCode = 1\n logger.fail('There was an error trying to write the json to disk')\n logger.error(e)\n }\n } else {\n logger.log(report)\n }\n}\n","import { fetchScan } from './fetch-scan'\nimport { outputScanView } from './output-scan-view'\n\nexport async function handleScanView(\n orgSlug: string,\n scanId: string,\n filePath: string\n): Promise<void> {\n const data = await fetchScan(orgSlug, scanId)\n if (!data) {\n return\n }\n\n await outputScanView(data, orgSlug, scanId, filePath)\n}\n","import constants from '../../constants'\nimport { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'\nimport { setupSdk } from '../../utils/sdk'\n\nimport type { SocketSdkResultType } from '@socketsecurity/sdk'\n\nexport async function streamScan(\n orgSlug: string,\n scanId: string,\n file: string | undefined\n): Promise<SocketSdkResultType<'getOrgFullScan'> | undefined> {\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n const sockSdk = await setupSdk()\n\n spinner.start('Fetching scan...')\n\n const data = await handleApiCall(\n sockSdk.getOrgFullScan(orgSlug, scanId, file === '-' ? undefined : file),\n 'Fetching a scan'\n )\n\n spinner.successAndStop(\n file ? `Full scan details written to ${file}` : 'stdout'\n )\n\n if (!data?.success) {\n handleUnsuccessfulApiResponse('getOrgFullScan', data)\n }\n\n return data\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleScanView } from './handle-scan-view'\nimport { streamScan } from './streamScan'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type {\n CliCommandConfig,\n CliSubcommand\n} from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'view',\n description: 'View the raw results of a scan',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags\n },\n help: (command, config) => `\n Usage\n $ ${command} <org slug> <scan ID> [path to output file]\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: full-scans:list\n\n When no output path is given the contents is sent to stdout.\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} FakeOrg 000aaaa1-0000-0a0a-00a0-00a0000000a0 ./stream.txt\n `\n}\n\nexport const cmdScanView: CliSubcommand = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: string[] | readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const scanId = (defaultOrgSlug ? cli.input[0] : cli.input[1]) || ''\n const file = (defaultOrgSlug ? cli.input[1] : cli.input[2]) || '-'\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: !!defaultOrgSlug,\n test: !!orgSlug && orgSlug !== '.',\n message: 'Org name as the first argument',\n pass: 'ok',\n fail:\n orgSlug === '.'\n ? 'dot is an invalid org, most likely you forgot the org name here?'\n : 'missing'\n },\n {\n test: !!scanId,\n message: 'Scan ID to delete',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message:\n 'The `--json` and `--markdown` flags can not be used at the same time',\n pass: 'ok',\n fail: 'bad'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n if (json) {\n await streamScan(orgSlug, scanId, file)\n } else {\n await handleScanView(orgSlug, scanId, file)\n }\n}\n","import { cmdScanCreate } from './cmd-scan-create'\nimport { cmdScanDel } from './cmd-scan-del'\nimport { cmdScanDiff } from './cmd-scan-diff'\nimport { cmdScanList } from './cmd-scan-list'\nimport { cmdScanMetadata } from './cmd-scan-metadata'\nimport { cmdScanReport } from './cmd-scan-report'\nimport { cmdScanView } from './cmd-scan-view'\nimport { meowWithSubcommands } from '../../utils/meow-with-subcommands'\n\nimport type { CliSubcommand } from '../../utils/meow-with-subcommands'\n\nconst description = 'Scan related commands'\n\nexport const cmdScan: CliSubcommand = {\n description,\n async run(argv, importMeta, { parentName }) {\n await meowWithSubcommands(\n {\n create: cmdScanCreate,\n list: cmdScanList,\n del: cmdScanDel,\n diff: cmdScanDiff,\n metadata: cmdScanMetadata,\n report: cmdScanReport,\n view: cmdScanView\n },\n {\n aliases: {\n // Backwards compat. TODO: Drop next major bump\n stream: {\n description: cmdScanView.description,\n hidden: true,\n argv: ['view'] // Original args will be appended (!)\n }\n },\n argv,\n description,\n importMeta,\n name: parentName + ' scan'\n }\n )\n }\n}\n","import constants from '../../constants'\nimport { queryApi } from '../../utils/api'\nimport { AuthError } from '../../utils/errors'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { ThreadFeedResponse } from './types'\n\nexport async function fetchThreatFeed({\n direction,\n ecosystem,\n filter,\n page,\n perPage\n}: {\n direction: string\n ecosystem: string\n filter: string\n page: string\n perPage: number\n}): Promise<ThreadFeedResponse | { error: { message: string } }> {\n const queryParams = new URLSearchParams([\n ['direction', direction],\n ['ecosystem', ecosystem],\n ['filter', filter],\n ['page', page],\n ['per_page', String(perPage)]\n ])\n\n const apiToken = getDefaultToken()\n if (!apiToken) {\n throw new AuthError(\n 'User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.'\n )\n }\n\n // Lazily access constants.spinner.\n const { spinner } = constants\n\n spinner.start('Fetching Threat Feed data...')\n\n const response = await queryApi(`threat-feed?${queryParams}`, apiToken)\n\n spinner.successAndStop('Received response while fetching Threat Feed data.')\n\n const data = await response.json()\n\n return data as ThreadFeedResponse | { error: { message: string } }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants from '../../constants'\n\nimport type { ThreadFeedResponse, ThreatResult } from './types'\nimport type { Widgets } from 'blessed'\n\nexport async function outputThreatFeed(\n data: ThreadFeedResponse,\n {\n outputKind\n }: {\n outputKind: 'json' | 'markdown' | 'text'\n }\n) {\n if (outputKind === 'json') {\n logger.log(data)\n return\n }\n\n if (!data?.results?.length) {\n logger.error('Did not receive any data to display...')\n return\n }\n\n const formattedOutput = formatResults(data.results)\n const descriptions = data.results.map(d => d.description)\n\n // Note: this temporarily takes over the terminal (just like `man` does).\n const ScreenWidget = require('blessed/lib/widgets/screen')\n // Lazily access constants.blessedOptions.\n const screen: Widgets.Screen = new ScreenWidget({\n ...constants.blessedOptions\n })\n // Register these keys first so you can always exit, even when it gets stuck\n // If we don't do this and the code crashes, the user must hard-kill the\n // node process just to exit it. That's very bad UX.\n // eslint-disable-next-line n/no-process-exit\n screen.key(['escape', 'q', 'C-c'], () => process.exit(0))\n\n const TableWidget = require('blessed-contrib/lib/widget/table')\n const table: any = new TableWidget({\n keys: 'true',\n fg: 'white',\n selectedFg: 'white',\n selectedBg: 'magenta',\n interactive: 'true',\n label: 'Threat feed',\n width: '100%',\n height: '70%', // Changed from 100% to 70%\n border: {\n type: 'line',\n fg: 'cyan'\n },\n columnWidth: [10, 30, 20, 18, 15, 200],\n // TODO: the truncation doesn't seem to work too well yet but when we add\n // `pad` alignment fails, when we extend columnSpacing alignment fails\n columnSpacing: 1,\n truncate: '_'\n })\n\n // Create details box at the bottom\n const BoxWidget = require('blessed/lib/widgets/box')\n const detailsBox: Widgets.BoxElement = new BoxWidget({\n bottom: 0,\n height: '30%',\n width: '100%',\n border: {\n type: 'line',\n fg: 'cyan'\n },\n label: 'Details',\n content:\n 'Use arrow keys to navigate. Press Enter to select a threat. Press q to exit.',\n style: {\n fg: 'white'\n }\n })\n\n table.setData({\n headers: [\n ' Ecosystem',\n ' Name',\n ' Version',\n ' Threat type',\n ' Detected at',\n ' Details'\n ],\n data: formattedOutput\n })\n\n // allow control the table with the keyboard\n table.focus()\n\n screen.append(table)\n screen.append(detailsBox)\n\n // Update details box when selection changes\n table.rows.on('select item', () => {\n const selectedIndex = table.rows.selected\n if (selectedIndex !== undefined && selectedIndex >= 0) {\n const selectedRow = formattedOutput[selectedIndex]\n if (selectedRow) {\n // Note: the spacing works around issues with the table; it refuses to pad!\n detailsBox.setContent(\n `Ecosystem: ${selectedRow[0]}\\n` +\n `Name: ${selectedRow[1]}\\n` +\n `Version:${selectedRow[2]}\\n` +\n `Threat type:${selectedRow[3]}\\n` +\n `Detected at:${selectedRow[4]}\\n` +\n `Details: ${selectedRow[5]}\\n` +\n `Description: ${descriptions[selectedIndex]}`\n )\n screen.render()\n }\n }\n })\n\n screen.render()\n\n screen.key(['return'], () => {\n const selectedIndex = table.rows.selected\n screen.destroy()\n const selectedRow = formattedOutput[selectedIndex]\n logger.log('Last selection:\\n', selectedRow)\n })\n}\n\nfunction formatResults(data: ThreatResult[]) {\n return data.map(d => {\n const ecosystem = d.purl.split('pkg:')[1]!.split('/')[0]!\n const name = d.purl.split('/')[1]!.split('@')[0]!\n const version = d.purl.split('@')[1]!\n\n const timeDiff = msAtHome(d.createdAt)\n\n // Note: the spacing works around issues with the table; it refuses to pad!\n return [\n ecosystem,\n decodeURIComponent(name),\n ` ${version}`,\n ` ${d.threatType}`,\n ` ${timeDiff}`,\n d.locationHtmlUrl\n ]\n })\n}\n\nfunction msAtHome(isoTimeStamp: string): string {\n const timeStart = Date.parse(isoTimeStamp)\n const timeEnd = Date.now()\n\n const rtf = new Intl.RelativeTimeFormat('en', {\n numeric: 'always',\n style: 'short'\n })\n\n const delta = timeEnd - timeStart\n if (delta < 60 * 60 * 1000) {\n return rtf.format(-Math.round(delta / (60 * 1000)), 'minute')\n // return Math.round(delta / (60 * 1000)) + ' min ago'\n } else if (delta < 24 * 60 * 60 * 1000) {\n return rtf.format(-(delta / (60 * 60 * 1000)).toFixed(1), 'hour')\n // return (delta / (60 * 60 * 1000)).toFixed(1) + ' hr ago'\n } else if (delta < 7 * 24 * 60 * 60 * 1000) {\n return rtf.format(-(delta / (24 * 60 * 60 * 1000)).toFixed(1), 'day')\n // return (delta / (24 * 60 * 60 * 1000)).toFixed(1) + ' day ago'\n } else {\n return isoTimeStamp.slice(0, 10)\n }\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { fetchThreatFeed } from './fetch-threat-feed'\nimport { outputThreatFeed } from './output-threat-feed'\nimport { failMsgWithBadge } from '../../utils/fail-msg-with-badge'\n\nimport type { ThreadFeedResponse } from './types'\n\nexport async function handleThreatFeed({\n direction,\n ecosystem,\n filter,\n outputKind,\n page,\n perPage\n}: {\n direction: string\n ecosystem: string\n filter: string\n outputKind: 'json' | 'markdown' | 'text'\n page: string\n perPage: number\n}): Promise<void> {\n const data = await fetchThreatFeed({\n direction,\n ecosystem,\n filter,\n page,\n perPage\n })\n if (!data) {\n return\n }\n\n if ('error' in data && data.error) {\n logger.fail(failMsgWithBadge('Server Error', data.error.message))\n return\n }\n\n await outputThreatFeed(data as ThreadFeedResponse, {\n outputKind\n })\n}\n","import { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { handleThreatFeed } from './handle-threat-feed'\nimport constants from '../../constants'\nimport { commonFlags, outputFlags } from '../../flags'\nimport { getConfigValue } from '../../utils/config'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\nimport { getDefaultToken } from '../../utils/sdk'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'threat-feed',\n description: '[beta] View the threat feed',\n hidden: false,\n flags: {\n ...commonFlags,\n ...outputFlags,\n perPage: {\n type: 'number',\n shortFlag: 'pp',\n default: 30,\n description: 'Number of items per page'\n },\n page: {\n type: 'string',\n shortFlag: 'p',\n default: '1',\n description: 'Page token'\n },\n direction: {\n type: 'string',\n shortFlag: 'd',\n default: 'desc',\n description: 'Order asc or desc by the createdAt attribute'\n },\n eco: {\n type: 'string',\n shortFlag: 'e',\n default: '',\n description: 'Only show threats for a particular ecosystem'\n },\n filter: {\n type: 'string',\n shortFlag: 'f',\n default: 'mal',\n description: 'Filter what type of threats to return'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command}\n\n API Token Requirements\n - Quota: 1 unit\n - Permissions: threat-feed:list\n - Special access\n\n This feature requires a Threat Feed license. Please contact\n sales@socket.dev if you are interested in purchasing this access.\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Valid filters:\n\n - anom Anomaly\n - c Do not filter\n - fp False Positives\n - joke Joke / Fake\n - mal Malware and Possible Malware [default]\n - secret Secrets\n - spy Telemetry\n - tp False Positives and Unreviewed\n - typo Typo-squat\n - u Unreviewed\n - vuln Vulnerability\n\n Valid ecosystems:\n\n - gem\n - golang\n - maven\n - npm\n - nuget\n - pypi\n\n Examples\n $ ${command}\n $ ${command} --perPage=5 --page=2 --direction=asc --filter=joke\n `\n}\n\nexport const cmdThreatFeed = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { json, markdown } = cli.flags\n const defaultOrgSlug = getConfigValue('defaultOrg')\n const orgSlug = defaultOrgSlug || cli.input[0] || ''\n const apiToken = getDefaultToken()\n\n const wasBadInput = handleBadInput(\n {\n nook: true,\n test: !!orgSlug,\n message: 'Org name as the first argument',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !json || !markdown,\n message: 'The json and markdown flags cannot be both set, pick one',\n pass: 'ok',\n fail: 'omit one'\n },\n {\n nook: true,\n test: !!apiToken,\n message:\n 'You need to be logged in to use this command. See `socket login`.',\n pass: 'ok',\n fail: 'missing API token'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n await handleThreatFeed({\n direction: String(cli.flags['direction'] || 'desc'),\n ecosystem: String(cli.flags['eco'] || ''),\n filter: String(cli.flags['filter'] || 'mal'),\n outputKind: json ? 'json' : markdown ? 'markdown' : 'text',\n page: String(cli.flags['page'] || '1'),\n perPage: Number(cli.flags['perPage']) || 30\n })\n}\n","import fs from 'node:fs'\n\nimport { codeBlock } from 'common-tags'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nexport function addSocketWrapper(file: string): void {\n return fs.appendFile(\n file,\n 'alias npm=\"socket npm\"\\nalias npx=\"socket npx\"\\n',\n err => {\n if (err) {\n return new Error(`There was an error setting up the alias: ${err}`)\n }\n // TODO: pretty sure you need to source the file or restart\n // any terminal session before changes are reflected.\n logger.log(\n codeBlock`\nThe alias was added to ${file}. Running 'npm install' will now be wrapped in Socket's \"safe npm\" 🎉\nIf you want to disable it at any time, run \\`socket wrapper --disable\\`\n`\n )\n }\n )\n}\n","import fs from 'node:fs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nexport function checkSocketWrapperSetup(file: string): boolean {\n const fileContent = fs.readFileSync(file, 'utf8')\n const linesWithSocketAlias = fileContent\n .split('\\n')\n .filter(\n l => l === 'alias npm=\"socket npm\"' || l === 'alias npx=\"socket npx\"'\n )\n\n if (linesWithSocketAlias.length) {\n logger.log(\n `The Socket npm/npx wrapper is set up in your bash profile (${file})`\n )\n return true\n }\n return false\n}\n","import { existsSync } from 'node:fs'\n\nimport { codeBlock } from 'common-tags'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { confirm } from '@socketsecurity/registry/lib/prompts'\n\nimport { addSocketWrapper } from './add-socket-wrapper'\nimport { checkSocketWrapperSetup } from './check-socket-wrapper-setup'\nimport constants from '../../constants'\n\nexport async function postinstallWrapper() {\n // Lazily access constants.bashRcPath and constants.zshRcPath.\n const { bashRcPath, zshRcPath } = constants\n const socketWrapperEnabled =\n (existsSync(bashRcPath) && checkSocketWrapperSetup(bashRcPath)) ||\n (existsSync(zshRcPath) && checkSocketWrapperSetup(zshRcPath))\n\n if (!socketWrapperEnabled) {\n await installSafeNpm(codeBlock`\n The Socket CLI is now successfully installed! 🎉\n\n To better protect yourself against supply-chain attacks, our \"safe npm\" wrapper can warn you about malicious packages whenever you run 'npm install'.\n\n Do you want to install \"safe npm\" (this will create an alias to the socket-npm command)?`)\n }\n}\n\nasync function installSafeNpm(query: string): Promise<void> {\n logger.log(`\n _____ _ _\n| __|___ ___| |_ ___| |_\n|__ | . | _| '_| -_| _|\n|_____|___|___|_,_|___|_|\n\n`)\n if (\n await confirm({\n message: query,\n default: true\n })\n ) {\n // Lazily access constants.bashRcPath and constants.zshRcPath.\n const { bashRcPath, zshRcPath } = constants\n try {\n if (existsSync(bashRcPath)) {\n addSocketWrapper(bashRcPath)\n }\n if (existsSync(zshRcPath)) {\n addSocketWrapper(zshRcPath)\n }\n } catch (e) {\n throw new Error(\n `There was an issue setting up the alias: ${(e as any)?.['message']}`\n )\n }\n }\n}\n","import fs from 'node:fs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nexport function removeSocketWrapper(file: string): void {\n return fs.readFile(file, 'utf8', function (err, data) {\n if (err) {\n logger.fail('There was an error removing the alias:')\n logger.error(err)\n return\n }\n const linesWithoutSocketAlias = data\n .split('\\n')\n .filter(\n l => l !== 'alias npm=\"socket npm\"' && l !== 'alias npx=\"socket npx\"'\n )\n\n const updatedFileContent = linesWithoutSocketAlias.join('\\n')\n\n fs.writeFile(file, updatedFileContent, function (err) {\n if (err) {\n logger.error(err)\n return\n }\n // TODO: pretty sure you need to source the file or restart\n // any terminal session before changes are reflected.\n logger.log(\n `The alias was removed from ${file}. Running 'npm install' will now run the standard npm command.`\n )\n })\n })\n}\n","import { existsSync } from 'node:fs'\n\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { addSocketWrapper } from './add-socket-wrapper'\nimport { checkSocketWrapperSetup } from './check-socket-wrapper-setup'\nimport { postinstallWrapper } from './postinstall-wrapper'\nimport { removeSocketWrapper } from './remove-socket-wrapper'\nimport constants from '../../constants'\nimport { commonFlags } from '../../flags'\nimport { handleBadInput } from '../../utils/handle-bad-input'\nimport { meowOrExit } from '../../utils/meow-with-subcommands'\nimport { getFlagListOutput } from '../../utils/output-formatting'\n\nimport type { CliCommandConfig } from '../../utils/meow-with-subcommands'\n\nconst { DRY_RUN_BAIL_TEXT } = constants\n\nconst config: CliCommandConfig = {\n commandName: 'wrapper',\n description: 'Enable or disable the Socket npm/npx wrapper',\n hidden: false,\n flags: {\n ...commonFlags,\n enable: {\n type: 'boolean',\n default: false,\n description: 'Enables the Socket npm/npx wrapper'\n },\n disable: {\n type: 'boolean',\n default: false,\n description: 'Disables the Socket npm/npx wrapper'\n }\n },\n help: (command, config) => `\n Usage\n $ ${command} <flag>\n\n Options\n ${getFlagListOutput(config.flags, 6)}\n\n Examples\n $ ${command} --enable\n $ ${command} --disable\n `\n}\n\nexport const cmdWrapper = {\n description: config.description,\n hidden: config.hidden,\n run\n}\n\nasync function run(\n argv: readonly string[],\n importMeta: ImportMeta,\n { parentName }: { parentName: string }\n): Promise<void> {\n // I don't think meow would mess with this but ...\n if (argv[0] === '--postinstall') {\n await postinstallWrapper()\n return\n }\n\n const cli = meowOrExit({\n argv,\n config,\n importMeta,\n parentName\n })\n\n const { disable, enable } = cli.flags\n\n const wasBadInput = handleBadInput(\n {\n test: !!(enable || disable),\n message: 'Must use --enabled or --disable',\n pass: 'ok',\n fail: 'missing'\n },\n {\n nook: true,\n test: !enable || !disable,\n message: 'Do not use both --enable and --disable',\n pass: 'ok',\n fail: 'missing'\n }\n )\n if (wasBadInput) {\n return\n }\n\n if (cli.flags['dryRun']) {\n logger.log(DRY_RUN_BAIL_TEXT)\n return\n }\n\n // Lazily access constants.bashRcPath and constants.zshRcPath.\n const { bashRcPath, zshRcPath } = constants\n if (enable) {\n if (existsSync(bashRcPath) && !checkSocketWrapperSetup(bashRcPath)) {\n addSocketWrapper(bashRcPath)\n }\n if (existsSync(zshRcPath) && !checkSocketWrapperSetup(zshRcPath)) {\n addSocketWrapper(zshRcPath)\n }\n } else {\n if (existsSync(bashRcPath)) {\n removeSocketWrapper(bashRcPath)\n }\n if (existsSync(zshRcPath)) {\n removeSocketWrapper(zshRcPath)\n }\n }\n if (!existsSync(bashRcPath) && !existsSync(zshRcPath)) {\n logger.fail('There was an issue setting up the alias in your bash profile')\n }\n}\n","#!/usr/bin/env node\n\nimport process from 'node:process'\nimport { pathToFileURL } from 'node:url'\n\nimport { messageWithCauses, stackWithCauses } from 'pony-cause'\nimport updateNotifier from 'tiny-updater'\n\nimport { debugLog } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport { cmdAnalytics } from './commands/analytics/cmd-analytics'\nimport { cmdAuditLog } from './commands/audit-log/cmd-audit-log'\nimport { cmdCdxgen } from './commands/cdxgen/cmd-cdxgen'\nimport { cmdCI } from './commands/ci/cmd-ci'\nimport { cmdConfig } from './commands/config/cmd-config'\nimport { cmdScanCreate } from './commands/dependencies/cmd-dependencies'\nimport { cmdDiffScan } from './commands/diff-scan/cmd-diff-scan'\nimport { cmdFix } from './commands/fix/cmd-fix'\nimport { cmdInfo } from './commands/info/cmd-info'\nimport { cmdLogin } from './commands/login/cmd-login'\nimport { cmdLogout } from './commands/logout/cmd-logout'\nimport { cmdManifest } from './commands/manifest/cmd-manifest'\nimport { cmdNpm } from './commands/npm/cmd-npm'\nimport { cmdNpx } from './commands/npx/cmd-npx'\nimport { cmdOops } from './commands/oops/cmd-oops'\nimport { cmdOptimize } from './commands/optimize/cmd-optimize'\nimport { cmdOrganization } from './commands/organization/cmd-organization'\nimport { cmdPackage } from './commands/package/cmd-package'\nimport { cmdRawNpm } from './commands/raw-npm/cmd-raw-npm'\nimport { cmdRawNpx } from './commands/raw-npx/cmd-raw-npx'\nimport { cmdReport } from './commands/report/cmd-report'\nimport { cmdRepos } from './commands/repos/cmd-repos'\nimport { cmdScan } from './commands/scan/cmd-scan'\nimport { cmdThreatFeed } from './commands/threat-feed/cmd-threat-feed'\nimport { cmdWrapper } from './commands/wrapper/cmd-wrapper'\nimport constants from './constants'\nimport { AuthError, InputError, captureException } from './utils/errors'\nimport { failMsgWithBadge } from './utils/fail-msg-with-badge'\nimport { meowWithSubcommands } from './utils/meow-with-subcommands'\n\nconst { SOCKET_CLI_BIN_NAME } = constants\n\n// TODO: Add autocompletion using https://socket.dev/npm/package/omelette\nvoid (async () => {\n await updateNotifier({\n name: SOCKET_CLI_BIN_NAME,\n // The '@rollup/plugin-replace' will replace \"process.env['INLINED_SOCKET_CLI_VERSION']\".\n version: process.env['INLINED_SOCKET_CLI_VERSION']!,\n ttl: 86_400_000 /* 24 hours in milliseconds */\n })\n\n try {\n await meowWithSubcommands(\n {\n cdxgen: cmdCdxgen,\n ci: cmdCI,\n config: cmdConfig,\n fix: cmdFix,\n info: cmdInfo,\n login: cmdLogin,\n logout: cmdLogout,\n npm: cmdNpm,\n npx: cmdNpx,\n oops: cmdOops,\n optimize: cmdOptimize,\n organization: cmdOrganization,\n package: cmdPackage,\n 'raw-npm': cmdRawNpm,\n 'raw-npx': cmdRawNpx,\n report: cmdReport,\n wrapper: cmdWrapper,\n scan: cmdScan,\n 'audit-log': cmdAuditLog,\n repos: cmdRepos,\n dependencies: cmdScanCreate,\n analytics: cmdAnalytics,\n 'diff-scan': cmdDiffScan,\n 'threat-feed': cmdThreatFeed,\n manifest: cmdManifest\n },\n {\n aliases: {},\n argv: process.argv.slice(2),\n name: SOCKET_CLI_BIN_NAME,\n importMeta: { url: `${pathToFileURL(__filename)}` } as ImportMeta\n }\n )\n } catch (e) {\n process.exitCode = 1\n let errorBody: string | undefined\n let errorTitle: string\n let errorMessage = ''\n if (e instanceof AuthError) {\n errorTitle = 'Authentication error'\n errorMessage = e.message\n } else if (e instanceof InputError) {\n errorTitle = 'Invalid input'\n errorMessage = e.message\n errorBody = e.body\n } else if (e instanceof Error) {\n errorTitle = 'Unexpected error'\n errorMessage = messageWithCauses(e)\n errorBody = stackWithCauses(e)\n } else {\n errorTitle = 'Unexpected error with no details'\n }\n logger.error('\\n') // Any-spinner-newline\n logger.fail(failMsgWithBadge(errorTitle, errorMessage))\n if (errorBody) {\n debugLog(`${errorBody}`)\n }\n await captureException(e)\n }\n})()\n"],"names":["status","spinner","process","debugLog","cause","logger","method","headers","Authorization","handleUnsuccessfulApiResponse","mw2","lines","cols","length","cws","body","time","data","rows","screen","label","barWidth","barSpacing","xOffset","maxHeight","barBgColor","formattedData","totalTopAlerts","sortedTopFiveAlerts","top_five_alert_types","formatted","style","line","text","baseline","xLabelPadding","xPadding","wholeNumbersOnly","legend","width","x","y","config","type","default","hidden","description","dryRun","help","shortFlag","silent","json","markdown","all","strict","msg","keyPrefix","padName","REDACTED","__proto__","commandOrAliasName","allowUnknownFlags","autoHelp","configOverrideResult","parentName","DRY_RUN_BAIL_TEXT","commandName","flags","file","repo","scope","run","test","message","pass","fail","nook","assert","filePath","perPage","outputJson","outputMarkdown","page","desc","generated","org","logs","user_email","logType","YARN_LOCK","cleanupPackageLock","result","i","configuration","coerce","author","filter","only","profile","standard","lifecycle","alias","array","key","boolean","argv","defaultOrg","repoName","branch","commit_hash","commit_message","committers","make_default_branch","set_as_pending_head","scanStatus","updateProgress","policyStatus","updateScan","finishedFetching","ok","scan","securityPolicy","version","alerts","healthy","addAlert","options","reportLevel","policy","url","manifest","ecomap","pkgmap","vermap","filemap","keys","value","short","depth","Package","Policy","scanId","success","tmp","branchName","fold","includeLicensePolicy","commitMessage","commitHash","cwd","defaultBranch","interactive","outputKind","pendingHead","pullRequest","readOnly","report","slug","choices","name","updateConfigValue","obj","full","auto","get","list","set","unset","offset","columns","field","limit","orgSlug","fs","showHidden","colors","maxArrayLength","after","before","GITHUB_REF_NAME","stdio","stdout","SOCKET_SECURITY_GITHUB_PAT","auth","_octokitGraphql","authorization","head","state","node_id","number","pullRequestId","workspaceName","base","NPM","path","testScript","consolidate","include","existing","unfixable","upgradable","nothrow","pkgPath","vulnerableVersionRange","unavailableSpecs","editable","dependencies","optionalDependencies","peerDependencies","owner","updatePackageJsonFromNode","saved","testedSpecs","installed","fixedSpecs","error","errored","revertedSpecs","editablePkgJson","failedSpecs","SOCKET_IPC_HANDSHAKE","args","constants","env","spawnPromise","PNPM","agentExecPath","NODE_OPTIONS","ignoreIncompatible","installedSpecs","actualTree","YARN_CLASSIC","semver","onUnknown","agent","agentVersion","maintainedNodeVersions","engines","pkgAgentRange","pkgNodeRange","lockSrc","lockName","lockPath","features","npmBuggyOverrides","pkgRequirements","node","pkgSupports","cmdName","prod","autoPilot","autoMerge","purl","isMultiple","rangeStyle","acc","count","fallbackToUrl","severityCount","pkgVersion","Maintenance","Quality","Vulnerabilities","Object","outputPackageIssuesDetails","includeAllIssues","SOCKET_PUBLIC_API_TOKEN","apiBaseUrl","apiProxy","enforcedOrgs","applyLogout","attemptLogout","buf","resolve","reject","keeping","collecting","arr","out","verbose","stderr","bin","gradleOpts","task","poms","sbtOpts","subArgs","meow","importMeta","conda","scala","gradle","kotlin","aliases","yolo","NPX","overrides","pkgs","pkgid","names","isPlacingHigher","insertIndex","entries","added","addedInWorkspaces","updated","updatedInWorkspaces","warnedPnpmWorkspaceRequiresNpm","workspacePkgJsonPaths","npmExecPath","overridesDataObjects","package","depAliasMap","thisSpec","depObj","newSpec","updateManifestByAgent","NPM_BUGGY_OVERRIDES_PATCHED_VERSION","pin","mw1","mw3","console","security","license","defaultSub","quota","SOCKET_CLI_ISSUES_URL","self","capabilities","score","transitively","selfCaps","valid","purls","components","packageData","License","shallowScore","shallow","deep","meowOrExit","create","view","visibility","repoDescription","homepage","sort","per_page","direction","created_at","del","update","updatedInput","id1","id2","from","year","month","day","fromTime","untilTime","diff","metadata","stream","fg","selectedFg","selectedBg","height","border","columnWidth","columnSpacing","truncate","bottom","content","table","numeric","eco","zshRcPath","enable","disable","SOCKET_CLI_BIN_NAME","cdxgen","ci","fix","info","login","logout","npm","npx","oops","optimize","organization","wrapper","repos","analytics","errorTitle","errorMessage","errorBody"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEO;;AAEP;;ACYO;AAIL;;AACQA;AAAO;AACf;AACE;;AACQC;AAAQ;;AAIhB;AACF;;AAEA;AACAC;AACF;AAEO;AAIL;;;;AAIEC;AACA;AAA2CC;AAAS;AACtD;AACA;AACF;AAEO;;AAEH;AACF;;AAEE;AACF;;AAEE;AACF;;AAEF;AAEO;AACL;;AAEF;;AAEA;AACO;AACL;AAEA;AACE;AACF;AACA;AACA;AACA;AACF;AAEO;AACL;;AAEEC;AAGF;AACA;AAGIC;AACAC;AACEC;AACF;AACF;AAEJ;;ACvFO;AAIL;AACA;AAKA;AACEC;AACF;;AAIA;AACEJ;AACA;AACF;;AAGF;;ACtBO;AAKL;AACA;AAKA;AACEI;AACF;;AAIA;AACEJ;AACA;AACF;;AAGF;;AC/BO;AAKL;AACA;AACA;AACA;AACA;AACA;AACA;;AAEEK;AACF;;;AAIAC;AACA;;AAIA;AACAA;AAEA;AACF;AAEO;AAEL;AACA;AACAC;AAGA;;AAGA;AACE;AAAkBC;;AAChB;AACA;AACAC;AAKF;AACF;;AAGA;;AAEA;;AAGA;AAAkBD;;;AAElB;;AAGA;AACEE;AACA;AAAkBF;;AAChB;AACA;;AAEF;AACAE;AACF;AAEA;AACF;AAEO;AAEL;AACA;AACAH;AAEA;;;;;AAMA;;AAGA;;AAEA;;AAGA;AAAkBC;;;AAElB;;;AAIEE;;;AAGAA;AACF;AAEA;AACF;;AChGuC;;AAmBvC;;AAeA;AACA;AAeO;;;;;AAKLC;AAOF;AACE;;AACQf;AAAQ;AAEhBA;AAEA;;AAKEgB;;;AAGF;;AAEA;;AAEE;AACF;;AAGE;;AAEE;AACF;AAEA;;;AAGIZ;;;AAGAA;AACAA;AACF;AACF;AACEA;AACF;AACF;AACE;;;AAKE;;;AAGIA;;AAEAA;AACF;AACF;AACEA;AACF;AACF;;AAEA;AACF;AACF;AAEA;;;;;AAKI;AACAA;AAGA;AACF;AACF;AAEA;AAKE;AACF;;AAEA;;AAEA;AAqCA;;AAEA;AACA;;AAIA;;AAEA;AACA;AACA;AAEA;AACE;AACA;AACA;AACE;AACF;AACA;AACA;AAAgCa;AAASN;AAASO;AAAO;;;;;;;;;AA2DzD;AACEC;AACAC;AACAC;AACAC;AACAC;AACAC;AACF;AAEAN;;;;AAIEF;AACF;;AAGA;AACAE;AACF;AAEA;;;;AAOE;AACEO;AACF;AAEA;AACE;;AAEE;AACA;AACEC;;AAEAA;AACF;AACF;AACF;AACA;AACE;AACED;AACF;AACF;AAEA;;AAIEE;AACF;;AAGE;AACAC;;AAEJ;AAEA;;;;AAOE;AACEH;AACF;AAEA;AACE;;AAEE;AACA;AACEC;AACF;AACEA;AACF;AACF;AACF;AAEA;AACE;AACA;;AAEE;AACEG;AACF;AACEA;AACF;AACF;AACF;AAEA;;AAIEF;AACF;;AAGE;AACAC;;AAEJ;AAEA;;AAEA;AAEA;AAOE;AACA;AACEE;AAASC;AAAcC;AAAcC;;AACrCC;AACAC;AACAb;AACAc;AACAC;AACEC;;AAEFnB;AACF;AAEAD;AAEA;AACEqB;AACAC;;AAGFT;AACF;;AC9ZA;;AAMA;;AAMO;AACLU;AACEC;AACAC;AACAC;AACAC;;AAEFC;AACEJ;AACAC;AACAC;AAAc;AACdC;;AAEFE;AACEL;AACAC;AACAK;AACAH;;AAEFI;AACEP;AACAC;AACAC;AACAI;AACAH;AACF;AACF;AAEO;AACLK;AACER;AACAM;AACAL;AACAE;;AAEFM;AACET;AACAM;AACAL;AACAE;AACF;AACF;AAEO;AACLO;AACEV;AACAC;AACAE;;AAEFQ;AACEX;AACAC;AACAE;AACF;AACF;;AC9DO;;AAUH;AACF;;AASA;AACE;AACA;AACE;AACF;;;AAGA;AACA;AACAS;AAGA;AACEA;AACF;AACAA;AACF;;;AAIA;AACA;AACA;;AAGA;AACF;;ACzCO;AAGHC;AAAkBC;AAAQ;AAE5B;;;;AAKeA;AAAQ;AAEzB;AAEO;AAGHD;AAAgBC;AAAa;;;AAI/B;AACE;;AAEE;AACF;AACA;;AAOF;AACA;AACF;;ACtBA;;AAAuBC;AAAS;AAiDzB;;;;;;;;AAWL;AAAMC;;;AACN;;AAEA;AACEC;AACF;AAEA;AACE;AACA;;;AAGF;AACA;;AAKIjB;AACAC;AACAC;AAAe;AACfC;;AAGJ;;AAIF;AACA;;AAEA;AACA;AAEU;AAGS;AAAc;AAIvB;AAEsC;AAAS;;AACjCD;AAAO;;;AAGf;AACF;;;AAOd;AACA;;AAEA;AACA;AACA;;;AAIM;;AAEA;AACAgB;AACA;AACA;AACAC;AACF;;AAGF;AACA;AACA;AACA;AACA;;;AAKEC;AAGF;AAEA;AACE;AACA;;AAEF;AACE;AACA;AACA;AACA;AACA;AACA;AAKA;AACE;AACA;;AAEF;AACF;AAEA;;AAEE1D;;AAEA;AACF;;AAEA;AACA;AACE;AACA;;AAIA;;AAEA;AACA;;AAEI2D;AACF;AACF;AACF;;AAEA;AACA;;AAEA;AACA;;AAEE3D;AACF;;AAEA;AACF;;AAEA;AACA;AACA;AACO;;AACc;;;;AAInB2D;AAOF;;;AAIE;;;;;;;AAOEH;;AAEF;AAEA;;AAEA;AACA;;AAEA;AACA;AACF;AAEO;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACAxD;AACF;AAEA;AAIE;AAGIH;;AAEJ;AACA;;AAEA;AAKA;AAaA;AACF;AACA;AACA;AACA;;AAEA;;AC/SA;AAAQ+D;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;AACA;AACAC;AACEzB;AACAM;AACAL;AACAE;;AAGFuB;AACE1B;AACAM;AACAL;AACAE;;AAEFwB;AACE3B;AACAM;AACAL;AACAE;;AAGF9B;AACE2B;AACAM;AACAL;AACAE;AACF;;;AAEgBqB;AAAM;AAC1B;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEO;;;AAGLI;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;;;;;AAE2ChD;;AAE3C;;AAIIwD;AACAC;AACAC;AACAC;AACF;;AAGEF;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEEC;;AAEAH;AAEAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AAEAC;AACAC;AACF;AAEEC;;AAEAH;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEAwE;AACAA;;;;AAKER;;AAEAS;AACF;AACF;AAEA;AACE;AACF;AAEA;;AAEA;;AC/JO;;;;;AAKLC;AAOF;AACE;;AAEA;;AACQ9E;AAAQ;AAEhBA;;AAII;AACA+E;AACA;AACAC;;AAEAtC;AACAuC;;AAEF;AAIF;AACEzE;AACF;;;AAKF;;ACrCA;AAAQiD;AAAS;AAEV;;;;;AAOHqB;AAOF;;;;;;AAQMA;AACF;AAEJ;;;;;AAMMA;AACF;AAEJ;AACF;AAEO;;;;AAMHA;AAMF;AAEA;;AAEE5B;AAEIgC;AACAC;AACAC;;;;AAIAC;AACE;;;;;;;AAOEC;AACF;;;;;;;AAOEA;;;AAGN;;;AAMFlF;;AAIEF;AACF;AACA;AACF;AAEA;AACF;AAEO;;;;AAMH4E;AAMF;;AAGE;;AAUJ;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;;AAGI1E;;AAIEF;AACF;AACA;AACA;AACF;AACF;;AC1JO;;;;;AAKL4E;AAOF;AACE;;;;;AAKES;AACF;;AAEE;AACF;;;;;;AAOET;AACF;AACF;;ACrBA;AAAQd;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACExB;AACEA;AACAM;AACAL;AACAE;;AAEFiC;AACEpC;AACAM;AACAL;AACAE;;AAEFoC;AACEvC;AACAM;AACAL;AACAE;;AAEF;;;AAGFE;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;;;;AAEuCrB;;AACvC;AAEA;;AAGA;;;AAKI8B;AACAC;AACAC;AACF;AAEEC;;AAEAH;AAEAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEA;;;AAGE6E;AACAH;AACAS;AACF;AACF;;ACnHA;;;;;;AAAiDC;AAAU;AAE3D;AAWO;;;;;AAEiB;AAAM9B;;;;;AAO1B;;AAEA;AACE;AACA;;AAEE;AAEE;AACA;;AAKF+B;;AAEJ;AACF;AACA;AAEE;AACA;AAGF;;AAEI;;AAEJ;AACA;AACA;AACErF;AACF;AACF;AAEA;AAGE;;AAEA;;AAEA;AAAa;AAAQ;AAAS;AAC5B;AACE;AACF;;AAEE;AACA;AACAsF;AACF;AACEA;AACF;;;AAGEA;AACF;AACF;AACA;;AAEA;AACA;AACF;;AC/FA;AAEO;;AAEL;AAAkB9E;;;AAEd;AACA;AACE8E;AACAC;AACF;AACED;AACF;AACF;AACF;AACA;AACF;AAEO;;AAEL;AACF;AAEO;AACL;AACF;;ACzBA;AAcA;AAAQ1B;AAAkB;;AAE1B;AACA;AACA;AAEA;AACE4B;AACE;AACA;AACA;AACA;AACA;;AAEFC;AACEC;AACAC;AACAC;AACAC;AACAC;AACAxD;;AAEFC;AACE;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACAwD;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEFC;;;;;;;;;;AAUAC;AACIC;AAAe5D;AAAe;AAC9B4D;AAAgB5D;AAAe;AAC/B4D;AAAe5D;AAAe;AAC9B4D;AAAa5D;AAAe;AAC5B4D;AAAiB5D;AAAe;AAChC4D;AAAa5D;AAAe;AAEhC6D;AAgBE;AACA;AACA;;AAiBJ;AAEA;AACEtC;AACApB;AACAD;AACAsB;AACE;;AAEFnB;AACF;AACA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;AAGnCH;AACA;AACA4C;;;AAGAzC;AACF;;AAEA;AACA;AACE;;AAGF;;AACQnD;AAAsB;AAC9B;AACE;AACA;AACA;;;AAKA;AACF;AAEA;AACER;AACA;AACF;AAEA;;AAEA;;AAGF;;AC7KA;AACO;AACL;AACA;AACEA;AACF;AACE;AACA;AAIA;AACA;AACA;AACEA;;AAIA;AACF;AACA;AACA;AAEA;AACEA;;AAIA;AACF;;AAIA;AACEqG;AACArG;AACF;AACF;;AAGEA;;AAIA;AACF;AAEA;AACF;;AChDO;;;;;;AAaHsG;AAQF;AAEA;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AAEF;AAEEuB;AACAvB;AACA1F;;AAEN;AACA;AACEzC;AAGA2J;AACF;AACE3J;AACF;AACF;AACE;AACEoE;AAEAqF;AAEIC;AACAvB;;AAEF;AAEEuB;AACAvB;AACA1F;;AAEN;AACA;AACEzC;AACA2J;AACF;AACE3J;AACF;AACF;AACF;AACF;AACF;;AC1FO;;AAELmJ;AAIF;AACE;AAEA;AACF;;ACFA;AAAQvF;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;;;AAGFnB;AACF;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAIA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;AAEcZ;;;;;AAMVqB;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEA;AACEkG;;AAEF;AACF;;AC5FO;AAGc;AACnBiD;;AAGEnJ;AACmByI;AAAenD;;AAAe6C;;AAASmB;AAAS;AAErE;AACEtJ;AACAA;;AAEA;AACEA;AACAA;AAGF;AACF;;AAEE;AACEA;AACAA;AAGF;AACF;AACF;;AC5BO;;AAELmJ;AAIF;AACE;AACA;;AAGF;;ACHA;AAAQvF;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;;;AAGFnB;AACF;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAIA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;AAEcZ;;;;;AAMVqB;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEA;AACEkG;;AAEF;AACF;;AClFO;;AAELiD;AAIF;AACE;;;;AAII;;AAEEhB;AACF;AACA;AACEyB;AACF;AACF;AACA5J;AAGMyI;;AAEApG;AACAiH;AACF;AAKN;AACE;AAKAtJ;AACAA;;AAEAA;;AAEE;;AAEEmI;AACF;AACA;;AAIA;AACF;AAC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D;AACE;;AAMF;AACAlJ;AACAA;;;AAEoDkJ;AAAI;AACxD;;AACkDA;AAAI;AACtD;AAAmEA;AAAI;AACvE;AACF;AAEO;;AACqCA;AAAI;AAChD;AAEA;;AAGUgC;;AAAyDhC;AAAI;AACrE;;AAEF;AAEO;;;;AAID+B;AACF;AACA;;AAEF;AACF;;ACjJA;;;AAA2CE;AAA2B;AAQtE;AACA;;;AAGM;AACAC;AACF;AACF;AACA;AACF;AAEA;AACO;;AAEHC;AACEjL;AACE;AACAkL;AACF;AACF;AACF;AACA;AACF;AAEO;AAKL;;;AAEUxK;AAAU;;;AAGhByK;AACAC;AACF;AACAxL;AACA;;AAEF;AACF;AAEO;AACLyL;AACAC;AACuB;AACvB;;;AAIF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEQC;AACF;AAEFzL;AACA;;AAEA;AACA;;AAEYoE;AAAQ;;AAGpB;AACApE;AACA;AACF;AACF;AAEO;AACL;AACA;AACA;AACA;AACE;AACF;;;AAGEgE;;AAEJ;AAOO;;AASGgF;AAAqB0C;AAAc;AACzCpI;;;AAGF;AACA;AACE;AACA;;AAEE;AACF;;AAEA;AACE0F;AACF;AACA;;AAEE;;;;AAIEqC;AACAM;AACAjL;AACF;;;;;AAKE;AACE;;AAOF;AACF;AACAV;AACA;AACF;AACF;AACA;AACF;;ACrIA;;AAAY4L;AAAI;AAMhB;;AAIU5C;AAAoB;AAC1B1F;;;AAGF;AAA4BuI;AAAU;;AAEtC;AACF;AAEO;;;;;;;AASHC;AACoB;;AAItB;;;AAGA;AACA;AACA;AAEA;AACEC;AACAC;AACEC;AACAC;AACAC;;AAEFC;;;AAOF;;;AAGE;AACF;;AAEA;AACA;;AACQC;AAAkB;;AAElB;AAAW;AAAyB;;AAS5C;AAEA;AAAa;AAAS;;;AAEpB;AACEzM;AACA;AACF;;;AAMM;AACA;;AAGJ;AACF;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACE;AACE;AACA;AACA;;AAEE0M;;AAEA;;AAEA;AACA;;;AAIE;AACF;;AAUE;AACEC;AACA3M;AACF;AACA;AACF;;AAIA;;AAIA;AAEI;;AACqC4M;AAAe;AAExD;;AAEA;AACA;AAEA;AACE;AACMC;;AAEN;AAEMC;;AAIN;AACMC;AAA2D;;AAInE;;;;AAIe3I;AAAK;AAEd4I;AAAW5I;;;AAEb;;AAIJ;AACE;AACA;AACF;AAEA6I;AAQA;;;;;AAKA;AACA;AACEC;AACF;AAEA;AACEC;;AAEF;;AAGE;AACA;AAAgC/D;AAAI;AACpCgE;AAEA;AACE;AACED;;AAEF;AACA;AACA;;AAA2ChC;AAAgB;AAC7D;AACA;AACEkC;;;AAGF;;AAEAC;AACAC;AACF;AAEA;AACE;AACA;AAKA;AACA;;AASIzB;AACF;;AAGA;AACA;AACF;AACF;;AAGE;AACE;AACE0B;;AAEF;AACF;AACA;AACE;;AAEF;AACA;AACEC;;AAEE;AACA;AACF;AACF;AACA;AACE;;AAC4BrE;AAAI;AAClC;AACA;AACE;AACEsE;;AAIF;AACF;AACF;AACF;AACF;AACF;AACF;;AAEF;;AClUA;;;;AAIEC;AACF;AAWO;;;AAGHC;;;;AAIF;AAAMlK;;;AACN;AACA;AACA;AACA;AACA;AACA;AACEyH;AACF;AACEA;AACF;AACA;AACA;AACA;;;AAKA;;;;AAIE;;AAGE;;AAEA;;AAEA;;AASA;AACA0C;AAGA;AACA;AAEA;;AAEA;AACA;;;AAOA;;AAEAC;;AAEE;AACF;AACF;AAEF;AACEC;AACE;;;;AAIA;AACF;AACF;AACA;AACF;;ACxGA;;AAAaC;AAAK;AAWX;;;AAIUC;AAAc;AAC7B;;AAEE;;;AAGA;AACF;;AAEEL;;;AAGF;AAAMlK;;;AACN;;;AAIEyH;AACA;AACA2C;;AAEEI;AAGM;;AAEJ;AACA;AAEF;AACF;AACF;AACF;;ACDA;;;;AAA4BF;AAAK;AAOjC;AACE;AACE/B;;AAEF;AACA;AACF;AAEA;;;AAIejM;AAAQ;AAAM0D;;;;;;AAIzByH;AACF;AACA;AACF;AAEO;;;;;;;AASHe;AACoB;;AAGpBiC;AACF;;AAEE;AACF;AAEA;AACEhC;AACAC;AAAWC;AAAgBC;AAAkBC;;AAC7CC;;;AAOF;;AAEE;AACF;;;AAIA;AACA;;AACQC;AAAkB;;AAGxB;AACA;AACA;;;AAWFvM;;AAIA;AAAa;AAAS;;AACpB;AACEF;AACA;AACF;AACA;;AAKM;AACA;;AAGJ;AACF;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACE;AACE;AACA;AAEA;;AAEE0M;;;;AAIE;AACF;;;;AAaA;AACE;AACEC;AACA3M;AACF;AACA;AACF;;AAIA;;AAIA;AAEI;;AACqC4M;AAAe;AAExD;AAGA;AACA;AAGA;AAIA;AACA;AAKA;AACA;;AAIM;AACE;AACA;;;AAGA;AACF;AACF;AAGJ;AACE;;AAIY;AACA;;;AAMM;AACR;;AAIV;AACMC;;AAEN;AAEMC;;AAIN;AACMC;AAA2D;;AAInE;;;;AAIe3I;AAAK;AAEd4I;AAAW5I;;;AAEb;;AAIJ;AACE;AACA;AACF;AAEA;AACEqJ;AACF;AAEA;AAOAvN;AACAA;AACA;;;;AAIA;;AAEEA;AACA;AACF;AAEA;AACEkO;;AAEF;;AAGE;AACAC;AAA4CrO;AAAQ;AACpDoN;AAEA;AACE;AACED;;AAEF;AACA;AACA;;AAA2ChC;AAAgB;AAC7D;AACA;AACEkC;;;AAGF;;AAEAC;AACAC;AACF;AAEArN;AACAA;AACA;;AAEE;AACA;;AAMA;AACA;;AASI4L;AACF;;AAGA;AACA;AACF;AACF;;AAGE;AACE;AACE0B;;AAEF;AACF;AACAC;AACA;AACE;;AAEA;AACAY;;AAEA;AACA;AACA;AACAA;AAA4CrO;AAAQ;AACtD;AACA;AACE;AACE0N;;AAIF;AACF;AACF;AACF;AACF;AACF;AACF;;AAEF;;ACjZO;AAEA;AAGL;;AAEA;AACA;AACE7F;AACF;AACA;AACEA;AACF;AACA;;AAEA;AACA;AACEA;AACF;AACA;;AAEA;AACA;AACF;;ACHA;;;;;;;;;;;;AAYEyG;AACF;AAEO;AAIP;AASA;AACE;AACA;AAA+B9B;;AACjC;AAEA;AAIE;;;AAGI;AACA;AACA;AACA+B;AACE;;AAC6CnF;AAAI;;AAGvD;AACF;;AAEA;AACA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAMA;;;;AAMQ;;AAEF;;AAEJ;AAEA;AAEA;AAIA;AAIM;;AAEE;AACF;;AAEE;AACA;;;;AAIA;AACA;AACA;AACA;AACA;AACF;AACA;AACF;AAQN;AAuDO;AACLA;AACAoF;AACa;;AACqCpF;AAAI;;AAEtD;;AAMiCA;AAAI;AACrC;;AAKqCwD;;AAErC;AACA;AACA;AAIA;AACA;AACA;AACE;AACA;AACA;AACA;;;;AAII6B;AACF;AACF;AACF;AACA;AAMEA;AACF;;AAEEA;;AAEF;AACA;AACA;;AAGEC;AACF;AACA;AACED;AACF;AACA;;AACQE;AAAuB;AAC/B;;AAEA;;AAEA;AACA;AACA;;;;;AAIUC;;AACR;AACA;AACA;AACEC;AACA;AACA;AACA;;;AAGA;AACF;AACA;AACEC;AACA;AACA;AACA;;;AAGA;AACF;AACA;AAGA;AACE;AACA;;AAKE;;;;AAIA;AACF;AACF;AACAC;AAIF;AACEC;AACAC;AACF;AACA;AACA;;AAIA;;AAMA;;;;;;;AAWEC;AAAYC;;;;;;;;;AAQZC;AACEX;AACAY;;AAEFC;AACE;;AAKA;AACAD;AAGF;;AAEJ;AAQO;;AAKHE;;AAEAC;AACF;AACE9L;;;AAGF;;;AAGItD;AAMF;AACF;;;;AAC4BgP;AAAgB;AAC5C;AACA;;AAEEhP;AAMA;AACF;AACA;AACE;AACAA;AAMA;AACF;AACA;AACEA;AAMA;AACF;AACA;AACEA;AAMA;AACF;;;AAQE;AACF;AACA;;;AAGE;AACF;;;AAGE;AACF;AACA;;AAEE;AACF;;AAEEA;AAMA;AACF;AACA;AAIEA;AAMF;AACA;AACF;;ACvdA;;AAAa4N;AAAK;AAEX;;AAEHtK;;AAEF;;AAEE6L;AACAnP;AACF;;AAEE;AACF;;;AAEQqO;AAAM;;AAEZ;AACF;AACE;AACF;AACF;;ACdA;AAAQzK;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;AACAuL;AACE/M;AACAC;AACAE;;AAEF6M;AACEhN;AACAC;AACAE;;AAKF8M;AACEjN;AACAC;AACAE;AACA+M;AACA5M;;AAEF6M;AACEnN;AACAC;AACAE;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEI0B;AACE7B;AACAC;AACAE;;AAEFqJ;AACExJ;AACAC;AACAE;AACF;;AAEFE;AACF;AACA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;AAIES;AACAC;AACAC;AACF;AACA;AACE;AACF;AAEA;AACEtE;AACA;AACF;;AAEA;;AACQJ;AAAQ;AAEhB;;;;;;;AASEkM;AACF;AACF;;ACvHO;;;AAOL;;AACQlM;AAAQ;AAEhBA;AAMA;AAIA;AAKAA;AAEA;AACEQ;AACF;AAEA;AACEA;AACF;AAEA;;;;;;AAUF;;ACnCA;AAAQwL;AAAI;AAEZ;;AAEI;;AAEA;AACF;AACA;AACF;AAEA;;;;AAUYtJ;AAAK;AACb;AACE;AACA;;AAEA;AACEoN;AACE3O;AACA4O;AACF;AACF;AACF;AACA;AACF;AACA;AACA;AACE;AAGIC;AAAoB;AAExB;AACE5P;AACF;;AAEA;AACF;AACF;AAEO;;;AACU6P;AAA2B;;;;AAKxCC;AAOF;;AAGE9P;AACA;AACF;;;AAGF;;AAEA;AACA;AACE;AACEA;AACF;AACA;AACE;AACA+P;AACAC;AACAC;;;AAGFjQ;AACAkQ;AAGAlQ;AACA;;AAEIA;AACF;;AAIAmQ;AACF;AACEnQ;AACF;;;AAKAA;;AAEEA;AACwE4P;;AAE1E;AACE5P;AACuF4P;;AAEzF;;;AAOA;AACE5P;AACF;AACF;;AC7HO;;;;;;AAMLiD;AAQF;;AAOE;;;;;AAMI6M;AACF;;AAGE;;AAEF;AACF;AACF;;ACxCA;AAAQlM;AAAkB;AAE1B;AACEC;AACApB;AACAD;AAAc;AACdsB;AACE;AACA;;;AAGFnB;AACF;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;;;AAE6BV;;;;;AAMzBmB;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACA;AAEA;AAGA;AACEtE;AACA;AACF;AAEA;AACE6D;AACAuM;;;;;AAKF;AACF;;ACtGO;AAMLzG;AACAA;AACAA;AACAA;AACF;;ACIA;AAAQ0G;AAAwB;AAEzB;AAILC;AACAC;AACA;AAEInM;;AAKJ;;AACQxE;AAAQ;;AAIhBA;AAEA;AAEAA;AAEA;AACEI;AACAI;AACF;AAEAJ;AAEA;;AAKI0J;;AAEF;;AAGF;AACE;AACEtF;AAEAqF;AACEC;AACAvB;AACA1F;;AAEJ;AACA;;AAEA;AACF;;;AAIMF;AACF;AAEA;AACA;AACEiO;AACF;AACF;AACF;;AAIA;;;AAGExQ;;AAIEA;AACAA;AAGF;AACF;AACEA;AACF;AACF;;AC3FA;AAAQ4D;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;AACAwM;AACEhO;AACAG;;AAEF8N;AACEjO;AACAG;AACF;;AAEFE;AACF;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;AAEA;AACA;AAEA;AACE3D;AACA;AACF;AAEA;AACE;AAGF;AAEA;AACF;;AC9EO;AACL2J;AACAA;AACAA;AACAA;AACF;;ACFO;;AAEH8G;AACAzQ;;AAEEA;AACAA;AAGF;AACF;AACEA;AACF;AACF;;ACTA;AAAQ4D;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;;;AAGAnB;AACF;AACA;;AAEA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;AAEA;AACE3D;AACA;AACF;AAEA0Q;AACF;;AC7CO;AAQL;;AAEE;AACE1Q;AACF;;;;AAKI;AACA2Q;AACF;AACA9Q;AACE+Q;AACF;;AAEE;AACE5Q;AACF;;AAEF;AACAH;AACE;AACE;AACEG;AACF;AACA6Q;AACF;AACE;AACE7Q;AAGF;AACA4Q;AACF;AACF;AACF;;;AAII1J;AACA9C;AACAxD;;AAEJ;AACF;;AAGE;AACEZ;AACF;AAEA;;AAEIkH;;AAEAtG;;AAEJ;;;;AAKWsG;AAAW9C;AAA0BxD;;AAChD;AACF;;AAGEsG;AACA9C;AACAxD;;;AAGA;;AAEJ;;AAEA;AACO;;;;;;;AAOD;AACA;AACF;AACA;AACE;AACE;AACA;AACF;AACA;AACE;AACA;AACA;AACF;;AAEI;;;AAGE;AACE;AACA;AACA;AACF;AACF;AACF;AACA;AACEkQ;AACF;AACE;AACA;AACF;AACF;AACF;AACE;;;AAGEC;AACF;AACF;AACF;AAEA;AACF;;ACvIO;;AAMH;AAEI7J;AACAtG;;AAEA;AACF;;AAMAZ;AACF;;AAEA;AAEA;AACF;;;AAIEgR;AACAA;AACAA;AAGAA;AACAA;AACAA;AACAA;AACAA;AACA;;AAGEhR;AACF;;AAEA;AACA;AACF;;AAGEA;AACAA;AACF;;AAEA;AACF;;ACrDO;;;AASH;AACF;AACA;AACEA;AACA;AACF;;AAGF;;ACXA;AAAQ4D;AAAkB;AAE1B;AACEC;AACApB;AAEAD;AACAsB;AACE;AACA;AACAkF;AACE1G;AACAG;;AAEFwO;AACE3O;AACAC;AACAE;;AAEFyO;AACE5O;AACAG;AACF;;AAEFE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;AAGEqF;AACAlG;AACAC;AACAkO;AACAC;;;AAIF;AACElR;;;AAGAA;AACAA;;AAEF;;;AAKIoE;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEA;AAOF;;ACnHO;AAOL;;AAEA;;AAEA;;AAEA;;AAGA;AAEA;AAEAA;AACA;AACEA;AAGAA;AAGF;AACEA;;AAEEA;AAGF;AACAA;;AAEEA;AAGF;AACF;;;AAIE;AACA;AACA;AACA;AACA;;AAEA;;;AAIA;AACEA;AACF;;AAKA;AAEA;AACEA;AACAA;;AAEF;AACA;;;AAGE;;AAEEA;AACAA;;AAEF;AACA;AACF;AACAA;AACAA;;AAIIA;AACA;AACF;AAEFA;AACAA;;;;AASA;AACEA;AACAA;;AAEF;AACF;AACF;AAEA;AAME;;AACQJ;AAAQ;;;AAIdA;;AAIE;AACA;AACA;AACA;;AAEF;AACAyE;;;;AACsB2G;AAAO;;;;AACNmG;;AACzB;AACE;AACEvR;AACF;AACEA;AACF;AACF;AACF;;ACxIA;AAAQgE;AAAkB;AAE1B;AACEC;AACApB;AAEAD;AACAsB;AACE;AACAsN;AACE9O;AACAG;;AAEFuG;AACE1G;AACAG;;AAEF4O;AACE/O;AACAC;AACAE;;AAGF6O;AACEhP;AACAC;AACAE;;AAEFyO;AACE5O;AACAG;AACF;;AAEFE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;AAIA;AACE3D;;;;;AAKF;;;AAIA;AACA;AACA;;;AAIImE;AACAC;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEF;AACE;AACF;;;AAE4C0E;;AAE5C;;AAEEhJ;AACAA;;AAEF;;AAGA;;AAKA;AAEA;AACEA;AACA;AACF;AAEA;AAOF;;AC1JO;AAOL;;AACQJ;AAAQ;AAChB;AACA;AAEA;AACEI;AACAA;AACAA;AACA;;AAEF;AACEA;AACAA;AACAA;AACA;;AAEF;;;;AAKE;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAIA;AACEA;AACAA;;AAEF;;;AAGEA;AACA;;AAEEA;AACAA;;AAEF;AACA;AACF;;;AAGEuR;AACA;AACF;AACA;;AAEEvR;AAGA;AACF;AACA;AACA;AACA;;AAEEA;;AAEAA;AACAA;AACF;;AAEEA;AAGAuR;AACAvR;AACA;AACF;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEAuR;AACAvR;AACF;;;;;AAQA;AACEA;AACAA;;AAEF;AACF;AACF;;AC5GA;AAAQ4D;AAAkB;AAE1B;AACEC;AACApB;AAEAD;AACAsB;AACE;AACAsN;AACE9O;AACAC;AACAE;;AAEFuG;AACE1G;AACAG;;AAEFwO;AACE3O;AACAC;AACAE;;AAGFuI;AACE1I;AACAG;;AAEF+O;AACElP;AACAC;AACAE;;AAEFyO;AACE5O;AACAG;AACF;;AAEFE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;AAIA;AACE3D;;;;;AAKF;;;AAIA;AACA;AACA;;;AAIImE;AACAC;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEF;AACE;AACF;;AAGA;AACE8M;AACF;;AAGA;AACEH;AACF;AACA;AACEA;AACF;AAEA;;AAEEjR;AACAA;AACAA;;AAEF;;AAGA;;AAKA;AAEA;AACEA;AACA;AACF;;AAGF;;AC/JA;AAAQ4D;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;AACAkF;AACE1G;AACAG;;AAEFyO;AACE5O;AACAC;AACAE;AACF;AACA;;AAEFE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;AAEA;AAEA;AACE3D;;;;AAIAA;;AAEF;;AAGA;AACEyR;AACF;;;AAKEzR;AACA;AACEyR;AACF;AACAA;AACA;AACEzR;AACA;AACF;AACA;AAAkD2D;AAAW;AAC7D;AACF;;AAGE3D;AACA;AACE;AACAyR;AACF;AACA;AACEzR;AACA;AACF;AACA;AAAmD2D;AAAW;AAC9D;AACF;;AAGA;;;;AAIE3D;AAGA;AACAyR;AACA;AACEzR;AACA;AACF;AACA;AAAkD2D;AAAW;AAC7D;AACF;AAEA;AACE3D;AACA;AACF;;AAEA;AACA0R;AAEF;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AAEMtL;;AAEAuL;AACF;AAEJ;;AChJA;AAAQ/N;AAAkB;;AAE1B;AACA;AACA;AACA;AACA;AACA;AACEC;AACApB;AAEAD;AACAsB;AACE;AACAsN;AACE9O;AACAG;;AAEFuG;AACE1G;AACAG;;AAEF4O;AACE/O;AACAC;AACAE;;AAGF6O;AACEhP;AACAC;AACAE;;AAEFyO;AACE5O;AACAG;AACF;;AAEFE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;AAIA;AACE3D;;;;;AAKF;;;AAIA;AACA;AACA;;;AAIImE;AACAC;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEF;AACE;AACF;;;AAE4C0E;;AAE5C;;AAEEhJ;AACAA;;AAEF;;AAGA;;AAKA;AAEA;AACEA;AACA;AACF;AAEA;AAOF;;AC5JA;AACE6D;AACApB;AACAD;AACAsB;;;AA+BK;;;AAGLI;AACF;AAEA;AAGIP;AAAmC;AAErC;AAEImG;AACA8H;AACAC;AACAC;AACAC;AACF;;AAGEC;AACEC;;AAEEzP;;AAEF;;;;;AAKFkH;AACF;AAEJ;;AC9EA;AAAQkC;AAAI;AAEL;AACL;AACA;AACA;AACF;;ACCA;;AAA2BA;AAAI;AAE/B;AACE/H;;AAEArB;AACAsB;;;AAGAnB;AACF;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;AAGnCH;;;;AAIAG;AACF;AAEA;AACE3D;AACA;AACF;;AAGF;;AC/CA;AAAQkS;AAAI;AAEL;AACL;AACA;AACA;AACF;;ACCA;;AAA2BA;AAAI;AAE/B;AACErO;;AAEArB;AACAsB;;;AAGAnB;AACF;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;AAGnCH;;;;AAIAG;AACF;AAEA;AACE3D;AACA;AACF;;AAGF;;ACzCA;AAAQ4D;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;;;AAGAnB;AACF;AACA;;AAEA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;AAEA;AACE3D;AACA;AACF;AAEA;AACF;;AC3CA;;;;;;AAAyCkO;AAAa;AAEtD;AACE;AACF;AAEA;AACE;AACF;AAEO;;ACdA;;;;;AAKHvB;AACF;AACA;AAGqBrJ;;;AAIGA;;;AAICA;;;AAKfA;;AAAyC;AAGvC;;AACd;;ACxBA;;;;;;;;AAQE4K;AACF;AAEA;AACE;;AAGS5L;AAAkB6P;;AAC7B;;AAEA;AACA;AACA;AACE;;AAES7P;AAAW6P;;AACtB;;AAEA;AACA;AACA;AACE;;AAGS7P;AAAY6P;;AACvB;AAEA;AACE;;AAES7P;AAAW6P;;AACtB;;AAEA;AACA;AACA;AACE;;AAGS7P;AAAkB6P;;AAC7B;;AAEA;AACA;AACA;AACE;;AAGS7P;AAAoB6P;;AAC/B;AAMO;;ACxDP;;;;;;;AAAmDjE;AAAa;AAEhE;AACE;AACA;AACA;AACF;AAEA;AACE;AACA;AACA;AACA;;AAIA;AACF;AAEA;AACE;AACA;AACE;AACA;AACA;AACA;AACA;;AAIJ;AAEA;AACE;AACA;AACA;AACF;AAEA;AACE;AACA;AACE;AACA;AACA;AACA;AACA;;AAIJ;AAEO;;ACzDP;;;;;;AAAyCA;AAAa;AAEtD;;AAEI;AACF;AACA;;AAEEkE;;AAEF;AACE;AACF;AACA;AACA;;;AAAwBC;;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEEC;AACF;AACF;AACA;AACF;AAEA;;AAEI;AACF;AACA;AACA;AACA;;AAEA;AACF;AAEA;;;AAGItH;AAA8DhC;;;;AAGlE;AAEA;;AAEI;AACA;AACA;AACoEA;;;AAGtE;AACF;AAEA;;AAEA;AAEA;AAKE;AACA;;AAEE;AACE;AACF;AACF;;;AAGEgC;AAGI;AACA;;AAEEhC;;;;AAKV;AAEA;;;AAGI;AACAgC;AAKMhC;;;;AAMV;AAEA;;AAKI;AACE;AACA;AACA;AAKMA;AACF;AAEW;;AAGnB;AACF;AAEA;;AAKI;AACA;AACA;AACA;AACA;AACiEA;AAAI;;AAGvE;AACF;AAUO;;AC/JA;;ACQP;;;;;;;;AAQEkF;AACF;AAEA;AASA;AAIE;AAIF;AAEA;;AAKA;AAEA;AAIE;AACF;AAEA;AAKE;AACA;AACE;;AAEE;AACA;;AAEI;AACE;AACAiE;;;AAGA;AACF;AACF;AACF;AACE;AACA9E;AAGQ;AACE;AACA8E;AACF;AACF;AACE;AAAmB;AAE7B;;AAEA;;;AAGA;AACF;;AAC2B;AAAe;AAC1C;AACA;AACF;AACA;AAIE;AACF;AACA;AACA;AACA;;;;;;AAME;AACEI;;AAEF;AACF;AACEA;AACAC;AACF;;AAEE;AACED;AACAC;AACF;AACF;AACA;;AAEA;AACA;AACED;AACAC;AACF;AACA;;;AAGEA;AACF;AACAC;AAEqB;;;AAKvB;AAEA;;AAEA;AAEA;;AAKA;AAEA;;AAEA;AAOO;;ACxHP;;;AAAmBvE;AAAa;AAEhC;AAEO;;;;;;AAUH7B;AACF;;;;;;AAMEf;AACEoH;AACAC;AACAC;AACAC;AACAC;AACAC;AACF;AACF;AAAMzP;;;;AAEN;AACA;AACA;AACA;AAGE;AACA0P;;AAIAhT;AAMF;;;AAIEiT;AACF;;AAKA;AAEArT;AAIA;AACA;AAEA;AAAuD;;AAEnD;AACA;AACAuO;;AAKJ;AACA;AAAyC;AAAQ;;AACvCzE;AAAsBwJ;AAAsB7L;AAAQ;AAC5D;AACA;AACA;AACA;AAAa;;AACX;AAGA;AACE8L;AACF;AACA;AAGA;;AAEE;AACA;AACA;AACA;AACE;AACA;AAEE;AACA;AACAhF;AAGFiF;AACAC;AACA/H;AACA;AACEA;AACF;AACF;AACA6H;AACF;AACF;AACA;AACE;AACA;AACA;AACA;AACA;AAKA;AAE0DH;AAAY;AACtE;AACA;;AAAyD1Q;AAAK;AAC5D;;;AAME;AACA;AACA;;AAEA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACAgR;AACF;AACE;AAGA;AACE;AAGI;AACA;AACA;AACA;AACA;AACAnF;;AAKF;AACEmF;AACF;AACF;AACF;AACEA;AACF;AACF;;AAEEnB;AACA;AACA7G;AACF;AACF;AACF;AACF;AACF;AAEA;AACE;;AAEE;;;;;AAQIA;AACF;AAEF;AAeE;AACEA;AACF;AACF;AACF;AACF;AAEA;;AAIE;;AAAwBhJ;;AACtBiR;AACF;AACA;AACF;AAEA;AACF;;AC5QA;AAAQC;AAAoC;AAQrC;;AAKHrE;;AAEAvP;AACF;AACE0D;;;AAGF;;;AAGA;;;;AAGyC1D;AAAQ;AAC/C;;AAIA;;;AAGAI;AAMAA;AACF;AACA;;AAEA;;AAEA;AACF;;AC/CA;;AAMA;AAEO;AAKL;AACEmP;;AAEAC;AACF;;AAEE;AACF;AACA;;AACQxP;AAAQ;AAEhBA;;;;;AAMEA;AACF;AAEA;AACA;;AAGA;;AACwCuP;;AAA2BvP;AAAQ;AAC3E;;AAIA;;;AAKE;;AAEEI;AAGF;AACF;AACEA;AACF;AACF;;ACxDA;AAAQ4D;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;AACA2P;AACEnR;AACAC;AACAE;;AAEF2M;AACE9M;AACAC;AACAE;AACF;;AAEFE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;AAEA;AAEA;AACE3D;AACA;AACF;;AAOF;;AClEO;AAGL;;AAEA;;AACQJ;AAAQ;AAEhBA;AAEA;AAKAA;AAEA;AACEQ;AACF;;AAGF;;ACnBO;;AAKL;AACA;AAEA;AACE;AAAa;AACXJ;;;;AAMI;AAKJ;AACF;AACA;AAAiB;AACf;AACA;AACA;AACA;;;;AAIA;AACE0T;AACArT;AACAsT;AACF;AACA3T;;AAIAA;;AAMA;;AAIA;;AAIA;AACF;AACA;AAAS;;AAIP;AACA;AACEA;AAGF;AACF;AACF;AACF;;AC1EO;AAGL;;AAEE;AACF;AAEA;AACF;;ACAA;AAAQ4D;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;;;AAGFnB;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;AAEcZ;;AACd;;AAIIwB;AACAJ;AACAC;AAEAC;AACAC;AACF;AAEEC;;AAEAH;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;;AAGF;;AC9EO;AAGL;;AAEA;;AACQJ;AAAQ;AAEhBA;AAEA;AAKAA;AAEA;AACEQ;AACF;;AAGF;;ACtBO;;AAKH;;;AAGA;AACEwT;AAGA;AACF;AAEA5T;AACAA;AACA;AACF;AAEAA;AACAA;AACAA;AACAA;AACAA;AACA;;;;AAMAA;AACAA;AACF;;ACpCO;AAIL;;AAEE;AACF;AAEA;AACF;;ACAA;AAAQ4D;AAAkB;;AAE1B;AACA;AACEC;AACApB;AACAD;AACAsB;AACE;;;AAGFnB;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;AAKA;;AAEA;;AAIIY;;AAEAH;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEEC;;AAEAH;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEA;AAIF;;ACpGO;AAGL;;AAEA;;AACQJ;AAAQ;AAEhBA;AAEA;AAKAA;AAEA;AACEQ;AACF;;AAGF;;ACtBO;;AAKH;;;AAGA;AACEwT;AAGA;AACF;AAEA5T;AACAA;AACA;AACF;AAEAA;AACAA;;AAIAA;AACAA;AAGAA;AACA;;;;AASAA;AACAA;AACF;;AC5CO;AAIL;;AAEE;AACF;AAEA;AACF;;ACAA;AAAQ4D;AAAkB;;AAE1B;AACA;AACEC;AACApB;AACAD;AACAsB;AACE;;;AAGFnB;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;AAKA;;AAEA;;AAIIY;;AAEAH;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEEC;;AAEAH;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEA;AAIF;;ACpGA;AAEO;;AAEL;AACA;AACA;AACA;AACAwC;AACA;AAA8BmB;AAAW;AACvC;AAEIkQ;AACAC;AACF;;;AAIEC;AAAoB;;;AAGtB;AAEJ;AACF;;ACxBO;AAGL;;AAEA;;AACQnU;AAAQ;AAEhBA;AAEA;AAKAA;AAEA;AACEQ;AACF;;AAGF;;ACxBO;;AAKH;;;AAGA;AACEwT;AAGA;AACF;AAEA5T;AACAA;AACA;AACF;;AAGEA;AACAA;;AAEAA;AACA;AACF;;AAGAA;AACF;;AC/BO;AAGL;;AAEE;AACF;AAEA;AACF;;ACAA;AAAQ4D;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;;;AAGFnB;AACF;AACA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;AAIA;;AAIIY;AACAJ;AACAC;AACAC;AACAC;AACF;AAEEC;;AAEAH;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;;AAGF;;ACzEA;AAEO;;AAEL;AACA;AACA;AACA;AACAwC;AACA;AAA8BmB;AAAW;AACvC;AAEIqG;AACAgK;AACArM;AACF;;;AAIEoM;AAAoB;;;AAGtB;AAEJ;AACF;;ACxBA;AAAQE;AAAsB;AAEvB;AACLjU;AAEA;;AAEE;AAGF;;AAEA;;AACQJ;AAAQ;AAEhBA;AAEA;;AAEE0F;AACA1F;;AAEAA;AACA;AACA;AACEI;AACAA;AAGF;AACEA;AAGF;AACA;AACF;AAEA;;;;AAIE;AACF;AAEA;;AAGE;;AAEA;AAGF;AACF;;ACzDO;;AAMH;;;AAGA;AACE4T;;AAIA;AACF;AAEA5T;AACAA;AACAA;AACA;AACF;;;AAIIuP;AACA2E;AACE5M;AACA6M;;AAEAC;;AAEFC;;;;;;AAMED;AACF;AACF;;AAkDApU;AACAA;AACA;;AAIA;AACEA;AAGF;AACAA;AACA;AACEA;AAGF;AACEA;AAGAA;AACAA;AAGF;AACAA;AACA;AACE;AACAA;AAGAA;AACAA;AACAA;AACAA;AAGF;AACEA;AACAA;AACAA;AAGF;AACAA;AACAA;AACAA;AACAA;AACAA;;;;;;;AAOAA;AACAA;AACAA;;AAEEA;AACAA;AACAsU;AACEtU;AACF;AACF;AACEA;AACF;AACAA;AACAA;AACAA;;AAEE;AACEA;AACF;AACEA;AACF;AACAA;AACAA;AAGF;AACEA;AACF;AACAA;AACA;AACEA;AACAA;AACAA;AAGAA;AACAA;AACAA;AACAA;AAGAA;AAGAA;;;;;;;AAOAA;AACAA;AACAA;AACAA;AAGAA;;;;;;;AAOAA;AACAA;AACAA;;AAEEA;AAGAA;AACAmU;AACEnU;AACF;AACF;AACEA;AAGF;AACAA;AACAA;AACAA;;AAEEA;AACAA;;AASF;AACEA;AAGF;AACAA;AACF;AACA;AACF;AAEAA;AAGAA;AACAA;AACF;;AC/PO;AAIL;;AAEE;AACF;AAEA;AACF;;ACbA;AACA;AACA;AACA;AACO;;;;AAOHuU;;AAEA;AACE;;AAEEA;AACA;;AAEA;AACAC;AACF;;AAEA;AACF;AACA;AACED;AACF;AACF;AACE;AACAnC;AAEA;AACE;AACA;AACE;AACAmC;AACA;;AAEAC;AACF;AACEA;AACF;AACF;AAEA;AACED;AACF;AACF;;;AAEgBA;;AAClB;;ACtCA;AAAQ3Q;AAAkB;AAE1B;AACEC;AACApB;AAEAD;AACAsB;AACE;;;AAGFnB;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;AAEcZ;;;AAEd;;;AAEewR;AAAM;;AAIjBpQ;AACA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;AACxCW;AAAeX;AAA6B;AAC5CW;AAAqBX;AAAmC;AACxDW;AAAyBX;AAAuC;AAChEW;AAAmBX;AAAiC;AACpDW;AAAmBX;AAAiC;AACpDW;AAAqBX;;;;AAK7B;;AClDO;;;AAOH;AACF;AAEA;AACF;;ACDA;AAAQ9F;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;AACA;AACAwC;AACE7D;AACAF;AACAD;AACF;;AAEFK;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;;AAEwB2C;;AAExB;;AAEA;;AAII/B;;AAEAH;AACAC;AACAC;AACF;;AAGEF;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AAEAC;AACAC;AACF;AAEEC;;AAEAH;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEA;AAKF;;ACxGA;AAEO;;AAEL;AAA8B2D;AAAW;AACvC;AAEIqR;AACAC;AACAjL;AACAyL;AACAC;AACF;;;;;AAMA;AAEJ;AACF;;ACxBO;AACL;AACA;AAIA;AACA;;AAEE;AACEtR;AAEAqF;AAEI;;;AAGEtB;;;AAGJ;AAEEuB;AACAvB;AACA1F;;AAIN;AACA;AACE;AACF;AACF;AACEzC;AAGF;AACF;;ACzCO;AACL;AACA;AACA;AACEoE;AACAqF;AAEIC;AACAvB;AACA1F;AACF;AAEEiH;AACAvB;AACA1F;;AAIN;AACA;;AAEA;AACF;;ACTA;AAAQmB;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;AACA;AACAyC;AACEjE;AACAM;AACAL;AACAE;;AAEFqG;AACExG;AACAM;AACAL;AACAE;;AAEFsG;AACEzG;AACAM;AACAL;AACAE;;AAEFiE;AACEpE;AACAM;AACAL;AACAE;;AAEFuG;AACE1G;AACAG;;AAEFwG;AACE3G;AACAC;AACAE;;AAGFyG;AACE5G;AACAC;AACAE;;AAGF2G;AACE9G;AACAC;AACAE;;AAGF4G;AACE/G;AACAM;AACAH;;AAEF6G;AACEhH;AACAC;AACAE;;AAGFuB;AACE1B;AACAM;AACAL;AACAE;;AAEF8G;AACEjH;AACAC;AACAE;;AAGFiG;AACEpG;AACAM;AACAL;AACAE;AAEF;;AAEF;AACAE;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;;;;AAOEqF;;;AAGAE;;;;;;;;AAQAR;;AAmBF;;AAEA;AAEA;;AAKA;AACA;AACA;AACA;;AAEA;AACA;;;AAIE;;AAEAiN;AACF;;AAEA;AACA;AACA;AACA;;AAEI;AACA;AACEpL;AACF;AACAoL;AACF;AACF;AAEA;AACE3V;AAGAA;AACAA;AAGAA;AACF;;;AAKImE;AACAC;AACAC;AACAC;AAIF;AAEEH;AACAC;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEEC;;AAEAH;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEF;AACE;AACF;;AAEA;AACA;AACEtE;AACA;AACF;AAEA;AACE2I;;;;;AAKAM;AACAC;;;AAGAE;AACAC;AACAC;AACAhD;;;;AAIF;AACF;;AC7TO;AAIL;;AAEA;;AACQ1G;AAAQ;AAEhBA;AAEA;AAKAA;AAEA;AACEQ;AACF;;AAGF;;ACzBO;AAGLJ;AACF;;ACLO;;;AAMH;AACF;;AAGF;;ACAA;AAAQ4D;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;;;AAGFnB;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;AAEA;;AAEA;AACA;;;AAKIQ;AACAC;AACAC;AACAC;AAIF;;AAGEF;AACAC;AACAC;AACF;AAEEC;;AAEAH;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEA;AACF;;ACzFO;;;AAGLuK;AAKF;AACE;;AAEA;;AACQ3K;AAAQ;AAEhBI;AACAA;AAEAJ;;AAOAA;AAEA;;;AAGE;AACF;AAEA;AAOA;AACF;;ACxCA;AAGO;;;AAKHuJ;AAKF;AAEA;AACA;;AAIA;AACA;AACA;AACA;AACE;;;;;AAKE;AACAnJ;AACAA;AACA;AACF;AAEA;AACEA;AACAwK;AACE;AACExK;AACAA;AACF;AACEA;AACF;AACAA;AACF;AACF;AACE;AACAA;AACAA;AACAA;AACF;AAEA;AACF;;AAGEA;AACAA;AACAA;AACAA;AAGAA;AAGAA;;AAIAA;AACAA;AACAA;;AAIAA;;AAEEsF;AACEtF;AACF;;AAEEA;AACF;AACF;AACAA;;AAEEsF;AACEtF;AACF;;AAEEA;AACF;AACF;AACAA;;AAEEsF;AACEtF;AACF;;AAEEA;AACF;AACF;AACAA;;AAEEsF;AACEtF;AACF;;AAEEA;AACF;AACF;AACAA;;AAEEsF;AACEtF;AACF;;AAEEA;AACF;AACF;AACAA;;AAEAA;AACAA;AAGAA;AACA;AACE;AACE;AACF;AACA;;;AAKA;AACF;AACAA;;AAEAA;AACAA;AAGAA;AACA;AACE;AACE;AACF;AACA;;;AAKA;AACF;AACAA;AAEA;AACF;;AAEA;AACA;;AAEAA;;AAGIyK;AACApC;AACAqC;AACAC;AACF;AAEF3K;AAGAA;AACF;;ACxLO;;;;;;AAMLmJ;AAQF;AACE;;;AAGEoB;AACF;;AAEE;AACF;;;;AAKEpB;AACF;AACF;;ACnBA;AAAQvF;AAAkB;AAE1B;AAGA;AACEC;AACApB;AACAD;AACAsB;AACE;AACA;AACAuE;AACE/F;AACAC;AACAE;;AAGFsB;AACEzB;AACAM;AACAL;AACAE;AAEF;;AAEFE;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAE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ACAC;AACAvN;AACAnI;AACAmB;AACAwU;AAAe;AACfC;AACErU;AACAiU;;AAEFK;AACA;AACA;AACAC;AACAC;AACF;;AAEA;AACA;AACA;AACEC;AACAL;AACAxU;AACAyU;AACErU;AACAiU;;AAEFxV;AACAiW;AAEAtV;AACE6U;AACF;AACF;;AAGErW;AAQAU;AACF;;AAEA;;AAGAE;AACAA;;AAEA;AACAmW;AACE;AACA;AACE;AACA;AACE;;;AAWF;AACF;AACF;;AAIAnW;AACE;;AAEA;AACAd;AACF;AACF;AAEA;AACE;;;AAGE;AAEA;;AAEA;;AASF;AACF;AAEA;AACE;AACA;;AAGEkX;AACAxV;AACF;AAEA;AACA;AACE;AACA;;;AAGA;AACF;;AAEE;AACF;AACE;AACF;AACF;;AClKO;;;;;;AAMLgD;AAQF;AACE;;;;;AAKEA;AACF;;AAEE;AACF;AAEA;AACE1E;AACA;AACF;;AAGEmJ;AACF;AACF;;AC7BA;AAAQvF;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;AACA;AACAY;AACEpC;AACAM;AACAL;AACAE;;AAEFoC;AACEvC;AACAM;AACAL;AACAE;;AAEF8S;AACEjT;AACAM;AACAL;AACAE;;AAEF0U;AACE7U;AACAM;AACAL;AACAE;;AAEFkD;AACErD;AACAM;AACAL;AACAE;AACF;;AAEFE;AACF;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;;;;;AAMnCA;AACF;;;AAEcZ;;AACd;;AAEA;;AAIIwB;;AAEAH;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEEC;;AAEAH;AAEAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;AAEA;;;;;;;AAOA;AACF;;AC3JO;;AAKD;AACE;AACF;AACA;AACA;;AAGN;AACA;AACA;AAEI;AAEJ;;ACpBO;;;;AASHA;AAGA;AACF;AACA;AACF;;ACRO;AACL;;;AACoBoX;AAAU;;;;AAOhC;;AAEA;;AAEA;AACE;AACF;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAGMhT;AACA7B;AACF;AAEA;;;AACoB6U;AAAU;;AAE5B;;AAEA;AACA;;AAEA;;;AAKF;AACF;AACF;;ACrDO;AACL;AACE;AACEpX;AACAA;AACA;AACF;;AAOA;;AAGE;AACEA;AACA;AACF;AACA;AACA;AACAA;AAGF;AACF;AACF;;ACfA;AAAQ4D;AAAkB;AAE1B;AACEC;AACApB;AACAD;AACAsB;AACE;AACAuT;AACE/U;AACAC;AACAE;;AAEF6U;AACEhV;AACAC;AACAE;AACF;;AAEFE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEO;;;AAGLuB;AACF;AAEA;AAGIP;AAAmC;AAErC;AACA;;AAEE;AACF;;;;;AAMEA;AACF;;;AAEiB0T;;;AAIblT;AACAC;AACAC;AACAC;AACF;AAEEC;AACAJ;AACAC;AACAC;AACAC;AACF;AAEF;AACE;AACF;AAEA;AACEtE;AACA;AACF;;AAEA;;;AACoBoX;AAAU;AAC9B;;;AAGE;;;AAGA;AACF;AACE;;AAEA;AACA;;AAEA;AACF;;AAEEpX;AACF;AACF;;AC7EA;AAAQuX;AAAoB;;AAE5B;AACA;AACE;AACE7N;AACA;AACArC;;AAEF;;AAGE;AAEImQ;AACAC;AACApV;AACAqV;AACAC;AACAC;AACAC;AACAC;AACAC;AACAC;AACAC;AACAC;AACAhF;AACA;AACA;AACA3J;AACA4O;AACAhR;AACA;AACAiR;AACA3L;AACA4L;AACA;AACA;AACAxQ;AACF;;;AAIE6B;AACAiI;AAAc/J;AAAoC;AACpD;;;AAIF;AACA;;;AAGE0Q;;AAEF;AACEA;;;AAGF;AACEA;AACAC;AACAC;AACF;AACEF;AACF;AACAtY;;AAEA;AACEF;AACF;;AAEF;AACF","debugId":"ebd126cb-ef92-4c88-84ec-ac65069cdd10"}
|