import assert from 'node:assert/strict'
import { spawn } from 'node:child_process'
import { createServer } from 'node:http'
import { mkdtemp, symlink } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import test from 'node:test'
import { verifyDshWebReady } from '../../control-plane/hooks/dsh-web-ready.mjs'
async function fixture(routes) {
const requests = new Map()
const server = createServer((request, response) => {
requests.set(request.url, (requests.get(request.url) ?? 0) + 1)
const configured = routes.get(`${request.method} ${request.url}`) ?? routes.get(request.url)
const route = typeof configured === 'function' ? configured(requests.get(request.url)) : configured
response.writeHead(route?.status ?? 404, {
'content-type': route?.type ?? 'text/plain',
...route?.headers,
})
response.end(route?.body ?? '')
})
await new Promise(resolve => server.listen(0, '127.0.0.1', resolve))
return { server, port: server.address().port, requests }
}
test('DSH web readiness requires every boot manifest Plugin bundle', async () => {
const manifest = JSON.stringify({ rev: 'one', entries: [
{ id: 'one', url: '/plugins/one/client.js?rev=one', rev: 'one' },
{ id: 'two', url: '/plugins/two/client.js?rev=two', rev: 'two' },
] })
const routes = new Map([
['/', { status: 200, type: 'text/html', body: `` }],
['/plugins/one/client.js?rev=one', { status: 200, type: 'text/javascript', body: 'one' }],
['/plugins/two/client.js?rev=two', { status: 404 }],
['POST /api/pluginInventory/list', { status: 200, type: 'application/json', body: JSON.stringify({
type: 'server-response',
rpcId: 'dsh-platform-readiness',
result: { ok: true, value: { entries: [{ moduleName: 'ready', enabled: true, fiberPhase: 'active' }] } },
}) }],
])
const context = await fixture(routes)
try {
await assert.rejects(verifyDshWebReady({ port: context.port, managedReady: async () => {} }), /returned HTTP 404/)
routes.set('/plugins/two/client.js?rev=two', { status: 200, type: 'text/javascript', body: 'two' })
await verifyDshWebReady({ port: context.port, managedReady: async () => {} })
assert.equal(context.requests.get('/'), 3)
assert.equal(context.requests.get('/plugins/one/client.js?rev=one'), 3)
assert.equal(context.requests.get('/plugins/two/client.js?rev=two'), 3)
assert.equal(context.requests.get('/api/pluginInventory/list'), 2)
} finally {
await new Promise(resolve => context.server.close(resolve))
}
})
test('DSH web readiness verifies 0.1.5 initial combo batches', async () => {
const entryUrl = '/plugins/??one/client.js&rev=entry-one'
const batchUrl = '/plugins/??one/client.js,two/client.js&rev=batch-one'
const manifest = JSON.stringify({
rev: 'graph-one',
entries: [{ id: 'one', url: entryUrl, rev: 'entry-one' }],
batches: [{ phase: 'application', url: batchUrl, rev: 'batch-one', entries: ['one', 'two'] }],
})
const routes = new Map([
['/', { status: 200, type: 'text/html', body: `` }],
[entryUrl, { status: 200, type: 'text/javascript', body: 'one' }],
[batchUrl, { status: 404 }],
['POST /api/pluginInventory/list', { status: 200, type: 'application/json', body: JSON.stringify({
type: 'server-response',
rpcId: 'dsh-platform-readiness',
result: { ok: true, value: { entries: [{ moduleName: 'ready', enabled: true, fiberPhase: 'active' }] } },
}) }],
])
const context = await fixture(routes)
try {
await assert.rejects(
verifyDshWebReady({ port: context.port, managedReady: async () => ({}) }),
/returned HTTP 404/,
)
routes.set(batchUrl, { status: 200, type: 'text/javascript', body: 'one and two' })
await verifyDshWebReady({ port: context.port, managedReady: async () => ({}) })
assert.equal(context.requests.get(entryUrl), 3)
assert.equal(context.requests.get(batchUrl), 3)
} finally {
await new Promise(resolve => context.server.close(resolve))
}
})
test('DSH web readiness rejects a malformed combo batch contract', async () => {
const manifest = JSON.stringify({
rev: 'graph-one',
entries: [{ id: 'one', url: '/plugins/one/client.js?rev=one', rev: 'one' }],
batches: { phase: 'application', url: '/plugins/??one/client.js&rev=one' },
})
const context = await fixture(new Map([
['/', { status: 200, type: 'text/html', body: `` }],
]))
try {
await assert.rejects(
verifyDshWebReady({ port: context.port, managedReady: async () => ({}) }),
/boot manifest batches are invalid/,
)
} finally {
await new Promise(resolve => context.server.close(resolve))
}
})
test('DSH web readiness exchanges the private launch token for an authenticated cookie', async () => {
const manifest = JSON.stringify({ rev: 'one', entries: [
{ id: 'one', url: '/plugins/one/client.js?rev=one', rev: 'one' },
] })
let expectedCookie = ''
const routes = new Map([
['/?token=fixture-token', {
status: 303,
headers: { location: '/', 'set-cookie': 'dsh-auth-fixture=session; Path=/; HttpOnly; SameSite=Strict' },
}],
])
const context = await fixture(routes)
context.server.removeAllListeners('request')
context.server.on('request', (request, response) => {
context.requests.set(request.url, (context.requests.get(request.url) ?? 0) + 1)
if (request.url === '/?token=fixture-token') {
response.writeHead(303, {
location: '/',
'set-cookie': 'dsh-auth-fixture=session; Path=/; HttpOnly; SameSite=Strict',
})
response.end()
return
}
expectedCookie = request.headers.cookie ?? ''
if (expectedCookie !== 'dsh-auth-fixture=session') {
response.writeHead(401)
response.end('unauthorized')
return
}
if (request.url === '/') {
response.writeHead(200, { 'content-type': 'text/html' })
response.end(``)
} else if (request.url === '/plugins/one/client.js?rev=one') {
response.writeHead(200, { 'content-type': 'text/javascript' })
response.end('one')
} else if (request.url === '/api/pluginInventory/list') {
response.writeHead(200, { 'content-type': 'application/json' })
response.end(JSON.stringify({
type: 'server-response',
rpcId: 'dsh-platform-readiness',
result: { ok: true, value: { entries: [{ moduleName: 'ready', enabled: true, fiberPhase: 'active' }] } },
}))
} else {
response.writeHead(404)
response.end()
}
})
try {
await verifyDshWebReady({
port: context.port,
managedReady: async () => ({ ready: true, readyUrl: `http://127.0.0.1:${String(context.port)}/?token=fixture-token` }),
})
assert.equal(expectedCookie, 'dsh-auth-fixture=session')
assert.equal(context.requests.get('/?token=fixture-token'), 1)
} finally {
await new Promise(resolve => context.server.close(resolve))
}
})
test('DSH web readiness rejects enabled Plugins that are not active', async () => {
const manifest = JSON.stringify({ rev: 'one', entries: [] })
const routes = new Map([
['/', { status: 200, type: 'text/html', body: `` }],
['POST /api/pluginInventory/list', { status: 200, type: 'application/json', body: JSON.stringify({
type: 'server-response',
rpcId: 'dsh-platform-readiness',
result: { ok: true, value: { entries: [
{ moduleName: 'active', enabled: true, fiberPhase: 'active' },
{ moduleName: 'disabled', enabled: false, fiberPhase: null },
{ moduleName: 'broken', enabled: true, fiberPhase: 'failed' },
] } },
}) }],
])
const context = await fixture(routes)
try {
await assert.rejects(
verifyDshWebReady({ port: context.port, managedReady: async () => {} }),
/DSH Plugins are not active: broken \(failed\)/,
)
} finally {
await new Promise(resolve => context.server.close(resolve))
}
})
test('DSH web readiness rejects Plugin inventory RPC failures', async () => {
const manifest = JSON.stringify({ rev: 'one', entries: [] })
const routes = new Map([
['/', { status: 200, type: 'text/html', body: `` }],
['POST /api/pluginInventory/list', { status: 200, type: 'application/json', body: JSON.stringify({
type: 'server-response',
rpcId: 'dsh-platform-readiness',
result: { ok: false, error: { code: 'internal', message: 'loader unavailable', details: {} } },
}) }],
])
const context = await fixture(routes)
try {
await assert.rejects(
verifyDshWebReady({ port: context.port, managedReady: async () => {} }),
/DSH Plugin inventory is unavailable: loader unavailable/,
)
} finally {
await new Promise(resolve => context.server.close(resolve))
}
})
test('DSH web readiness rejects a lifecycle generation change during verification', async () => {
const manifest = JSON.stringify({ rev: 'one', entries: [] })
const routes = new Map([
['/', { status: 200, type: 'text/html', body: `` }],
['POST /api/pluginInventory/list', { status: 200, type: 'application/json', body: JSON.stringify({
type: 'server-response',
rpcId: 'dsh-platform-readiness',
result: { ok: true, value: { entries: [] } },
}) }],
])
const context = await fixture(routes)
let observation = 0
try {
await assert.rejects(verifyDshWebReady({
port: context.port,
managedReady: async () => ({ generation: ++observation === 1 ? 'one' : 'two', ready: true, readyUrl: null }),
}), /lifecycle changed during Web readiness verification/)
assert.equal(context.requests.get('/'), 1)
assert.equal(context.requests.get('/api/pluginInventory/list'), 1)
} finally {
await new Promise(resolve => context.server.close(resolve))
}
})
test('DSH web readiness rejects a boot manifest mutation between observations', async () => {
const manifest = rev => JSON.stringify({ rev, entries: [] })
const routes = new Map([
['/', observation => ({
status: 200,
type: 'text/html',
body: ``,
})],
['POST /api/pluginInventory/list', { status: 200, type: 'application/json', body: JSON.stringify({
type: 'server-response',
rpcId: 'dsh-platform-readiness',
result: { ok: true, value: { entries: [] } },
}) }],
])
const context = await fixture(routes)
try {
await assert.rejects(
verifyDshWebReady({ port: context.port, managedReady: async () => ({ generation: 'one' }) }),
/boot manifest changed during Web readiness verification/,
)
} finally {
await new Promise(resolve => context.server.close(resolve))
}
})
test('DSH web readiness rejects a Plugin inventory mutation between observations', async () => {
const manifest = JSON.stringify({ rev: 'one', entries: [] })
const inventory = moduleName => JSON.stringify({
type: 'server-response',
rpcId: 'dsh-platform-readiness',
result: { ok: true, value: { entries: [{ moduleName, enabled: true, fiberPhase: 'active' }] } },
})
const routes = new Map([
['/', { status: 200, type: 'text/html', body: `` }],
['POST /api/pluginInventory/list', observation => ({
status: 200,
type: 'application/json',
body: inventory(observation === 1 ? 'one' : 'two'),
})],
])
const context = await fixture(routes)
try {
await assert.rejects(
verifyDshWebReady({ port: context.port, managedReady: async () => ({ generation: 'one' }) }),
/Plugin inventory changed during Web readiness verification/,
)
} finally {
await new Promise(resolve => context.server.close(resolve))
}
})
test('executes readiness checks when launched through the Bootstrap view symlink', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-web-ready-view-'))
const executable = join(root, 'dsh-web-ready.mjs')
await symlink(new URL('../../control-plane/hooks/dsh-web-ready.mjs', import.meta.url), executable)
const result = await new Promise((resolve, reject) => {
const child = spawn(process.execPath, [executable], {
env: { ...process.env, DSH_PLATFORM_RUN: join(root, 'missing-run') },
stdio: ['ignore', 'pipe', 'pipe'],
})
const stderr = []
child.stderr.on('data', chunk => stderr.push(chunk))
child.once('error', reject)
child.once('exit', code => resolve({ code, stderr: Buffer.concat(stderr).toString('utf8') }))
})
assert.notEqual(result.code, 0)
assert.match(result.stderr, /dsh-lifecycle\.sock/)
})