diff --git a/__tests__/proxy-integration.test.ts b/__tests__/proxy-integration.test.ts index a607c4b9a..2f5066dfc 100644 --- a/__tests__/proxy-integration.test.ts +++ b/__tests__/proxy-integration.test.ts @@ -22,8 +22,7 @@ integration('ProxyBuilder', () => { } ] - const cachedMode = true - const builder = new ProxyBuilder(docker, PROXY_IMAGE_NAME, cachedMode) + const builder = new ProxyBuilder(docker, PROXY_IMAGE_NAME) beforeAll(async () => { await ImageService.pull(PROXY_IMAGE_NAME) diff --git a/__tests__/proxy.test.ts b/__tests__/proxy.test.ts index 53776da40..67a332bfc 100644 --- a/__tests__/proxy.test.ts +++ b/__tests__/proxy.test.ts @@ -9,6 +9,7 @@ import {Updater} from '../src/updater' type ProxyTestResources = { container: Container containerRemove: jest.Mock + createContainer: jest.Mock externalNetworkRemove: jest.Mock internalNetworkRemove: jest.Mock proxy: Proxy @@ -20,7 +21,8 @@ const alreadyStoppedError = (): Error => async function buildProxyWithStopError( stopError: Error, containerRemoveError?: Error, - containerRemoveOverride?: jest.Mock + containerRemoveOverride?: jest.Mock, + experiments: object = {} ): Promise { const containerRemove = containerRemoveOverride ?? @@ -48,15 +50,16 @@ async function buildProxyWithStopError( const internalNetwork = { remove: internalNetworkRemove } as unknown as Network + const createContainer = jest.fn().mockResolvedValue(container) const docker = { listNetworks: jest.fn().mockResolvedValue([]), createNetwork: jest .fn() .mockResolvedValueOnce(externalNetwork) .mockResolvedValueOnce(internalNetwork), - createContainer: jest.fn().mockResolvedValue(container) + createContainer } as unknown as Docker - const proxy = await new ProxyBuilder(docker, 'proxy-image', false).run( + const proxy = await new ProxyBuilder(docker, 'proxy-image', experiments).run( 1, 'job-token', 'https://dependabot-api.example.com', @@ -66,6 +69,7 @@ async function buildProxyWithStopError( return { container, containerRemove, + createContainer, externalNetworkRemove, internalNetworkRemove, proxy @@ -107,6 +111,56 @@ function buildUpdaterWithProxy(proxy: Proxy): { } } +describe('Proxy config', () => { + it('forwards experiments without changing their names or values', async () => { + const experiments = { + 'proxy-read-only-git-credentials': true, + disabled: false, + timeout: 30, + mode: 'strict', + configuration: {enabled: true} + } + const storeInput = jest + .spyOn(ContainerService, 'storeInput') + .mockResolvedValue(undefined) + + try { + await buildProxyWithStopError( + alreadyStoppedError(), + undefined, + undefined, + experiments + ) + + expect(storeInput).toHaveBeenCalledWith( + 'config.json', + '/', + expect.anything(), + expect.objectContaining({ + all_credentials: [], + experiments + }) + ) + } finally { + storeInput.mockRestore() + } + }) +}) + +describe('Proxy environment', () => { + it('always enables the proxy cache', async () => { + const {createContainer} = await buildProxyWithStopError( + alreadyStoppedError() + ) + + expect(createContainer).toHaveBeenCalledWith( + expect.objectContaining({ + Env: expect.arrayContaining(['PROXY_CACHE=true']) + }) + ) + }) +}) + describe('Proxy readiness', () => { it('checks readiness inside the proxy container network namespace', async () => { const {container, proxy} = await buildProxyWithStopError( diff --git a/__tests__/updater-builder-integration.test.ts b/__tests__/updater-builder-integration.test.ts index 5f08cdf79..0510dcef8 100644 --- a/__tests__/updater-builder-integration.test.ts +++ b/__tests__/updater-builder-integration.test.ts @@ -39,12 +39,12 @@ integration('UpdaterBuilder', () => { }) it('createUpdaterContainer returns a container only connected to the internal network', async () => { - const cachedMode = true - const proxy = await new ProxyBuilder( - docker, - PROXY_IMAGE_NAME, - cachedMode - ).run(1, dependabotApiUrl, jobToken, credentials) + const proxy = await new ProxyBuilder(docker, PROXY_IMAGE_NAME).run( + 1, + jobToken, + dependabotApiUrl, + credentials + ) await proxy.container.start() const input = {job: details} const params = new JobParameters( @@ -79,12 +79,12 @@ integration('UpdaterBuilder', () => { it('passes through OPENSSL_FORCE_FIPS_MODE when set on host', async () => { process.env.OPENSSL_FORCE_FIPS_MODE = '0' - const cachedMode = true - const proxy = await new ProxyBuilder( - docker, - PROXY_IMAGE_NAME, - cachedMode - ).run(1, dependabotApiUrl, jobToken, credentials) + const proxy = await new ProxyBuilder(docker, PROXY_IMAGE_NAME).run( + 1, + jobToken, + dependabotApiUrl, + credentials + ) await proxy.container.start() const input = {job: details} const params = new JobParameters( @@ -116,12 +116,12 @@ integration('UpdaterBuilder', () => { it('does not set OPENSSL_FORCE_FIPS_MODE when not set on host', async () => { delete process.env.OPENSSL_FORCE_FIPS_MODE - const cachedMode = true - const proxy = await new ProxyBuilder( - docker, - PROXY_IMAGE_NAME, - cachedMode - ).run(1, dependabotApiUrl, jobToken, credentials) + const proxy = await new ProxyBuilder(docker, PROXY_IMAGE_NAME).run( + 1, + jobToken, + dependabotApiUrl, + credentials + ) await proxy.container.start() const input = {job: details} const params = new JobParameters( diff --git a/__tests__/updater.test.ts b/__tests__/updater.test.ts index c401aa99e..f0e9d025c 100644 --- a/__tests__/updater.test.ts +++ b/__tests__/updater.test.ts @@ -78,6 +78,31 @@ describe('Updater', () => { expect(await updater.runUpdater()).toBe(true) }) + it('passes job experiments to the proxy builder', async () => { + const jobDetails = { + ...mockJobDetails, + experiments: { + 'proxy-read-only-git-credentials': true, + 'other-experiment': true + } + } + const updaterWithExperiment = new Updater( + 'MOCK_UPDATER_IMAGE_NAME', + 'MOCK_PROXY_IMAGE_NAME', + mockApiClient, + jobDetails, + [] + ) + + await updaterWithExperiment.runUpdater() + + expect(ProxyBuilder).toHaveBeenCalledWith( + expect.any(Docker), + 'MOCK_PROXY_IMAGE_NAME', + jobDetails.experiments + ) + }) + it('does not start the updater until the proxy is ready', async () => { const {promise, resolve} = Promise.withResolvers() mockProxy.waitUntilReady.mockReturnValueOnce(promise) diff --git a/dist/main.js b/dist/main.js index 01363344d..47ef9240a 100644 --- a/dist/main.js +++ b/dist/main.js @@ -99501,14 +99501,14 @@ var CERT_SUBJECT = [ } ]; var ProxyBuilder = class { - constructor(docker, proxyImage, cachedMode) { + constructor(docker, proxyImage, experiments = {}) { this.docker = docker; this.proxyImage = proxyImage; - this.cachedMode = cachedMode; + this.experiments = experiments; } docker; proxyImage; - cachedMode; + experiments; async run(jobId2, jobToken, dependabotApiUrl, credentials) { const name = `dependabot-job-${jobId2}-proxy`; const config = this.buildProxyConfig(credentials); @@ -99635,7 +99635,11 @@ var ProxyBuilder = class { } buildProxyConfig(credentials) { const ca = this.generateCertificateAuthority(); - const config = { all_credentials: credentials, ca }; + const config = { + all_credentials: credentials, + ca, + experiments: this.experiments + }; return config; } generateCertificateAuthority() { @@ -99696,7 +99700,7 @@ var ProxyBuilder = class { `no_proxy=${process.env.no_proxy || process.env.NO_PROXY || ""}`, `JOB_ID=${jobId2}`, `JOB_TOKEN=${jobToken}`, - `PROXY_CACHE=${this.cachedMode ? "true" : "false"}`, + "PROXY_CACHE=true", `DEPENDABOT_API_URL=${dependabotApiUrl}`, `ACTIONS_ID_TOKEN_REQUEST_TOKEN=${process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN || ""}`, `ACTIONS_ID_TOKEN_REQUEST_URL=${process.env.ACTIONS_ID_TOKEN_REQUEST_URL || ""}`, @@ -99838,14 +99842,11 @@ var Updater = class { * Execute an update job and report the result to Dependabot API. */ async runUpdater() { - const cachedMode = Object.hasOwn( - this.details.experiments ?? {}, - "proxy-cached" - ); + const experiments = this.details.experiments ?? {}; const proxyBuilder = new ProxyBuilder( this.docker, this.proxyImage, - cachedMode + experiments ); const proxy = await proxyBuilder.run( this.apiClient.params.jobId, diff --git a/src/config-types.ts b/src/config-types.ts index b69795c12..a0d275fa8 100644 --- a/src/config-types.ts +++ b/src/config-types.ts @@ -33,4 +33,5 @@ export type CertificateAuthority = { export type ProxyConfig = { all_credentials: Credential[] ca: CertificateAuthority + experiments: object } diff --git a/src/proxy.ts b/src/proxy.ts index af8f8cda6..2c797d96e 100644 --- a/src/proxy.ts +++ b/src/proxy.ts @@ -55,7 +55,7 @@ export class ProxyBuilder { constructor( private readonly docker: Docker, private readonly proxyImage: string, - private readonly cachedMode: boolean + private readonly experiments: object = {} ) {} async run( @@ -213,7 +213,11 @@ export class ProxyBuilder { private buildProxyConfig(credentials: Credential[]): ProxyConfig { const ca = this.generateCertificateAuthority() - const config: ProxyConfig = {all_credentials: credentials, ca} + const config: ProxyConfig = { + all_credentials: credentials, + ca, + experiments: this.experiments + } return config } @@ -292,7 +296,7 @@ export class ProxyBuilder { `no_proxy=${process.env.no_proxy || process.env.NO_PROXY || ''}`, `JOB_ID=${jobId}`, `JOB_TOKEN=${jobToken}`, - `PROXY_CACHE=${this.cachedMode ? 'true' : 'false'}`, + 'PROXY_CACHE=true', `DEPENDABOT_API_URL=${dependabotApiUrl}`, `ACTIONS_ID_TOKEN_REQUEST_TOKEN=${process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN || ''}`, `ACTIONS_ID_TOKEN_REQUEST_URL=${process.env.ACTIONS_ID_TOKEN_REQUEST_URL || ''}`, diff --git a/src/updater.ts b/src/updater.ts index 71f3764f0..06597175b 100644 --- a/src/updater.ts +++ b/src/updater.ts @@ -24,15 +24,12 @@ export class Updater { * Execute an update job and report the result to Dependabot API. */ async runUpdater(): Promise { - const cachedMode = Object.hasOwn( - this.details.experiments ?? {}, - 'proxy-cached' - ) + const experiments = this.details.experiments ?? {} const proxyBuilder = new ProxyBuilder( this.docker, this.proxyImage, - cachedMode + experiments ) const proxy = await proxyBuilder.run(