From 781ca4b1928957a3d3f0f016e61330859cc4bf07 Mon Sep 17 00:00:00 2001 From: kegato <37505324+kegato@users.noreply.github.com> Date: Mon, 27 Mar 2023 19:07:49 +0200 Subject: [PATCH] feat(datasource/docker): support registry proxy for digest updates (#20777) Co-authored-by: Sebastian Poxhofer --- lib/modules/datasource/docker/index.spec.ts | 73 +++++++++++++++++++++ lib/modules/datasource/docker/index.ts | 48 ++++++++++++-- 2 files changed, 115 insertions(+), 6 deletions(-) diff --git a/lib/modules/datasource/docker/index.spec.ts b/lib/modules/datasource/docker/index.spec.ts index 87f1e53a4d5e80..d3317515d050d0 100644 --- a/lib/modules/datasource/docker/index.spec.ts +++ b/lib/modules/datasource/docker/index.spec.ts @@ -1086,6 +1086,79 @@ describe('modules/datasource/docker/index', () => { ); expect(res).toBeNull(); }); + + it('falls back to library/ prefix on non-namespaced images with existing digest', async () => { + const currentDigest = + 'sha256:0000000000000000000000000000000000000000000000000000000000000000', + newDigest = + 'sha256:1111111111111111111111111111111111111111111111111111111111111111'; + + httpMock + .scope('https://registry.company.com/v2') + .get('/') + .times(4) + .reply(200) + .head(`/some-dep/manifests/${currentDigest}`) + .reply(500) + .head(`/some-dep/manifests/3.17`) + .reply(404) + .head(`/library/some-dep/manifests/${currentDigest}`) + .reply(200, '', { + 'content-type': + 'application/vnd.docker.distribution.manifest.list.v2+json', + 'docker-content-digest': currentDigest, + }) + .head('/library/some-dep/manifests/3.17') + .reply(200, '', { + 'content-type': + 'application/vnd.docker.distribution.manifest.list.v2+json', + 'docker-content-digest': newDigest, + }); + + hostRules.find.mockReturnValue({}); + const res = await getDigest( + { + datasource: 'docker', + packageName: 'some-dep', + currentDigest, + registryUrls: ['https://registry.company.com'], + }, + '3.17' + ); + + expect(res).toBe(newDigest); + }); + + it('falls back to library/ prefix on non-namespaced images without existing digest', async () => { + const newDigest = + 'sha256:1111111111111111111111111111111111111111111111111111111111111111'; + + httpMock + .scope('https://registry.company.com/v2') + .get('/') + .times(2) + .reply(200) + .head(`/some-dep/manifests/3.17`) + .reply(404) + .head('/library/some-dep/manifests/3.17') + .reply(200, '', { + 'content-type': + 'application/vnd.docker.distribution.manifest.list.v2+json', + 'docker-content-digest': newDigest, + }); + + hostRules.find.mockReturnValue({}); + const res = await getDigest( + { + datasource: 'docker', + packageName: 'some-dep', + registryUrls: ['https://registry.company.com'], + }, + '3.17' + ); + + expect(res).toBe(newDigest); + }); }); describe('getReleases', () => { diff --git a/lib/modules/datasource/docker/index.ts b/lib/modules/datasource/docker/index.ts index 43e66d2321d35c..63cd8faf19055f 100644 --- a/lib/modules/datasource/docker/index.ts +++ b/lib/modules/datasource/docker/index.ts @@ -628,12 +628,30 @@ export class DockerDatasource extends Datasource { currentDigest: string ): Promise { try { - const manifestResponse = await this.getManifestResponse( - registryHost, - dockerRepository, - currentDigest, - 'head' - ); + let manifestResponse: HttpResponse | null; + + try { + manifestResponse = await this.getManifestResponse( + registryHost, + dockerRepository, + currentDigest, + 'head' + ); + } catch (_err) { + const err = _err instanceof ExternalHostError ? _err.err : _err; + + if ( + typeof err.statusCode === 'number' && + err.statusCode >= 500 && + err.statusCode < 600 + ) { + // querying the digest manifest for a non existent image leads to a 500 statusCode + return null; + } + + /* istanbul ignore next */ + throw _err; + } if ( manifestResponse?.headers['content-type'] !== @@ -1096,6 +1114,24 @@ export class DockerDatasource extends Datasource { } } + if ( + !manifestResponse && + !dockerRepository.includes('/') && + !packageName.includes('/') + ) { + logger.debug( + `Retrying Digest for ${registryHost}/${dockerRepository} using library/ prefix` + ); + return this.getDigest( + { + registryUrl, + packageName: 'library/' + packageName, + currentDigest, + }, + newValue + ); + } + if (manifestResponse) { // TODO: fix types (#7154) logger.debug(`Got docker digest ${digest!}`);