Files
peardock/test/registry-auth.test.js
T
Raven Scott 8235a8a6c8
Release rolling / release (push) Has been cancelled
Fix flatten push auth by retargeting short names to vault registry
Private registry credentials were applied while pushing Docker Hub short
names. Auto-retag under the credential host and prefix the flattener repo.
2026-07-18 07:46:07 -04:00

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)
})