From 0faced6a0b23ac3f29e6c7277cf990432a8ae112 Mon Sep 17 00:00:00 2001 From: Tatyana Kostromskaya Date: Thu, 5 Oct 2023 16:20:26 +0200 Subject: [PATCH] Add function to return proxy agent dispatcher for compatibility with latest octokit --- packages/core/package-lock.json | 2 +- packages/http-client/__tests__/proxy.test.ts | 12 +- packages/http-client/package-lock.json | 170 +++++++++++++------ packages/http-client/package.json | 9 +- packages/http-client/src/index.ts | 55 ++++++ 5 files changed, 190 insertions(+), 58 deletions(-) diff --git a/packages/core/package-lock.json b/packages/core/package-lock.json index 3acf99cd..d86f7ef0 100644 --- a/packages/core/package-lock.json +++ b/packages/core/package-lock.json @@ -1,6 +1,6 @@ { "name": "@actions/core", - "version": "1.10.0", + "version": "1.10.1", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/packages/http-client/__tests__/proxy.test.ts b/packages/http-client/__tests__/proxy.test.ts index 1a0e28a7..31c1b66e 100644 --- a/packages/http-client/__tests__/proxy.test.ts +++ b/packages/http-client/__tests__/proxy.test.ts @@ -3,6 +3,7 @@ import * as http from 'http' import * as httpm from '../lib/' import * as pm from '../lib/proxy' +import { ProxyAgent } from "undici"; // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports const proxy = require('proxy') @@ -13,7 +14,7 @@ const _proxyUrl = 'http://127.0.0.1:8080' describe('proxy', () => { beforeAll(async () => { // Start proxy server - _proxyServer = proxy() + _proxyServer = proxy.createProxy() await new Promise(resolve => { const port = Number(_proxyUrl.split(':')[2]) _proxyServer.listen(port, () => resolve()) @@ -294,6 +295,15 @@ describe('proxy', () => { expect(agent.proxyOptions.port).toBe('8080') expect(agent.proxyOptions.proxyAuth).toBe('user:password') }) + + it('ProxyAgent is returned when proxy setting are provided', async () => { + process.env['https_proxy'] = 'http://127.0.0.1:8080' + const httpClient = new httpm.HttpClient() + const agent = httpClient.getAgentDispatcher('https://some-url') + // eslint-disable-next-line no-console + console.log(agent) + expect(agent instanceof ProxyAgent).toBe(true) + }) }) function _clearVars(): void { diff --git a/packages/http-client/package-lock.json b/packages/http-client/package-lock.json index 503a680a..8391d4f4 100644 --- a/packages/http-client/package-lock.json +++ b/packages/http-client/package-lock.json @@ -1,27 +1,48 @@ { "name": "@actions/http-client", - "version": "2.1.1", + "version": "3.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@actions/http-client", - "version": "2.1.1", + "version": "3.0.0", "license": "MIT", "dependencies": { "tunnel": "^0.0.6" }, "devDependencies": { + "@types/node": "20.7.1", + "@types/proxy": "^1.0.1", "@types/tunnel": "0.0.3", - "proxy": "^1.0.1" + "proxy": "^2.1.1", + "undici": "^5.25.4" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.0.0.tgz", + "integrity": "sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==", + "dev": true, + "engines": { + "node": ">=14" } }, "node_modules/@types/node": { - "version": "12.12.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.31.tgz", - "integrity": "sha512-T+wnJno8uh27G9c+1T+a1/WYCHzLeDqtsGJkoEdSp2X8RTh3oOCZQcUnjAx90CS8cmmADX51O0FI/tu9s0yssg==", + "version": "20.7.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.7.1.tgz", + "integrity": "sha512-LT+OIXpp2kj4E2S/p91BMe+VgGX2+lfO+XTpfXhh+bCk2LkQtHZSub8ewFBMGP5ClysPjTDFa4sMI8Q3n4T0wg==", "dev": true }, + "node_modules/@types/proxy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/proxy/-/proxy-1.0.2.tgz", + "integrity": "sha512-NDNsg7YuClVzEenn9SUButu43blypWvljGsIkDV7HI4N9apjrS0aeeMTUG0PYa71lD1AvIgvjkBagqHDiomDjA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/tunnel": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.3.tgz", @@ -44,9 +65,9 @@ } }, "node_modules/args": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/args/-/args-5.0.1.tgz", - "integrity": "sha512-1kqmFCFsPffavQFGt8OxJdIcETti99kySRUPMpOhaGjL6mRJn8HFU1OxKY5bMqfZKUwTQc1mZkAjmGYaVOHFtQ==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/args/-/args-5.0.3.tgz", + "integrity": "sha512-h6k/zfFgusnv3i5TU08KQkVKuCPBtL/PWQbWkHUxvJrZ2nAyeaUupneemcrgn1xmqxPQsPIzwkUhOpoqPDRZuA==", "dev": true, "dependencies": { "camelcase": "5.0.0", @@ -59,9 +80,9 @@ } }, "node_modules/basic-auth-parser": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/basic-auth-parser/-/basic-auth-parser-0.0.2.tgz", - "integrity": "sha1-zp5xp38jwSee7NJlmypGJEwVbkE=", + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/basic-auth-parser/-/basic-auth-parser-0.0.2-1.tgz", + "integrity": "sha512-GFj8iVxo9onSU6BnnQvVwqvxh60UcSHJEDnIk3z4B6iOjsKSmqe+ibW0Rsz7YO7IE1HG3D3tqCNIidP46SZVdQ==", "dev": true }, "node_modules/camelcase": { @@ -99,23 +120,30 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { - "ms": "^2.1.1" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "engines": { "node": ">=0.8.0" @@ -124,7 +152,7 @@ "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, "engines": { "node": ">=4" @@ -133,7 +161,7 @@ "node_modules/leven": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "integrity": "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -155,17 +183,17 @@ "dev": true }, "node_modules/proxy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/proxy/-/proxy-1.0.2.tgz", - "integrity": "sha512-KNac2ueWRpjbUh77OAFPZuNdfEqNynm9DD4xHT14CccGpW8wKZwEkN0yjlb7X9G9Z9F55N0Q+1z+WfgAhwYdzQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/proxy/-/proxy-2.1.1.tgz", + "integrity": "sha512-nLgd7zdUAOpB3ZO/xCkU8gy74UER7P0aihU8DkUsDS5ZoFwVCX7u8dy+cv5tVK8UaB/yminU1GiLWE26TKPYpg==", "dev": true, "dependencies": { - "args": "5.0.1", - "basic-auth-parser": "0.0.2", - "debug": "^4.1.1" + "args": "^5.0.3", + "basic-auth-parser": "0.0.2-1", + "debug": "^4.3.4" }, - "bin": { - "proxy": "bin/proxy.js" + "engines": { + "node": ">= 14" } }, "node_modules/supports-color": { @@ -187,15 +215,42 @@ "engines": { "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } + }, + "node_modules/undici": { + "version": "5.25.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.25.4.tgz", + "integrity": "sha512-450yJxT29qKMf3aoudzFpIciqpx6Pji3hEWaXqXmanbXF58LTAGCKxcJjxMXWu3iG+Mudgo3ZUfDB6YDFd/dAw==", + "dev": true, + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } } }, "dependencies": { - "@types/node": { - "version": "12.12.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.31.tgz", - "integrity": "sha512-T+wnJno8uh27G9c+1T+a1/WYCHzLeDqtsGJkoEdSp2X8RTh3oOCZQcUnjAx90CS8cmmADX51O0FI/tu9s0yssg==", + "@fastify/busboy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.0.0.tgz", + "integrity": "sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==", "dev": true }, + "@types/node": { + "version": "20.7.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.7.1.tgz", + "integrity": "sha512-LT+OIXpp2kj4E2S/p91BMe+VgGX2+lfO+XTpfXhh+bCk2LkQtHZSub8ewFBMGP5ClysPjTDFa4sMI8Q3n4T0wg==", + "dev": true + }, + "@types/proxy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/proxy/-/proxy-1.0.2.tgz", + "integrity": "sha512-NDNsg7YuClVzEenn9SUButu43blypWvljGsIkDV7HI4N9apjrS0aeeMTUG0PYa71lD1AvIgvjkBagqHDiomDjA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/tunnel": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.3.tgz", @@ -215,9 +270,9 @@ } }, "args": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/args/-/args-5.0.1.tgz", - "integrity": "sha512-1kqmFCFsPffavQFGt8OxJdIcETti99kySRUPMpOhaGjL6mRJn8HFU1OxKY5bMqfZKUwTQc1mZkAjmGYaVOHFtQ==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/args/-/args-5.0.3.tgz", + "integrity": "sha512-h6k/zfFgusnv3i5TU08KQkVKuCPBtL/PWQbWkHUxvJrZ2nAyeaUupneemcrgn1xmqxPQsPIzwkUhOpoqPDRZuA==", "dev": true, "requires": { "camelcase": "5.0.0", @@ -227,9 +282,9 @@ } }, "basic-auth-parser": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/basic-auth-parser/-/basic-auth-parser-0.0.2.tgz", - "integrity": "sha1-zp5xp38jwSee7NJlmypGJEwVbkE=", + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/basic-auth-parser/-/basic-auth-parser-0.0.2-1.tgz", + "integrity": "sha512-GFj8iVxo9onSU6BnnQvVwqvxh60UcSHJEDnIk3z4B6iOjsKSmqe+ibW0Rsz7YO7IE1HG3D3tqCNIidP46SZVdQ==", "dev": true }, "camelcase": { @@ -261,34 +316,34 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true }, "leven": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "integrity": "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA==", "dev": true }, "mri": { @@ -304,14 +359,14 @@ "dev": true }, "proxy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/proxy/-/proxy-1.0.2.tgz", - "integrity": "sha512-KNac2ueWRpjbUh77OAFPZuNdfEqNynm9DD4xHT14CccGpW8wKZwEkN0yjlb7X9G9Z9F55N0Q+1z+WfgAhwYdzQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/proxy/-/proxy-2.1.1.tgz", + "integrity": "sha512-nLgd7zdUAOpB3ZO/xCkU8gy74UER7P0aihU8DkUsDS5ZoFwVCX7u8dy+cv5tVK8UaB/yminU1GiLWE26TKPYpg==", "dev": true, "requires": { - "args": "5.0.1", - "basic-auth-parser": "0.0.2", - "debug": "^4.1.1" + "args": "^5.0.3", + "basic-auth-parser": "0.0.2-1", + "debug": "^4.3.4" } }, "supports-color": { @@ -327,6 +382,15 @@ "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" + }, + "undici": { + "version": "5.25.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.25.4.tgz", + "integrity": "sha512-450yJxT29qKMf3aoudzFpIciqpx6Pji3hEWaXqXmanbXF58LTAGCKxcJjxMXWu3iG+Mudgo3ZUfDB6YDFd/dAw==", + "dev": true, + "requires": { + "@fastify/busboy": "^2.0.0" + } } } } diff --git a/packages/http-client/package.json b/packages/http-client/package.json index f0c747bd..4f88f1f9 100644 --- a/packages/http-client/package.json +++ b/packages/http-client/package.json @@ -1,6 +1,6 @@ { "name": "@actions/http-client", - "version": "2.1.1", + "version": "3.0.0", "description": "Actions Http Client", "keywords": [ "github", @@ -39,10 +39,13 @@ "url": "https://github.com/actions/toolkit/issues" }, "devDependencies": { + "@types/node": "20.7.1", "@types/tunnel": "0.0.3", - "proxy": "^1.0.1" + "proxy": "^2.1.1", + "undici": "^5.25.4", + "@types/proxy": "^1.0.1" }, "dependencies": { "tunnel": "^0.0.6" } -} \ No newline at end of file +} diff --git a/packages/http-client/src/index.ts b/packages/http-client/src/index.ts index a63e61b7..8deb83a3 100644 --- a/packages/http-client/src/index.ts +++ b/packages/http-client/src/index.ts @@ -6,6 +6,7 @@ import * as ifm from './interfaces' import * as net from 'net' import * as pm from './proxy' import * as tunnel from 'tunnel' +import { ProxyAgent } from "undici"; export enum HttpCodes { OK = 200, @@ -137,6 +138,7 @@ export class HttpClient { private _maxRetries = 1 private _agent: any private _proxyAgent: any + private _proxyAgentDispatcher: any private _keepAlive = false private _disposed = false @@ -564,6 +566,17 @@ export class HttpClient { return this._getAgent(parsedUrl) } + getAgentDispatcher(serverUrl: string): ProxyAgent | undefined { + const parsedUrl = new URL(serverUrl) + const proxyUrl = pm.getProxyUrl(parsedUrl) + const useProxy = proxyUrl && proxyUrl.hostname + if (!useProxy) { + return; + } + + return this._getProxyAgentDispatcher(parsedUrl, proxyUrl) + } + private _prepareRequest( method: string, requestUrl: URL, @@ -701,6 +714,48 @@ export class HttpClient { return agent } + private _getProxyAgentDispatcher(parsedUrl: URL, proxyUrl: URL): ProxyAgent { + let proxyAgent; + + if (this._keepAlive) { + proxyAgent = this._proxyAgentDispatcher + } + + // if agent is already assigned use that agent. + if (proxyAgent) { + return proxyAgent + } + + const usingSsl = parsedUrl.protocol === 'https:' + let maxSockets = 100 + if (this.requestOptions) { + maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets + } + + // This is `useProxy` again, but we need to check `proxyURl` directly for TypeScripts's flow analysis. + if (proxyUrl && proxyUrl.hostname) { + proxyAgent = new ProxyAgent({ + uri: proxyUrl.href, + pipelining: (!this._keepAlive ? 0 : 1), + ...((proxyUrl.username || proxyUrl.password) && { + token: `${proxyUrl.username}:${proxyUrl.password}` + }), + }) + this._proxyAgentDispatcher = proxyAgent + } + + if (usingSsl && this._ignoreSslError) { + // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process + // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options + // we have to cast it to any and change it directly + proxyAgent.options = Object.assign(proxyAgent.options.requestTls || {}, { + rejectUnauthorized: false + }) + } + + return proxyAgent + } + private async _performExponentialBackoff(retryNumber: number): Promise { retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber) const ms: number = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber)