Release rolling / release (push) Has been cancelled
Private registry credentials were applied while pushing Docker Hub short names. Auto-retag under the credential host and prefix the flattener repo.
109 lines
3.4 KiB
JavaScript
109 lines
3.4 KiB
JavaScript
/**
|
|
* Registry auth resolution — anonymous Docker Hub when no usable creds.
|
|
*/
|
|
import test from 'brittle'
|
|
import {
|
|
isUsableDockerAuth,
|
|
authMatchesImage,
|
|
normalizeRegistryHost,
|
|
registryHostFromImage,
|
|
resolveRegistryAuth,
|
|
registryPrefixFromServeraddress,
|
|
retargetImageRefForRegistry,
|
|
parseImageRepoTag,
|
|
} from '../server/handlers/vault.js'
|
|
|
|
test('isUsableDockerAuth requires username and non-empty password', (t) => {
|
|
t.absent(isUsableDockerAuth(null))
|
|
t.absent(isUsableDockerAuth({}))
|
|
t.absent(isUsableDockerAuth({ username: 'u' }))
|
|
t.absent(isUsableDockerAuth({ username: 'u', password: '' }))
|
|
t.ok(isUsableDockerAuth({ username: 'u', password: 'p' }))
|
|
})
|
|
|
|
test('registryHostFromImage maps short names to docker.io', (t) => {
|
|
t.is(registryHostFromImage('httpd:latest'), 'docker.io')
|
|
t.is(registryHostFromImage('library/httpd'), 'docker.io')
|
|
t.is(registryHostFromImage('user/app:1'), 'docker.io')
|
|
t.is(registryHostFromImage('ghcr.io/org/app:latest'), 'ghcr.io')
|
|
})
|
|
|
|
test('normalizeRegistryHost collapses docker hub aliases', (t) => {
|
|
t.is(normalizeRegistryHost('https://index.docker.io/v1/'), 'docker.io')
|
|
t.is(normalizeRegistryHost('registry-1.docker.io'), 'docker.io')
|
|
t.is(normalizeRegistryHost('ghcr.io'), 'ghcr.io')
|
|
})
|
|
|
|
test('authMatchesImage only applies same-registry session auth', (t) => {
|
|
t.ok(
|
|
authMatchesImage(
|
|
{ serveraddress: 'https://index.docker.io/v1/' },
|
|
'httpd:latest'
|
|
)
|
|
)
|
|
t.absent(
|
|
authMatchesImage({ serveraddress: 'https://ghcr.io' }, 'httpd:latest')
|
|
)
|
|
t.ok(authMatchesImage({ serveraddress: 'https://ghcr.io' }, 'ghcr.io/a/b:1'))
|
|
})
|
|
|
|
test('registryPrefixFromServeraddress strips scheme and api path, keeps port', (t) => {
|
|
t.is(registryPrefixFromServeraddress('https://192.168.0.12:5555/v2/'), '192.168.0.12:5555')
|
|
t.is(registryPrefixFromServeraddress('https://ghcr.io'), 'ghcr.io')
|
|
t.is(registryPrefixFromServeraddress('https://index.docker.io/v1/'), '')
|
|
t.is(
|
|
retargetImageRefForRegistry('apache-httpd:flat-latest', 'https://192.168.0.12:5555/'),
|
|
'192.168.0.12:5555/apache-httpd:flat-latest'
|
|
)
|
|
t.is(
|
|
retargetImageRefForRegistry('ghcr.io/org/app:1', 'https://192.168.0.12:5555/'),
|
|
'ghcr.io/org/app:1'
|
|
)
|
|
t.alike(parseImageRepoTag('192.168.0.12:5555/myapp:flat'), {
|
|
repo: '192.168.0.12:5555/myapp',
|
|
tag: 'flat',
|
|
})
|
|
})
|
|
|
|
test('resolveRegistryAuth returns null without session/vault (anonymous)', (t) => {
|
|
const session = { state: new Map(), id: 'peer1' }
|
|
const auth = resolveRegistryAuth(session, {
|
|
image: 'httpd:latest',
|
|
autoVault: true,
|
|
})
|
|
t.is(auth, null)
|
|
})
|
|
|
|
test('resolveRegistryAuth ignores incomplete session auth', (t) => {
|
|
const session = {
|
|
id: 'peer1',
|
|
state: new Map([
|
|
[
|
|
'registryAuth',
|
|
{ username: 'baduser', password: '', serveraddress: 'https://index.docker.io/v1/' },
|
|
],
|
|
]),
|
|
}
|
|
const auth = resolveRegistryAuth(session, { image: 'httpd:latest' })
|
|
t.is(auth, null)
|
|
})
|
|
|
|
test('resolveRegistryAuth ignores session for different registry host', (t) => {
|
|
const session = {
|
|
id: 'peer1',
|
|
state: new Map([
|
|
[
|
|
'registryAuth',
|
|
{
|
|
username: 'ghuser',
|
|
password: 'secret',
|
|
serveraddress: 'https://ghcr.io',
|
|
},
|
|
],
|
|
]),
|
|
}
|
|
// Pulling Docker Hub while session is logged into GHCR → anonymous for Hub
|
|
const auth = resolveRegistryAuth(session, { image: 'httpd:latest' })
|
|
t.is(auth, null)
|
|
})
|