Skip to content

Commit

Permalink
fix(docker): use a HEAD request to the real resource auth. (#14744)
Browse files Browse the repository at this point in the history
  • Loading branch information
vlagorce committed Apr 6, 2022
1 parent 58bec21 commit 3bb6451
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 44 deletions.
129 changes: 92 additions & 37 deletions lib/modules/datasource/docker/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,12 @@ describe('modules/datasource/docker/index', () => {
});
});
describe('getAuthHeaders', () => {
beforeEach(() => {
it('returns "authType token" if both provided', async () => {
httpMock
.scope('https://my.local.registry')
.get('/v2/', undefined, { badheaders: ['authorization'] })
.reply(401, '', { 'www-authenticate': 'Authenticate you must' });
hostRules.hosts.mockReturnValue([]);
});

it('returns "authType token" if both provided', async () => {
hostRules.find.mockReturnValue({
authType: 'some-authType',
token: 'some-token',
Expand All @@ -130,6 +127,11 @@ describe('modules/datasource/docker/index', () => {
});

it('returns "Bearer token" if only token provided', async () => {
httpMock
.scope('https://my.local.registry')
.get('/v2/', undefined, { badheaders: ['authorization'] })
.reply(401, '', { 'www-authenticate': 'Authenticate you must' });
hostRules.hosts.mockReturnValue([]);
hostRules.find.mockReturnValue({
token: 'some-token',
});
Expand All @@ -149,6 +151,11 @@ describe('modules/datasource/docker/index', () => {
});

it('fails', async () => {
httpMock
.scope('https://my.local.registry')
.get('/v2/', undefined, { badheaders: ['authorization'] })
.reply(401, '', { 'www-authenticate': 'Authenticate you must' });
hostRules.hosts.mockReturnValue([]);
httpMock.clear(false);

httpMock
Expand All @@ -164,6 +171,35 @@ describe('modules/datasource/docker/index', () => {

expect(headers).toBeNull();
});

it('use a HEAD request to the real resource and use the auth header values to get a token', async () => {
httpMock
.scope('https://my.local.registry')
.head('/v2/my/node/resource')
.reply(401, '', {
'www-authenticate':
'Bearer realm="https://my.local.registry/oauth2/token",service="my.local.registry",scope="repository:my/node:whatever"',
})
.get(
'/oauth2/token?service=my.local.registry&scope=repository:my/node:whatever'
)
.reply(200, { token: 'some-token' });

const headers = await getAuthHeaders(
http,
'https://my.local.registry',
'my/node/prefix',
'head',
'https://my.local.registry/v2/my/node/resource'
);

// do not inline, otherwise we get false positive from codeql
expect(headers).toMatchInlineSnapshot(`
Object {
"authorization": "Bearer some-token",
}
`);
});
});

describe('getDigest', () => {
Expand Down Expand Up @@ -219,7 +255,7 @@ describe('modules/datasource/docker/index', () => {
.get('/')
.reply(401, '', {
'www-authenticate':
'Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:samalba/my-app:pull "',
'Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:library/some-dep:pull "',
})
.head('/library/some-dep/manifests/latest')
.reply(200, {}, { 'docker-content-digest': 'some-digest' });
Expand All @@ -245,7 +281,7 @@ describe('modules/datasource/docker/index', () => {
.twice()
.reply(401, '', {
'www-authenticate':
'Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:samalba/my-app:pull "',
'Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:library/some-dep:pull "',
})
.head('/library/some-dep/manifests/some-new-value')
.reply(200, undefined, {})
Expand Down Expand Up @@ -493,7 +529,7 @@ describe('modules/datasource/docker/index', () => {
.get('/')
.reply(401, '', {
'www-authenticate':
'Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:samalba/my-app:pull "',
'Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:library/some-other-dep:pull "',
})
.head('/library/some-other-dep/manifests/8.0.0-alpine')
.reply(200, {}, { 'docker-content-digest': 'some-digest' });
Expand Down Expand Up @@ -529,7 +565,7 @@ describe('modules/datasource/docker/index', () => {
it('returns null if no token', async () => {
httpMock
.scope(baseUrl)
.get('/')
.head('/library/node/tags/list?n=10000')
.reply(200, '', {})
.get('/library/node/tags/list?n=10000')
.reply(403);
Expand All @@ -545,7 +581,7 @@ describe('modules/datasource/docker/index', () => {
const tags = ['1.0.0'];
httpMock
.scope('https://registry.company.com/v2')
.get('/')
.head('/node/tags/list?n=10000')
.reply(200, '', {})
.get('/node/tags/list?n=10000')
.reply(
Expand Down Expand Up @@ -576,7 +612,7 @@ describe('modules/datasource/docker/index', () => {
const tags = ['1.0.0'];
httpMock
.scope('https://registry.company.com/v2')
.get('/')
.head('/node/tags/list?n=10000')
.reply(200, '', {})
.get('/node/tags/list?n=10000')
.reply(200, { tags }, {})
Expand Down Expand Up @@ -634,7 +670,7 @@ describe('modules/datasource/docker/index', () => {
it('uses lower tag limit for ECR deps', async () => {
httpMock
.scope(amazonUrl)
.get('/')
.head('/node/tags/list?n=1000')
.reply(200, '', {})
// The tag limit parameter `n` needs to be limited to 1000 for ECR
// See https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_DescribeRepositories.html#ECR-DescribeRepositories-request-maxResults
Expand All @@ -659,7 +695,7 @@ describe('modules/datasource/docker/index', () => {
it('resolves requests to ECR proxy', async () => {
httpMock
.scope('https://ecr-proxy.company.com/v2')
.get('/')
.head('/node/tags/list?n=10000')
.reply(200, '', {})
.get('/node/tags/list?n=10000')
.reply(
Expand Down Expand Up @@ -723,7 +759,7 @@ describe('modules/datasource/docker/index', () => {

httpMock
.scope('https://ecr-proxy.company.com/v2')
.get('/')
.head('/node/tags/list?n=10000')
.reply(200, '', {})
.get('/node/tags/list?n=10000')
.reply(405, maxResultsErrorBody, {
Expand All @@ -744,7 +780,7 @@ describe('modules/datasource/docker/index', () => {
it('returns null when the response code is not 405', async () => {
httpMock
.scope('https://ecr-proxy.company.com/v2')
.get('/')
.head('/node/tags/list?n=10000')
.reply(200, '', {})
.get('/node/tags/list?n=10000')
.reply(
Expand Down Expand Up @@ -775,7 +811,7 @@ describe('modules/datasource/docker/index', () => {
it('returns null when no response headers are present', async () => {
httpMock
.scope('https://ecr-proxy.company.com/v2')
.get('/')
.head('/node/tags/list?n=10000')
.reply(200, '', {})
.get('/node/tags/list?n=10000')
.reply(405, {
Expand All @@ -798,7 +834,7 @@ describe('modules/datasource/docker/index', () => {
it('returns null when the expected docker header is missing', async () => {
httpMock
.scope('https://ecr-proxy.company.com/v2')
.get('/')
.head('/node/tags/list?n=10000')
.reply(200, '', {})
.get('/node/tags/list?n=10000')
.reply(
Expand Down Expand Up @@ -827,7 +863,7 @@ describe('modules/datasource/docker/index', () => {
it('returns null when the response body does not contain an errors object', async () => {
httpMock
.scope('https://ecr-proxy.company.com/v2')
.get('/')
.head('/node/tags/list?n=10000')
.reply(200, '', {})
.get('/node/tags/list?n=10000')
.reply(
Expand All @@ -848,7 +884,7 @@ describe('modules/datasource/docker/index', () => {
it('returns null when the response body does not contain errors', async () => {
httpMock
.scope('https://ecr-proxy.company.com/v2')
.get('/')
.head('/node/tags/list?n=10000')
.reply(200, '', {})
.get('/node/tags/list?n=10000')
.reply(
Expand All @@ -871,7 +907,7 @@ describe('modules/datasource/docker/index', () => {
it('returns null when the the response errors does not have a message property', async () => {
httpMock
.scope('https://ecr-proxy.company.com/v2')
.get('/')
.head('/node/tags/list?n=10000')
.reply(200, '', {})
.get('/node/tags/list?n=10000')
.reply(
Expand All @@ -898,7 +934,7 @@ describe('modules/datasource/docker/index', () => {
it('returns null when the the error message does not have the expected max results error', async () => {
httpMock
.scope('https://ecr-proxy.company.com/v2')
.get('/')
.head('/node/tags/list?n=10000')
.reply(200, '', {})
.get('/node/tags/list?n=10000')
.reply(
Expand Down Expand Up @@ -928,7 +964,7 @@ describe('modules/datasource/docker/index', () => {
const tags = ['1.0.0'];
httpMock
.scope(baseUrl)
.get('/')
.head('/library/node/tags/list?n=10000')
.reply(401, '', {
'www-authenticate':
'Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:library/node:pull "',
Expand Down Expand Up @@ -956,7 +992,7 @@ describe('modules/datasource/docker/index', () => {
const tags = ['1.0.0'];
httpMock
.scope(baseUrl)
.get('/')
.head('/library/node/tags/list?n=10000')
.reply(401, '', {
'www-authenticate':
'Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:library/node:pull "',
Expand Down Expand Up @@ -984,7 +1020,7 @@ describe('modules/datasource/docker/index', () => {
const tags = ['1.0.0'];
httpMock
.scope('https://k8s.gcr.io/v2/')
.get('/')
.head('/kubernetes-dashboard-amd64/tags/list?n=10000')
.reply(401, '', {
'www-authenticate':
'Bearer realm="https://k8s.gcr.io/v2/token",service="k8s.gcr.io"',
Expand All @@ -1009,7 +1045,7 @@ describe('modules/datasource/docker/index', () => {
it('returns null on error', async () => {
httpMock
.scope(baseUrl)
.get('/')
.head('/my/node/tags/list?n=10000')
.reply(200, null)
.get('/my/node/tags/list?n=10000')
.replyWithError('error');
Expand All @@ -1023,7 +1059,7 @@ describe('modules/datasource/docker/index', () => {
it('strips trailing slash from registry', async () => {
httpMock
.scope(baseUrl)
.get('/')
.head('/my/node/tags/list?n=10000')
.reply(401, '', {
'www-authenticate':
'Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:my/node:pull "',
Expand All @@ -1048,9 +1084,12 @@ describe('modules/datasource/docker/index', () => {

it('returns null if no auth', async () => {
hostRules.find.mockReturnValue({});
httpMock.scope(baseUrl).get('/').reply(401, undefined, {
'www-authenticate': 'Basic realm="My Private Docker Registry Server"',
});
httpMock
.scope(baseUrl)
.head('/library/node/tags/list?n=10000')
.reply(401, undefined, {
'www-authenticate': 'Basic realm="My Private Docker Registry Server"',
});
const res = await getPkgReleases({
datasource: DockerDatasource.id,
depName: 'node',
Expand All @@ -1062,7 +1101,9 @@ describe('modules/datasource/docker/index', () => {
httpMock
.scope('https://registry.company.com/v2')
.get('/')
.times(3)
.times(2)
.reply(200)
.head('/node/tags/list?n=10000')
.reply(200)
.get('/node/tags/list?n=10000')
.reply(200, {
Expand Down Expand Up @@ -1125,7 +1166,9 @@ describe('modules/datasource/docker/index', () => {
httpMock
.scope('https://registry.company.com/v2')
.get('/')
.times(4)
.times(3)
.reply(200)
.head('/node/tags/list?n=10000')
.reply(200)
.get('/node/tags/list?n=10000')
.reply(200, { tags: ['abc'] })
Expand Down Expand Up @@ -1165,7 +1208,8 @@ describe('modules/datasource/docker/index', () => {
httpMock
.scope('https://registry.company.com/v2')
.get('/')
.times(2)
.reply(200)
.head('/node/tags/list?n=10000')
.reply(200)
.get('/node/tags/list?n=10000')
.reply(200, { tags: ['latest'] })
Expand All @@ -1189,7 +1233,8 @@ describe('modules/datasource/docker/index', () => {
httpMock
.scope('https://registry.company.com/v2')
.get('/')
.times(2)
.reply(200)
.head('/node/tags/list?n=10000')
.reply(200)
.get('/node/tags/list?n=10000')
.reply(200, { tags: ['latest'] })
Expand All @@ -1212,7 +1257,8 @@ describe('modules/datasource/docker/index', () => {
httpMock
.scope('https://registry.company.com/v2')
.get('/')
.times(2)
.reply(200)
.head('/node/tags/list?n=10000')
.reply(200)
.get('/node/tags/list?n=10000')
.reply(200, { tags: ['latest'] })
Expand All @@ -1232,7 +1278,9 @@ describe('modules/datasource/docker/index', () => {
httpMock
.scope('https://registry.company.com/v2')
.get('/')
.times(4)
.times(3)
.reply(200)
.head('/node/tags/list?n=10000')
.reply(200)
.get('/node/tags/list?n=10000')
.reply(200, { tags: ['1'] })
Expand Down Expand Up @@ -1276,7 +1324,9 @@ describe('modules/datasource/docker/index', () => {
httpMock
.scope('https://registry.company.com/v2')
.get('/')
.times(4)
.times(3)
.reply(200)
.head('/node/tags/list?n=10000')
.reply(200)
.get('/node/tags/list?n=10000')
.reply(200, { tags: ['1'] })
Expand Down Expand Up @@ -1319,7 +1369,8 @@ describe('modules/datasource/docker/index', () => {
httpMock
.scope('https://registry.company.com/v2')
.get('/')
.times(2)
.reply(200)
.head('/node/tags/list?n=10000')
.reply(200)
.get('/node/tags/list?n=10000')
.reply(200, { tags: ['latest'] })
Expand All @@ -1345,7 +1396,11 @@ describe('modules/datasource/docker/index', () => {
badheaders: ['authorization'],
})
.get('/')
.times(3)
.times(2)
.reply(401, '', {
'www-authenticate': 'Basic realm="My Private Docker Registry Server"',
})
.head('/node/tags/list?n=10000')
.reply(401, '', {
'www-authenticate': 'Basic realm="My Private Docker Registry Server"',
});
Expand Down

0 comments on commit 3bb6451

Please sign in to comment.