Release rolling / release (push) Successful in 7m47s
Validate port mappings for empty host ports, in-form duplicates, privileged low ports, and peer-side host port conflicts. Runs on template deploy, deploy view, and add-container before create RPC.
111 lines
3.0 KiB
JavaScript
111 lines
3.0 KiB
JavaScript
import test from 'brittle'
|
|
import {
|
|
parsePortMapping,
|
|
validateNetworkingSync,
|
|
precheckDeployNetworking,
|
|
formatNetworkingPrecheckMessage,
|
|
} from '../client/deployNetworkPrecheck.js'
|
|
|
|
test('parsePortMapping host:container/proto', (t) => {
|
|
const p = parsePortMapping('8080:80/tcp', 0)
|
|
t.ok(p)
|
|
t.is(p.hostPort, 8080)
|
|
t.is(p.containerPort, 80)
|
|
t.is(p.protocol, 'tcp')
|
|
t.is(p.incomplete, false)
|
|
})
|
|
|
|
test('parsePortMapping container-only is incomplete', (t) => {
|
|
const p = parsePortMapping('80/tcp', 1)
|
|
t.ok(p)
|
|
t.is(p.hostPort, null)
|
|
t.is(p.containerPort, 80)
|
|
t.is(p.incomplete, true)
|
|
})
|
|
|
|
test('parsePortMapping empty host with colon is incomplete', (t) => {
|
|
// Unusual but guard against blank host field serialization
|
|
const p = parsePortMapping(':443/tcp', 0)
|
|
t.ok(p)
|
|
t.is(p.containerPort, 443)
|
|
t.is(p.incomplete, true)
|
|
})
|
|
|
|
test('validateNetworkingSync rejects empty host ports', (t) => {
|
|
const r = validateNetworkingSync({
|
|
networkMode: 'bridge',
|
|
ports: ['80/tcp', '443/udp'],
|
|
})
|
|
t.not(r.ok === true && r.errors.length === 0)
|
|
t.ok(r.errors.length >= 2)
|
|
t.ok(r.errors.some((e) => /host port is empty/i.test(e)))
|
|
})
|
|
|
|
test('validateNetworkingSync accepts full mappings', (t) => {
|
|
const r = validateNetworkingSync({
|
|
networkMode: 'bridge',
|
|
ports: ['8080:80/tcp', '8443:443/tcp'],
|
|
})
|
|
t.is(r.errors.length, 0)
|
|
t.is(r.parsed.length, 2)
|
|
})
|
|
|
|
test('validateNetworkingSync detects duplicate host ports', (t) => {
|
|
const r = validateNetworkingSync({
|
|
ports: ['8080:80/tcp', '8080:81/tcp'],
|
|
})
|
|
t.ok(r.errors.some((e) => /more than once/i.test(e)))
|
|
})
|
|
|
|
test('validateNetworkingSync warns on privileged ports', (t) => {
|
|
const r = validateNetworkingSync({
|
|
ports: ['80:80/tcp'],
|
|
})
|
|
t.is(r.errors.length, 0)
|
|
t.ok(r.warnings.some((e) => /privileged/i.test(e)))
|
|
})
|
|
|
|
test('validateNetworkingSync host mode warns about ignored mappings', (t) => {
|
|
const r = validateNetworkingSync({
|
|
networkMode: 'host',
|
|
ports: ['8080:80/tcp'],
|
|
})
|
|
t.is(r.errors.length, 0)
|
|
t.ok(r.warnings.some((e) => /host/i.test(e) && /ignored/i.test(e)))
|
|
})
|
|
|
|
test('validateNetworkingSync container mode requires peer container', (t) => {
|
|
const r = validateNetworkingSync({
|
|
networkMode: 'container',
|
|
customNetwork: '',
|
|
ports: [],
|
|
})
|
|
t.ok(r.errors.some((e) => /peer container/i.test(e)))
|
|
})
|
|
|
|
test('precheckDeployNetworking flags used host ports', async (t) => {
|
|
const r = await precheckDeployNetworking(
|
|
{ networkMode: 'bridge', ports: ['8080:80/tcp'] },
|
|
{ usedPorts: [8080, 9000] }
|
|
)
|
|
t.not(r.ok)
|
|
t.ok(r.errors.some((e) => /already published/i.test(e)))
|
|
})
|
|
|
|
test('precheckDeployNetworking ok when free', async (t) => {
|
|
const r = await precheckDeployNetworking(
|
|
{ networkMode: 'bridge', ports: ['8080:80/tcp'] },
|
|
{ usedPorts: [9000] }
|
|
)
|
|
t.ok(r.ok)
|
|
})
|
|
|
|
test('formatNetworkingPrecheckMessage joins errors', (t) => {
|
|
const msg = formatNetworkingPrecheckMessage({
|
|
errors: ['a', 'b'],
|
|
warnings: ['c'],
|
|
})
|
|
t.ok(msg.includes('a'))
|
|
t.ok(msg.includes('b'))
|
|
})
|