Skip to content

Commit

Permalink
feat(plugin-commands-audit): show path info in audit output (#5917)
Browse files Browse the repository at this point in the history
close #3073
  • Loading branch information
await-ovo committed Jan 18, 2023
1 parent 6c7ac63 commit 94ef329
Show file tree
Hide file tree
Showing 11 changed files with 2,287 additions and 1,012 deletions.
9 changes: 9 additions & 0 deletions .changeset/eleven-emus-reply.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@pnpm/reviewing.dependencies-hierarchy": minor
"@pnpm/plugin-commands-audit": minor
"@pnpm/audit": minor
"@pnpm/list": minor
"pnpm": minor
---

Show dependency paths info in `pnpm audit` output [#3073](https://github.com/pnpm/pnpm/issues/3073)
1 change: 1 addition & 0 deletions lockfile/audit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@pnpm/error": "workspace:*",
"@pnpm/fetch": "workspace:*",
"@pnpm/fetching-types": "workspace:*",
"@pnpm/list": "workspace:*",
"@pnpm/lockfile-types": "workspace:*",
"@pnpm/lockfile-utils": "workspace:*",
"@pnpm/lockfile-walker": "workspace:*",
Expand Down
66 changes: 65 additions & 1 deletion lockfile/audit/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import path from 'path'
import { PnpmError } from '@pnpm/error'
import { AgentOptions, fetchWithAgent, RetryTimeoutOptions } from '@pnpm/fetch'
import { GetAuthHeader } from '@pnpm/fetching-types'
import { Lockfile } from '@pnpm/lockfile-types'
import { DependenciesField } from '@pnpm/types'
import { lockfileToAuditTree } from './lockfileToAuditTree'
import { AuditReport } from './types'
import { searchForPackages, PackageNode } from '@pnpm/list'

export * from './types'

Expand Down Expand Up @@ -44,7 +46,12 @@ export async function audit (
if (res.status !== 200) {
throw new PnpmError('AUDIT_BAD_RESPONSE', `The audit endpoint (at ${auditUrl}) responded with ${res.status}: ${await res.text()}`)
}
return res.json() as Promise<AuditReport>
const auditReport = await (res.json() as Promise<AuditReport>)
return extendWithDependencyPaths(auditReport, {
lockfile,
lockfileDir: opts.lockfileDir,
include: opts.include,
})
}

function getAuthHeaders (authHeaderValue: string | undefined) {
Expand All @@ -55,6 +62,63 @@ function getAuthHeaders (authHeaderValue: string | undefined) {
return headers
}

async function extendWithDependencyPaths (auditReport: AuditReport, opts: {
lockfile: Lockfile
lockfileDir: string
include?: { [dependenciesField in DependenciesField]: boolean }
}): Promise<AuditReport> {
const { advisories } = auditReport
if (!Object.keys(advisories).length) return auditReport
const projectDirs = Object.keys(opts.lockfile.importers)
.map((importerId) => path.join(opts.lockfileDir, importerId))
const searchOpts = {
lockfileDir: opts.lockfileDir,
depth: Infinity,
include: opts.include,
}
const _searchPackagePaths = searchPackagePaths.bind(null, searchOpts, projectDirs)
for (const { findings, module_name: moduleName } of Object.values(advisories)) {
for (const finding of findings) {
finding.paths = await _searchPackagePaths(`${moduleName}@${finding.version}`)
}
}
return auditReport
}

async function searchPackagePaths (
searchOpts: {
lockfileDir: string
depth: number
include?: { [dependenciesField in DependenciesField]: boolean }
},
projectDirs: string[],
pkg: string
) {
const pkgs = await searchForPackages([pkg], projectDirs, searchOpts)
const paths: string[] = []

for (const pkg of pkgs) {
_walker([
...(pkg.optionalDependencies ?? []),
...(pkg.dependencies ?? []),
...(pkg.devDependencies ?? []),
...(pkg.unsavedDependencies ?? []),
], path.relative(searchOpts.lockfileDir, pkg.path) || '.')
}
return paths

function _walker (packages: PackageNode[], depPath: string) {
for (const pkg of packages) {
const nextDepPath = `${depPath}>${pkg.name}@${pkg.version}`
if (pkg.dependencies?.length) {
_walker(pkg.dependencies, nextDepPath)
} else {
paths.push(nextDepPath)
}
}
}
}

export class AuditEndpointNotExistsError extends PnpmError {
constructor (endpoint: string) {
const message = `The audit endpoint (at ${endpoint}) is doesn't exist.`
Expand Down
3 changes: 3 additions & 0 deletions lockfile/audit/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
{
"path": "../../pkg-manifest/read-project-manifest"
},
{
"path": "../../reviewing/list"
},
{
"path": "../lockfile-file"
},
Expand Down
1 change: 1 addition & 0 deletions lockfile/plugin-commands-audit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"homepage": "https://github.com/pnpm/pnpm/blob/main/lockfile/plugin-commands-audit#readme",
"devDependencies": {
"@pnpm/plugin-commands-audit": "workspace:*",
"@pnpm/plugin-commands-installation": "workspace:*",
"@pnpm/test-fixtures": "workspace:*",
"@types/ramda": "0.28.20",
"@types/zkochan__table": "npm:@types/table@6.0.0",
Expand Down
1 change: 1 addition & 0 deletions lockfile/plugin-commands-audit/src/audit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ ${JSON.stringify(newOverrides, null, 2)}`,
['Package', advisory.module_name],
['Vulnerable versions', advisory.vulnerable_versions],
['Patched versions', advisory.patched_versions],
['Paths', advisory.findings.map(({ paths }) => paths).flat().join('\n\n')],
['More info', advisory.url],
], TABLE_OPTIONS)
}
Expand Down

0 comments on commit 94ef329

Please sign in to comment.