diff --git a/packages/artifact/__tests__/upload-artifact.test.ts b/packages/artifact/__tests__/upload-artifact.test.ts index b0dca5c8..a893c528 100644 --- a/packages/artifact/__tests__/upload-artifact.test.ts +++ b/packages/artifact/__tests__/upload-artifact.test.ts @@ -352,3 +352,46 @@ describe('upload-artifact', () => { expect(uploadResp).rejects.toThrow() }) }) + +describe('getBlobClientOptions', () => { + afterEach(() => { + delete process.env['HTTPS_PROXY'] + delete process.env['HTTP_PROXY'] + delete process.env['NO_PROXY'] + jest.restoreAllMocks() + }) + + it('should not use proxy settings if not specified', () => { + const opts = blobUpload.getBlobClientOptions('https://blob-storage.local') + expect(opts.proxyOptions).toBeUndefined() + }) + + it('should use https proxy settings from environment', () => { + process.env['HTTPS_PROXY'] = 'https://foo:bar@my-proxy.local' + const opts = blobUpload.getBlobClientOptions('https://blob-storage.local') + expect(opts.proxyOptions).toEqual({ + host: 'my-proxy.local', + port: 443, + username: 'foo', + password: 'bar' + }) + }) + + it('should use http proxy settings from environment', () => { + process.env['HTTP_PROXY'] = 'http://foo:bar@my-proxy.local:1234' + const opts = blobUpload.getBlobClientOptions('http://blob-storage.local') + expect(opts.proxyOptions).toEqual({ + host: 'my-proxy.local', + port: 1234, + username: 'foo', + password: 'bar' + }) + }) + + it('should respect NO_PROXY', () => { + process.env['HTTPS_PROXY'] = 'https://foo:bar@my-proxy.local' + process.env['NO_PROXY'] = 'no-proxy-me.local' + const opts = blobUpload.getBlobClientOptions('https://no-proxy-me.local') + expect(opts.proxyOptions).toBeUndefined() + }) +}) diff --git a/packages/artifact/src/internal/upload/blob-upload.ts b/packages/artifact/src/internal/upload/blob-upload.ts index 87bb7237..b70f9091 100644 --- a/packages/artifact/src/internal/upload/blob-upload.ts +++ b/packages/artifact/src/internal/upload/blob-upload.ts @@ -1,11 +1,18 @@ -import {BlobClient, BlockBlobUploadStreamOptions} from '@azure/storage-blob' +import { + AnonymousCredential, + BlobClient, + BlockBlobUploadStreamOptions, + StoragePipelineOptions +} from '@azure/storage-blob' import {TransferProgressEvent} from '@azure/core-http' import {ZipUploadStream} from './zip' import {getUploadChunkSize, getConcurrency} from '../shared/config' +import {getProxyUrl} from '@actions/http-client' import * as core from '@actions/core' import * as crypto from 'crypto' import * as stream from 'stream' import {NetworkError} from '../shared/errors' +import {getUserAgentString} from '../shared/user-agent' export interface BlobUploadResponse { /** @@ -27,7 +34,12 @@ export async function uploadZipToBlobStorage( const maxConcurrency = getConcurrency() const bufferSize = getUploadChunkSize() - const blobClient = new BlobClient(authenticatedUploadURL) + + const blobClient = new BlobClient( + authenticatedUploadURL, + new AnonymousCredential(), + getBlobClientOptions(authenticatedUploadURL) + ) const blockBlobClient = blobClient.getBlockBlobClient() core.debug( @@ -85,3 +97,37 @@ export async function uploadZipToBlobStorage( sha256Hash } } + +export function getBlobClientOptions(sasURL: string): StoragePipelineOptions { + const options: StoragePipelineOptions = { + userAgentOptions: { + userAgentPrefix: getUserAgentString() + } + } + + const proxyUrl = getProxyUrl(sasURL) + if (proxyUrl !== '') { + const { + port: portString, + hostname: host, + username, + password, + protocol + } = new URL(proxyUrl) + core.debug(`Using proxy server for blob storage upload, host: ${host}`) + + let port = protocol === 'https:' ? 443 : 80 + if (portString !== '') { + port = parseInt(portString) + } + + options.proxyOptions = { + host, + port, + username, + password + } + } + + return options +}