fix(audit): audit should work with a proxy (#4057)

close #3755
This commit is contained in:
Zoltan Kochan
2021-12-02 15:38:36 +02:00
committed by GitHub
parent 4c175e58fc
commit f1c194dedf
7 changed files with 74 additions and 10 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/audit": minor
---
Added options for the HTTP agent.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/fetch": minor
---
Add `fetchWithAgent()`.

View File

@@ -0,0 +1,5 @@
---
"pnpm": patch
---
`pnpm audit` should work when a proxy is configured for the registry [#3755](https://github.com/pnpm/pnpm/issues/3755).

View File

@@ -1,5 +1,5 @@
import PnpmError from '@pnpm/error'
import fetch, { RetryTimeoutOptions } from '@pnpm/fetch'
import { AgentOptions, fetchWithAgent, RetryTimeoutOptions } from '@pnpm/fetch'
import { Lockfile } from '@pnpm/lockfile-types'
import { DependenciesField } from '@pnpm/types'
import lockfileToAuditTree from './lockfileToAuditTree'
@@ -10,6 +10,7 @@ export * from './types'
export default async function audit (
lockfile: Lockfile,
opts: {
agentOptions?: AgentOptions
include?: { [dependenciesField in DependenciesField]: boolean }
registry: string
retry?: RetryTimeoutOptions
@@ -19,7 +20,8 @@ export default async function audit (
const auditTree = lockfileToAuditTree(lockfile, { include: opts.include })
const registry = opts.registry.endsWith('/') ? opts.registry : `${opts.registry}/`
const auditUrl = `${registry}-/npm/v1/security/audits`
const res = await fetch(auditUrl, {
const res = await fetchWithAgent(auditUrl, {
agentOptions: opts.agentOptions ?? {},
body: JSON.stringify(auditTree),
headers: { 'Content-Type': 'application/json' },
method: 'post',

View File

@@ -1,7 +1,7 @@
import { URL } from 'url'
import { FetchFromRegistry } from '@pnpm/fetching-types'
import npmRegistryAgent, { AgentOptions } from '@pnpm/npm-registry-agent'
import fetch, { isRedirect, Response } from './fetch'
import fetch, { isRedirect, Response, RequestInfo, RequestInit } from './fetch'
const USER_AGENT = 'pnpm' // or maybe make it `${pkg.name}/${pkg.version} (+https://npm.im/${pkg.name})`
@@ -9,6 +9,23 @@ const CORGI_DOC = 'application/vnd.npm.install-v1+json; q=1.0, application/json;
const JSON_DOC = 'application/json'
const MAX_FOLLOWED_REDIRECTS = 20
export type FetchWithAgentOptions = RequestInit & {
agentOptions: AgentOptions
}
export function fetchWithAgent (url: RequestInfo, opts: FetchWithAgentOptions) {
const agent = npmRegistryAgent(url.toString(), {
...opts.agentOptions,
strictSsl: opts.agentOptions.strictSsl ?? true,
} as any) // eslint-disable-line
const headers = opts.headers ?? {}
headers['connection'] = agent ? 'keep-alive' : 'close'
return fetch(url, {
...opts,
agent,
})
}
export { AgentOptions }
export default function (
@@ -31,17 +48,16 @@ export default function (
let urlObject = new URL(url)
const originalHost = urlObject.host
while (true) {
const agent = npmRegistryAgent(urlObject.href, {
const agentOptions = {
...defaultOpts,
...opts,
strictSsl: defaultOpts.strictSsl ?? true,
} as any) // eslint-disable-line
headers['connection'] = agent ? 'keep-alive' : 'close'
} as any // eslint-disable-line
// We should pass a URL object to node-fetch till this is not resolved:
// https://github.com/bitinn/node-fetch/issues/245
const response = await fetch(urlObject, {
agent,
const response = await fetchWithAgent(urlObject, {
agentOptions,
// if verifying integrity, node-fetch must not decompress
compress: opts?.compress ?? false,
headers,

View File

@@ -1,11 +1,12 @@
import { FetchFromRegistry } from '@pnpm/fetching-types'
import fetch, { RetryTimeoutOptions } from './fetch'
import createFetchFromRegistry, { AgentOptions } from './fetchFromRegistry'
import createFetchFromRegistry, { fetchWithAgent, AgentOptions } from './fetchFromRegistry'
export default fetch
export {
AgentOptions,
createFetchFromRegistry,
fetchWithAgent,
FetchFromRegistry,
RetryTimeoutOptions,
}

View File

@@ -106,7 +106,25 @@ export async function handler (
json?: boolean
lockfileDir?: string
registries: Registries
} & Pick<Config, 'fetchRetries' | 'fetchRetryMaxtimeout' | 'fetchRetryMintimeout' | 'fetchRetryFactor' | 'fetchTimeout' | 'production' | 'dev' | 'optional'>
} & Pick<Config, 'ca'
| 'cert'
| 'httpProxy'
| 'httpsProxy'
| 'key'
| 'localAddress'
| 'maxSockets'
| 'noProxy'
| 'strictSsl'
| 'fetchTimeout'
| 'fetchRetries'
| 'fetchRetryMaxtimeout'
| 'fetchRetryMintimeout'
| 'fetchRetryFactor'
| 'fetchTimeout'
| 'production'
| 'dev'
| 'optional'
>
) {
const lockfile = await readWantedLockfile(opts.lockfileDir ?? opts.dir, { ignoreIncompatible: true })
if (lockfile == null) {
@@ -120,6 +138,18 @@ export async function handler (
let auditReport!: AuditReport
try {
auditReport = await audit(lockfile, {
agentOptions: {
ca: opts.ca,
cert: opts.cert,
httpProxy: opts.httpProxy,
httpsProxy: opts.httpsProxy,
key: opts.key,
localAddress: opts.localAddress,
maxSockets: opts.maxSockets,
noProxy: opts.noProxy,
strictSsl: opts.strictSsl,
timeout: opts.fetchTimeout,
},
include,
registry: opts.registries.default,
retry: {