Files
dsh/upstream/container/platform/test/management.test.mjs
T

3260 lines
175 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from 'node:assert/strict'
import { EventEmitter } from 'node:events'
import { request as httpRequest } from 'node:http'
import { createConnection } from 'node:net'
import { appendFile, lstat, mkdir, mkdtemp, readFile, rm, symlink, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { PassThrough } from 'node:stream'
import test from 'node:test'
import { JsonlLogManager } from '../../control-plane/modules/log-manager/index.mjs'
import { parseCli, readSecret, recoverImageBaseline, resetTrust, runCli } from '../../control-plane/services/management/cli.mjs'
import { API_PREFIX, createManagementServer, listenManagement } from '../../control-plane/services/management/server.mjs'
import { LocalApiClient } from '../../control-plane/modules/updater/lib/client.mjs'
import { UpdateConflictError } from '../../control-plane/modules/updater/lib/coordinator.mjs'
import { UpdateScheduler } from '../../control-plane/modules/updater/lib/scheduler.mjs'
import { SettingsDocumentStore } from '../../control-plane/services/management/settings-document.mjs'
import { UserPluginInventory } from '../../control-plane/modules/plugin-manager/user-inventory.mjs'
import { UserPluginJournal } from '../../control-plane/modules/plugin-manager/user-journal.mjs'
import { UserPluginSnapshots } from '../../control-plane/modules/plugin-manager/user-snapshots.mjs'
import { UserPluginSelectionStore } from '../../control-plane/modules/plugin-manager/user-state.mjs'
import { UserPluginTransactionManager } from '../../control-plane/modules/plugin-manager/user-transaction.mjs'
import { FileInventory, FileSearchManager } from '../../control-plane/modules/file-manager/index.mjs'
import { FileTransferManager } from '../../control-plane/modules/file-manager/transfers.mjs'
import { FileTaskManager } from '../../control-plane/modules/file-manager/tasks.mjs'
import { AtomicFileEditor } from '../../control-plane/modules/file-manager/editor.mjs'
const ASYNC_POLL_ATTEMPTS = 2_000
const ASYNC_POLL_INTERVAL_MS = 5
class Coordinator extends EventEmitter {
constructor() {
super()
this.value = { status: 'idle', progress: 0 }
this.state = { read: async () => this.value }
}
async publicStatus() {
return { update: this.value, updateChannel: 'experimental', holds: [], experimentalBlocked: null, rollbackPlan: { planId: 'plan-a' } }
}
hasActiveTask() { return this.running === true }
async check(source) {
this.checkSource = source
return { value: { targetSequence: 2, desired: { dsh: { version: 'rc.8' } } } }
}
start() {
if (this.running) throw new UpdateConflictError('busy')
this.running = true
return { taskId: 'task-one', completion: new Promise(() => {}) }
}
startReconcile() { return this.start() }
rollbackPlan() { return Promise.resolve({ planId: 'plan-a' }) }
setChannel(channel) { return Promise.resolve({ updateChannel: channel, holds: [], experimentalBlocked: null }) }
retryHold(id) { return Promise.resolve({ retried: id }) }
startCompleteRollback(planId) {
assert.equal(planId, 'plan-a')
return { taskId: 'rollback-task', completion: Promise.resolve() }
}
}
function rawRequest(socketPath, path, method = 'GET') {
return new Promise((resolve, reject) => {
const request = httpRequest({ socketPath, path, method }, response => {
const chunks = []
response.on('data', chunk => chunks.push(chunk))
response.on('end', () => resolve({
status: response.statusCode,
headers: response.headers,
body: Buffer.concat(chunks).toString('utf8'),
}))
})
request.once('error', reject)
request.end()
})
}
function rawUpgrade(socketPath, path) {
return new Promise((resolve, reject) => {
const socket = createConnection(socketPath)
const chunks = []
socket.once('connect', () => socket.write([
`GET ${path} HTTP/1.1`,
'Host: management.internal',
'Connection: Upgrade',
'Upgrade: websocket',
'Sec-WebSocket-Key: dGVzdC1rZXk=',
'Sec-WebSocket-Version: 13',
'', '',
].join('\r\n')))
socket.on('data', chunk => chunks.push(chunk))
socket.once('error', reject)
socket.once('end', () => resolve(Buffer.concat(chunks).toString('utf8')))
})
}
test('management preserves capability backend failures for HTTP and WebSocket requests', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-capability-'))
const logs = new JsonlLogManager({ root: join(root, 'logs') })
const authorizeInternal = async () => {
throw Object.assign(new Error('Access Manager unavailable'), { statusCode: 503 })
}
const server = createManagementServer({
coordinator: new Coordinator(), logs, authorizeInternal,
terminalSessions: { upgrade() { assert.fail('unauthorized terminal upgrade reached execution point') } },
})
const socketPath = join(root, 'management.sock')
await listenManagement(server, socketPath)
try {
const response = await rawRequest(socketPath, `${API_PREFIX}status`)
assert.equal(response.status, 503)
assert.equal(JSON.parse(response.body).error, 'Access Manager unavailable')
assert.match(await rawUpgrade(socketPath, `${API_PREFIX}terminal/sessions/00000000-0000-4000-8000-000000000000/stream`), /^HTTP\/1\.1 503 Service Unavailable/m)
} finally {
await new Promise(resolve => server.close(resolve))
await rm(root, { recursive: true, force: true })
}
})
test('management socket exposes status, check, update, logs, and local rollback', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-'))
const coordinator = new Coordinator()
const originTransitions = []
const totpEnrollments = []
const logs = new JsonlLogManager({ root: join(root, 'logs') })
await logs.append('gateway', 'stdout', 'ready')
const server = createManagementServer({
coordinator,
logs,
platformStatus: async () => ({ environment: 'one' }),
updateAutomaticCheck: async value => value,
getAuthenticationSettings: async () => ({ account: { username: 'admin' } }),
updateAuthenticationSettings: async value => ({ account: { username: value.username } }),
beginTotpEnrollment: async value => {
totpEnrollments.push({ action: 'begin', value })
return { enrollmentToken: 'dshte_test', qrCode: 'data:image/svg+xml,test', secret: 'SECRET' }
},
confirmTotpEnrollment: async value => {
totpEnrollments.push({ action: 'confirm', value })
return { confirmed: true }
},
cancelTotpEnrollment: async value => {
totpEnrollments.push({ action: 'cancel', value })
return { canceled: true }
},
beginTotpDisableConfirmation: async value => {
totpEnrollments.push({ action: 'disable-begin', value })
return { confirmationToken: 'dshtd_test' }
},
confirmTotpDisable: async value => {
totpEnrollments.push({ action: 'disable-confirm', value })
return { confirmed: true }
},
cancelTotpDisableConfirmation: async value => {
totpEnrollments.push({ action: 'disable-cancel', value })
return { canceled: true }
},
revokeAuthenticationSessions: async value => ({ revoked: value.scope === 'all' ? 2 : 1 }),
createManagementOriginTransition: async value => {
originTransitions.push({ stage: 'create', value })
return { transition: { transitionId: 'transition-one', nonce: 'nonce-one' } }
},
commitManagementOriginTransition: async value => {
originTransitions.push({ stage: 'commit', value })
return { account: { managementAccess: { mode: 'isolated' } } }
},
reportManagementOriginTransitionFailure: async value => {
originTransitions.push({ stage: 'failure', value })
return { reported: true }
},
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
const status = await client.request('GET', '/_dsh_platform/api/v1/status')
assert.equal(status.environment, 'one')
assert.equal((await client.request('POST', '/_dsh_platform/api/v1/check', { source: 'page-open' })).targetSequence, 2)
assert.equal(coordinator.checkSource, 'page-open')
assert.deepEqual(await client.request('POST', '/_dsh_platform/api/v1/update'), { taskId: 'task-one' })
await assert.rejects(client.request('POST', '/_dsh_platform/api/v1/update'), error => error.statusCode === 409)
const rejected = await logs.query({ sources: ['platform-management'] })
assert.equal(rejected.some(entry => entry.message === 'management.request.failed'
&& entry.pathname === '/_dsh_platform/api/v1/update'
&& entry.level === 'warning'), true)
assert.equal((await client.request('GET', '/_dsh_platform/api/v1/logs?source=gateway')).entries[0].message, 'ready')
assert.equal((await client.request('PUT', '/_dsh_platform/api/v1/channel', { channel: 'experimental' })).updateChannel, 'experimental')
assert.deepEqual(await client.request('PUT', '/_dsh_platform/api/v1/automatic-check', {
enabled: true, intervalSeconds: 21_600, notificationsEnabled: false,
}), { enabled: true, intervalSeconds: 21_600, notificationsEnabled: false })
assert.equal((await client.request('GET', '/_dsh_platform/api/v1/auth-settings')).account.username, 'admin')
assert.equal((await client.request('PUT', '/_dsh_platform/api/v1/auth-settings', { username: 'operator' })).account.username, 'operator')
assert.equal((await client.request('POST', '/_dsh_platform/api/v1/auth-totp/enrollments', {
currentPassword: 'correct password',
})).enrollmentToken, 'dshte_test')
assert.equal((await client.request('POST', '/_dsh_platform/api/v1/auth-totp/enrollments/confirm', {
enrollmentToken: 'dshte_test', totpCode: '123456',
})).confirmed, true)
assert.equal((await client.request('POST', '/_dsh_platform/api/v1/auth-totp/enrollments/cancel', {
enrollmentToken: 'dshte_test',
})).canceled, true)
assert.equal((await client.request('POST', '/_dsh_platform/api/v1/auth-totp/disable-confirmations')).confirmationToken, 'dshtd_test')
assert.equal((await client.request('POST', '/_dsh_platform/api/v1/auth-totp/disable-confirmations/confirm', {
confirmationToken: 'dshtd_test', totpCode: '123456',
})).confirmed, true)
assert.equal((await client.request('POST', '/_dsh_platform/api/v1/auth-totp/disable-confirmations/cancel', {
confirmationToken: 'dshtd_test',
})).canceled, true)
assert.deepEqual(totpEnrollments, [
{ action: 'begin', value: { currentPassword: 'correct password' } },
{ action: 'confirm', value: { enrollmentToken: 'dshte_test', totpCode: '123456' } },
{ action: 'cancel', value: { enrollmentToken: 'dshte_test' } },
{ action: 'disable-begin', value: {} },
{ action: 'disable-confirm', value: { confirmationToken: 'dshtd_test', totpCode: '123456' } },
{ action: 'disable-cancel', value: { confirmationToken: 'dshtd_test' } },
])
assert.equal((await client.request('POST', '/_dsh_platform/api/v1/auth-sessions/revoke', {
sessionId: 'session-two',
})).revoked, 1)
assert.equal((await client.request('POST', '/_dsh_platform/api/v1/management-origin/transitions', {
mode: 'isolated', isolatedEntry: { kind: 'public', managementPublicOrigin: 'https://manage.example' },
})).transition.transitionId, 'transition-one')
assert.equal((await client.request('POST', '/_dsh_platform/api/v1/management-origin/transitions/commit', {
transitionId: 'transition-one', proof: 'proof-one',
})).account.managementAccess.mode, 'isolated')
assert.equal((await client.request('POST', '/_dsh_platform/api/v1/management-origin/transitions/failure', {
stage: 'browser-probe', mode: 'isolated',
})).reported, true)
assert.deepEqual(originTransitions.map(value => value.stage), ['create', 'commit', 'failure'])
assert.equal((await client.request('POST', '/_dsh_platform/api/v1/holds/retry', { id: 'hold-a' })).retried, 'hold-a')
assert.equal((await client.request('GET', '/_dsh_platform/api/v1/rollback-plan')).plan.planId, 'plan-a')
coordinator.running = false
assert.deepEqual(await client.request('POST', '/_dsh_platform/api/v1/rollback', { planId: 'plan-a' }), { taskId: 'rollback-task' })
const audit = await logs.query({ sources: ['audit'] })
assert.equal(audit.some(entry => entry.message === 'update.channel.changed' && entry.updateChannel === 'experimental'), true)
assert.equal(audit.some(entry => entry.message === 'update.automatic-check.configured' && entry.intervalSeconds === 21_600), true)
assert.equal(audit.some(entry => entry.message === 'update.hold.retried' && entry.holdId === 'hold-a'), true)
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management proxies sanitized outbound configuration, Provider inventory, and structured conflicts', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-outbound-proxy-'))
const logs = new JsonlLogManager({ root: join(root, 'logs') })
const view = {
schema: 1, enabled: false, revision: 'revision-one', componentReady: true,
proxy: { protocol: 'http', host: '', port: null, username: '', passwordConfigured: false, remoteDns: true },
scopes: {}, environment: { allProxy: null },
modelApi: { default: { proxyEnabled: false }, providers: {} },
noProxy: { system: ['localhost'], user: [] }, bypass: { additional: [] },
routeHealth: {}, lastTest: null, scopeCatalog: { schema: 1, entries: [] },
}
const providers = { schema: 1, source: 'live', providers: [{ id: 'deepseek', routingCapability: 'shared-dsh' }] }
const updates = []
const server = createManagementServer({
coordinator: new Coordinator(), logs,
getProxyConfiguration: async () => view,
listProxyProviders: async () => providers,
updateProxyConfiguration: async value => {
updates.push(value)
if (value.baseRevision !== view.revision) {
const error = new Error('proxy configuration changed')
error.statusCode = 409
error.code = 'REVISION_CONFLICT'
error.stage = 'activate'
error.retryable = true
error.proxyError = {
code: error.code, message: error.message, stage: error.stage, retryable: error.retryable,
}
throw error
}
return { ...view, revision: 'revision-two' }
},
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
assert.deepEqual(await client.request('GET', `${API_PREFIX}proxy`), view)
assert.deepEqual(await client.request('GET', `${API_PREFIX}proxy/provider-inventory`), providers)
const configured = await client.request('PUT', `${API_PREFIX}proxy`, {
baseRevision: view.revision,
value: { password: 'must-not-log' },
})
assert.equal(configured.revision, 'revision-two')
assert.deepEqual(updates, [{ baseRevision: view.revision, value: { password: 'must-not-log' } }])
const bytes = Buffer.from(JSON.stringify({ baseRevision: 'stale', value: {} }))
const conflict = await new Promise((resolve, reject) => {
const outgoing = httpRequest({
socketPath, method: 'PUT', path: `${API_PREFIX}proxy`,
headers: { 'content-type': 'application/json', 'content-length': bytes.byteLength },
}, response => {
const chunks = []
response.on('data', chunk => chunks.push(chunk))
response.on('end', () => resolve({ status: response.statusCode, body: JSON.parse(Buffer.concat(chunks).toString()) }))
})
outgoing.once('error', reject)
outgoing.end(bytes)
})
assert.equal(conflict.status, 409)
assert.deepEqual(conflict.body, { error: {
code: 'REVISION_CONFLICT', message: 'proxy configuration changed', stage: 'activate', retryable: true,
} })
const audit = await logs.query({ sources: ['audit'] })
assert.equal(audit.some(entry => entry.message === 'proxy.configuration.update.completed' && entry.revision === 'revision-two'), true)
assert.equal(audit.some(entry => entry.message === 'proxy.configuration.update.failed' && entry.code === 'REVISION_CONFLICT'), true)
assert.equal(JSON.stringify(audit).includes('must-not-log'), false)
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management exposes one reconnectable and cancellable outbound proxy test task', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-proxy-test-'))
const logs = new JsonlLogManager({ root: join(root, 'logs') })
const taskId = '123e4567-e89b-42d3-a456-426614174000'
let status = 'running'
let cancelled = false
const state = () => ({
schema: 1, taskId, status, baseRevision: 'revision-one', candidateHash: `sha256:${'a'.repeat(64)}`,
mode: 'proxy', currentStage: status === 'running' ? 'proxy-connect' : null,
stages: [{ stage: 'proxy-connect', status: status === 'running' ? 'running' : 'success', durationMs: 5, errorCode: null, detail: null }],
error: null, createdAt: '2026-08-25T00:00:00.000Z', updatedAt: new Date().toISOString(),
})
const server = createManagementServer({
coordinator: new Coordinator(), logs,
startProxyTest: async () => state(),
getProxyTest: async requested => {
assert.equal(requested, taskId)
return state()
},
cancelProxyTest: async requested => {
assert.equal(requested, taskId)
cancelled = true
status = 'cancelled'
return state()
},
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
assert.deepEqual(await client.request('POST', `${API_PREFIX}proxy/test`, {
baseRevision: 'revision-one', value: {},
}), { taskId })
assert.equal((await client.request('GET', `${API_PREFIX}status`)).proxyTestOperation.taskId, taskId)
assert.equal((await client.request('GET', `${API_PREFIX}proxy/test/tasks/${taskId}`)).status, 'running')
assert.equal((await client.request('DELETE', `${API_PREFIX}proxy/test/tasks/${taskId}`)).status, 'cancelled')
assert.equal(cancelled, true)
let audit
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
audit = await logs.query({ sources: ['audit'] })
if (audit.some(entry => entry.message === 'proxy.test.cancelled' && entry.taskId === taskId)) break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(audit.some(entry => entry.message === 'proxy.test.started' && entry.taskId === taskId), true)
assert.equal(audit.some(entry => entry.message === 'proxy.test.stage.changed'
&& entry.taskId === taskId && entry.stage === 'proxy-connect' && entry.status === 'running'), true)
assert.equal(audit.some(entry => entry.message === 'proxy.test.stage.changed'
&& entry.taskId === taskId && entry.stage === 'proxy-connect' && entry.status === 'success'), true)
assert.equal(audit.some(entry => entry.message === 'proxy.test.cancel-requested' && entry.taskId === taskId), true)
assert.equal(audit.some(entry => entry.message === 'proxy.test.cancelled' && entry.taskId === taskId), true)
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management exposes audited System Skill tasks through the shared runtime mutex', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-system-skills-'))
const logs = new JsonlLogManager({ root: join(root, 'logs') })
let complete
const pending = new Promise(resolve => { complete = resolve })
const calls = []
const skills = [{
id: 'dsh-docker-operations', sha256: 'a'.repeat(64),
description: { zh: '容器操作手册', en: 'Container operations guide' }, installed: true, enabled: true,
}]
const server = createManagementServer({
coordinator: new Coordinator(),
logs,
listSystemSkills: async () => skills,
configureSystemSkill: async (skillId, action) => { calls.push({ skillId, action }); await pending },
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
assert.deepEqual((await client.request('GET', `${API_PREFIX}system-skills`)).skills, skills)
const task = await client.request('POST', `${API_PREFIX}system-skills/action`, {
skillId: 'dsh-docker-operations', action: 'disable',
})
assert.match(task.taskId, /^[0-9a-f-]{36}$/)
await assert.rejects(client.request('POST', `${API_PREFIX}restart-dsh`), error => error.statusCode === 409)
await assert.rejects(client.request('POST', `${API_PREFIX}system-skills/action`, {
skillId: 'dsh-docker-operations', action: 'disable', unexpected: true,
}), error => error.statusCode === 400)
complete()
let status
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
status = await client.request('GET', `${API_PREFIX}status`)
if (status.systemSkillOperation.status === 'success') break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(status.systemSkillOperation.status, 'success')
assert.deepEqual(calls, [{ skillId: 'dsh-docker-operations', action: 'disable' }])
const audit = await logs.query({ sources: ['audit'] })
assert.equal(audit.some(entry => entry.message === 'system-skill.disable.started'), true)
assert.equal(audit.some(entry => entry.message === 'system-skill.disable.completed'), true)
} finally {
complete()
await new Promise(resolve => server.close(resolve))
}
})
test('management exposes validated User Skill tasks only on the standalone API', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-user-skills-'))
const logs = new JsonlLogManager({ root: join(root, 'logs') })
let complete
const pending = new Promise(resolve => { complete = resolve })
const revision = `sha256:${'a'.repeat(64)}`
const entryId = `sha256:${'b'.repeat(64)}`
const inventory = {
schema: 1, revision,
skills: [{ entryId, entryName: 'local-guide', source: 'user-dsh', kind: 'directory', name: 'local-guide', description: 'Local guide', enabled: true, damaged: false, metadataError: null, symbolicLink: false }],
}
const calls = []
const server = createManagementServer({
coordinator: new Coordinator(),
logs,
listUserSkills: async () => inventory,
validateUserSkillAction: async value => {
if (value.revision !== revision) {
const error = new Error('User Skill state changed')
error.statusCode = 409
throw error
}
},
configureUserSkill: async value => {
calls.push(value)
if (value.action === 'delete') throw new Error('permission denied')
await pending
},
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
assert.deepEqual(await client.request('GET', `${API_PREFIX}user-skills`), inventory)
await assert.rejects(client.request('POST', `${API_PREFIX}user-skills/action`, {
entryId, revision: `sha256:${'c'.repeat(64)}`, action: 'disable',
}), error => error.statusCode === 409)
await assert.rejects(client.request('POST', `${API_PREFIX}user-skills/action`, {
entryId, revision, action: 'disable', unexpected: true,
}), error => error.statusCode === 400)
const task = await client.request('POST', `${API_PREFIX}user-skills/action`, { entryId, revision, action: 'disable' })
assert.match(task.taskId, /^[0-9a-f-]{36}$/)
await assert.rejects(client.request('POST', `${API_PREFIX}restart-dsh`), error => error.statusCode === 409)
await assert.rejects(client.request('POST', `${API_PREFIX}user-skills/action`, {
entryId, revision, action: 'disable',
}), error => error.statusCode === 409)
complete()
let status
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
status = await client.request('GET', `${API_PREFIX}status`)
if (status.userSkillOperation.status === 'success') break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(status.userSkillOperation.status, 'success')
const failedTask = await client.request('POST', `${API_PREFIX}user-skills/action`, { entryId, revision, action: 'delete' })
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
status = await client.request('GET', `${API_PREFIX}status`)
if (status.userSkillOperation.taskId === failedTask.taskId && status.userSkillOperation.status === 'failed') break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(status.userSkillOperation.status, 'failed')
assert.equal(status.userSkillOperation.error, 'permission denied')
assert.deepEqual(calls, [{ entryId, revision, action: 'disable' }, { entryId, revision, action: 'delete' }])
const audit = await logs.query({ sources: ['audit'] })
assert.equal(audit.some(entry => entry.message === 'user-skill.disable.started'), true)
assert.equal(audit.some(entry => entry.message === 'user-skill.disable.completed'), true)
assert.equal(audit.some(entry => entry.message === 'user-skill.delete.started'), true)
assert.equal(audit.some(entry => entry.message === 'user-skill.delete.failed' && entry.error === 'permission denied'), true)
} finally {
complete()
await new Promise(resolve => server.close(resolve))
}
})
test('management live logs preserve the requested source filter', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-log-stream-'))
const logs = new JsonlLogManager({ root: join(root, 'logs') })
await logs.append('gateway', 'stdout', 'initial')
const server = createManagementServer({ coordinator: new Coordinator(), logs })
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
let request
let response
try {
({ request, response } = await new Promise((resolve, reject) => {
const nextRequest = httpRequest({ socketPath, path: `${API_PREFIX}logs/stream?source=gateway&limit=10` }, nextResponse => {
resolve({ request: nextRequest, response: nextResponse })
})
nextRequest.once('error', reject)
nextRequest.end()
}))
let body = ''
const live = new Promise(resolve => {
response.on('data', chunk => {
body += chunk.toString('utf8')
if (body.includes('must-stream')) resolve()
})
})
await logs.append('updater', 'stdout', 'must-not-stream')
await new Promise(resolve => setTimeout(resolve, 300))
await appendFile(logs.currentPath('gateway'), `${JSON.stringify({
timestamp: new Date().toISOString(), source: 'gateway', stream: 'stdout', level: 'info', message: 'must-stream',
})}\n`)
await Promise.race([
live,
new Promise((_, reject) => setTimeout(() => reject(new Error('timed out waiting for live log')), 1_000)),
])
assert.match(body, /must-stream/)
assert.doesNotMatch(body, /must-not-stream/)
assert.equal(response.headers['x-accel-buffering'], 'no')
assert.equal(response.headers['cache-control'], 'no-cache, no-transform')
} finally {
request?.destroy()
response?.destroy()
await new Promise(resolve => server.close(resolve))
}
})
test('management state events keep idle proxy connections alive', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-state-stream-'))
const server = createManagementServer({
coordinator: new Coordinator(),
logs: new JsonlLogManager({ root: join(root, 'logs') }),
stateHeartbeatMs: 10,
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
let request
let response
try {
({ request, response } = await new Promise((resolve, reject) => {
const nextRequest = httpRequest({ socketPath, path: `${API_PREFIX}events` }, nextResponse => {
resolve({ request: nextRequest, response: nextResponse })
})
nextRequest.once('error', reject)
nextRequest.end()
}))
let body = ''
await Promise.race([
new Promise(resolve => {
response.on('data', chunk => {
body += chunk.toString('utf8')
if (body.includes('event: heartbeat')) resolve()
})
}),
new Promise((_, reject) => setTimeout(() => reject(new Error('timed out waiting for state heartbeat')), 1_000)),
])
assert.match(body, /event: state/)
assert.match(body, /event: heartbeat/)
assert.equal(response.headers['x-accel-buffering'], 'no')
assert.equal(response.headers['cache-control'], 'no-cache, no-transform')
} finally {
request?.destroy()
response?.destroy()
await new Promise(resolve => server.close(resolve))
}
})
test('management state fan-out supports many tabs and releases every listener', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-state-fanout-'))
const coordinator = new Coordinator()
const server = createManagementServer({
coordinator,
logs: new JsonlLogManager({ root: join(root, 'logs') }),
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const connections = []
try {
for (let index = 0; index < 12; index += 1) {
connections.push(await new Promise((resolve, reject) => {
const request = httpRequest({ socketPath, path: `${API_PREFIX}events` }, response => {
response.once('data', () => resolve({ request, response }))
})
request.once('error', reject)
request.end()
}))
}
assert.equal(coordinator.getMaxListeners(), 0)
assert.equal(server.getMaxListeners(), 0)
assert.equal(coordinator.listenerCount('state'), 12)
assert.equal(server.listenerCount('management-state'), 12)
for (const connection of connections) {
connection.request.destroy()
connection.response.destroy()
}
for (let attempt = 0; attempt < 100 && coordinator.listenerCount('state') !== 0; attempt += 1) {
await new Promise(resolve => setTimeout(resolve, 5))
}
assert.equal(coordinator.listenerCount('state'), 0)
assert.equal(server.listenerCount('management-state'), 0)
} finally {
for (const connection of connections) {
connection.request.destroy()
connection.response.destroy()
}
await new Promise(resolve => server.close(resolve))
}
})
test('management reports unpublished development metadata without an HTTP error', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-unpublished-'))
const coordinator = new Coordinator()
coordinator.check = async () => ({ unavailable: true, upstream: { version: 'rc.10' } })
const server = createManagementServer({
coordinator,
logs: new JsonlLogManager({ root: join(root, 'logs') }),
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
try {
assert.deepEqual(await new LocalApiClient(socketPath).request('POST', '/_dsh_platform/api/v1/check'), {
available: false,
upstream: { version: 'rc.10' },
})
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management treats a page-open check during an update as an accepted no-op', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-busy-page-open-'))
const coordinator = new Coordinator()
coordinator.check = async () => ({ busy: true })
const server = createManagementServer({
coordinator,
logs: new JsonlLogManager({ root: join(root, 'logs') }),
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
try {
const response = await rawRequest(socketPath, `${API_PREFIX}check`, 'POST')
assert.equal(response.status, 202)
assert.deepEqual(JSON.parse(response.body), { busy: true })
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management edits only the fixed settings document with optimistic revisions', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-settings-document-'))
const dshHome = join(root, 'dsh')
const settingsDocument = new SettingsDocumentStore(dshHome)
const logs = new JsonlLogManager({ root: join(root, 'logs') })
const server = createManagementServer({ coordinator: new Coordinator(), logs, settingsDocument })
const socketPath = join(root, 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
const empty = await client.request('GET', `${API_PREFIX}settings-document`)
assert.equal(empty.content, '')
assert.equal(empty.exists, false)
assert.match(empty.revision, /^[a-f0-9]{64}$/)
const saved = await client.request('PUT', `${API_PREFIX}settings-document`, {
content: 'language: zh\n', revision: empty.revision,
})
assert.equal(saved.exists, true)
assert.equal(await readFile(join(dshHome, 'settings.yaml'), 'utf8'), 'language: zh\n')
assert.equal((await lstat(join(dshHome, 'settings.yaml'))).isFile(), true)
await assert.rejects(client.request('PUT', `${API_PREFIX}settings-document`, {
content: 'language: en\n', revision: empty.revision, path: '/etc/passwd',
}), error => error.statusCode === 400)
await assert.rejects(client.request('PUT', `${API_PREFIX}settings-document`, {
content: 'language: en\n', revision: empty.revision,
}), error => error.statusCode === 409)
assert.equal(await readFile(join(dshHome, 'settings.yaml'), 'utf8'), 'language: zh\n')
assert.deepEqual((await logs.query({ sources: ['audit'] })).map(entry => entry.message), ['settings-document.saved'])
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('settings document editing rejects symbolic links, invalid UTF-8, and oversized content', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-settings-unsafe-'))
const dshHome = join(root, 'dsh')
await import('node:fs/promises').then(({ mkdir }) => mkdir(dshHome))
const target = join(root, 'outside.yaml')
await writeFile(target, 'outside: true\n')
await symlink(target, join(dshHome, 'settings.yaml'))
const store = new SettingsDocumentStore(dshHome, { maxBytes: 8 })
await assert.rejects(store.read(), /regular file/)
await import('node:fs/promises').then(({ rm }) => rm(join(dshHome, 'settings.yaml')))
await writeFile(join(dshHome, 'settings.yaml'), Buffer.from([0xc3, 0x28]))
await assert.rejects(store.read(), /not valid UTF-8/)
await assert.rejects(store.write('123456789', '0'.repeat(64)), /too large/)
assert.equal(await readFile(target, 'utf8'), 'outside: true\n')
})
test('management restarts only DSH as an audited task and excludes update activation', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-restart-'))
const coordinator = new Coordinator()
const logs = new JsonlLogManager({ root: join(root, 'logs') })
let finishRestart
const restartCompletion = new Promise(resolve => { finishRestart = resolve })
let finishLoadedStateCapture
const loadedStateCaptureCompletion = new Promise(resolve => { finishLoadedStateCapture = resolve })
let restarts = 0
let loadedStateCaptures = 0
const server = createManagementServer({
coordinator,
logs,
restartDelayMs: 0,
restartDsh: async () => {
restarts += 1
await restartCompletion
},
markUserPluginsLoaded: async () => {
loadedStateCaptures += 1
await loadedStateCaptureCompletion
},
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
const task = await client.request('POST', '/_dsh_platform/api/v1/restart-dsh')
assert.equal(typeof task.taskId, 'string')
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS && restarts === 0; attempt += 1) {
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(restarts, 1)
assert.equal((await client.request('GET', '/_dsh_platform/api/v1/status')).dshLifecycle.state, 'restarting')
await assert.rejects(
client.request('POST', '/_dsh_platform/api/v1/restart-dsh'),
error => error.statusCode === 409,
)
await assert.rejects(
client.request('POST', '/_dsh_platform/api/v1/update'),
error => error.statusCode === 409,
)
finishRestart()
await new Promise(resolve => setImmediate(resolve))
await logs.queue
const status = await client.request('GET', '/_dsh_platform/api/v1/status')
assert.equal(status.dshLifecycle.state, 'running')
assert.equal(status.dshLifecycle.taskId, task.taskId)
assert.equal(loadedStateCaptures, 1)
finishLoadedStateCapture()
assert.deepEqual(
(await logs.query({ sources: ['audit'] })).map(entry => entry.message),
['dsh.restart.started', 'dsh.restart.completed'],
)
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management rejects DSH restart while an update task is active', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-restart-conflict-'))
const coordinator = new Coordinator()
coordinator.running = true
const server = createManagementServer({
coordinator,
logs: new JsonlLogManager({ root: join(root, 'logs') }),
restartDelayMs: 0,
restartDsh: async () => {},
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
try {
await assert.rejects(
new LocalApiClient(socketPath).request('POST', '/_dsh_platform/api/v1/restart-dsh'),
error => error.statusCode === 409,
)
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management returns the restart task before the configured restart delay elapses', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-restart-delay-'))
let restarted = false
const server = createManagementServer({
coordinator: new Coordinator(),
logs: new JsonlLogManager({ root: join(root, 'logs') }),
restartDelayMs: 40,
restartDsh: async () => { restarted = true },
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
const task = await client.request('POST', `${API_PREFIX}restart-dsh`)
assert.equal(typeof task.taskId, 'string')
assert.equal(restarted, false)
await new Promise(resolve => setTimeout(resolve, 60))
assert.equal(restarted, true)
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management starts and stops DSH through the unified lifecycle state', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-lifecycle-'))
const calls = []
const logs = new JsonlLogManager({ root: join(root, 'logs') })
const server = createManagementServer({
coordinator: new Coordinator(),
logs,
startDsh: async () => { calls.push('start') },
stopDsh: async () => { calls.push('stop') },
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
const stopped = await client.request('POST', `${API_PREFIX}stop-dsh`)
let status
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
status = await client.request('GET', `${API_PREFIX}status`)
if (status.dshLifecycle.taskId === stopped.taskId && status.dshLifecycle.state === 'stopped') break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(status.dshLifecycle.state, 'stopped')
assert.equal(status.dshLifecycle.action, null)
const started = await client.request('POST', `${API_PREFIX}start-dsh`)
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
status = await client.request('GET', `${API_PREFIX}status`)
if (status.dshLifecycle.taskId === started.taskId && status.dshLifecycle.state === 'running') break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(status.dshLifecycle.state, 'running')
assert.deepEqual(calls, ['stop', 'start'])
assert.deepEqual((await logs.query({ sources: ['audit'] })).map(entry => entry.message), [
'dsh.stop.started', 'dsh.stop.completed', 'dsh.start.started', 'dsh.start.completed',
])
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management preserves a completed lifecycle task until Bootstrap publishes a newer state', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-lifecycle-merge-'))
const logs = new JsonlLogManager({ root: join(root, 'logs') })
let bootstrapLifecycle = {
state: 'running', action: null, taskId: null, attempt: 0, maxAttempts: 3,
error: null, updatedAt: '2026-08-22T00:00:00.000Z',
}
const server = createManagementServer({
coordinator: new Coordinator(),
logs,
platformStatus: async () => ({ dshLifecycle: bootstrapLifecycle }),
startDsh: async () => {},
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
const started = await client.request('POST', `${API_PREFIX}start-dsh`)
let status
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
status = await client.request('GET', `${API_PREFIX}status`)
if (status.dshLifecycle.taskId === started.taskId && status.dshLifecycle.state === 'running') break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(status.dshLifecycle.taskId, started.taskId)
bootstrapLifecycle = {
...bootstrapLifecycle,
state: 'recovering', action: 'auto-recover', attempt: 1,
updatedAt: '2099-08-22T00:00:00.000Z',
}
status = await client.request('GET', `${API_PREFIX}status`)
assert.equal(status.dshLifecycle.state, 'recovering')
assert.equal(status.dshLifecycle.attempt, 1)
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management resets the current Runtime as an audited exclusive task', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-runtime-reset-'))
const coordinator = new Coordinator()
const logs = new JsonlLogManager({ root: join(root, 'logs') })
let finishReset
const completion = new Promise(resolve => { finishReset = resolve })
let resets = 0
const server = createManagementServer({
coordinator,
logs,
resetRuntime: async () => {
resets += 1
await completion
},
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
const task = await client.request('POST', '/_dsh_platform/api/v1/runtime/reset')
assert.equal(typeof task.taskId, 'string')
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS && resets === 0; attempt += 1) {
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(resets, 1)
assert.equal((await client.request('GET', '/_dsh_platform/api/v1/status')).runtimeReset.status, 'resetting')
for (const path of ['runtime/reset', 'restart-dsh', 'update']) {
await assert.rejects(
client.request('POST', `/_dsh_platform/api/v1/${path}`),
error => error.statusCode === 409,
)
}
finishReset()
await new Promise(resolve => setImmediate(resolve))
await logs.queue
const status = await client.request('GET', '/_dsh_platform/api/v1/status')
assert.equal(status.runtimeReset.status, 'success')
assert.equal(status.runtimeReset.taskId, task.taskId)
assert.deepEqual(
(await logs.query({ sources: ['audit'] })).map(entry => entry.message),
['runtime.reset.started', 'runtime.reset.completed'],
)
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management exposes recoverable User Plugin tasks under the shared runtime mutex', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-user-plugins-'))
const coordinator = new Coordinator()
const logs = new JsonlLogManager({ root: join(root, 'logs') })
let finish
const completion = new Promise(resolve => { finish = resolve })
const calls = []
const inventory = {
schema: 1,
profile: 'web',
revision: `sha256:${'a'.repeat(64)}`,
plugins: [{ name: 'faulty-plugin', enabled: true, damaged: false }],
}
const server = createManagementServer({
coordinator,
logs,
listUserPlugins: async () => inventory,
validateUserPluginActions: async value => {
calls.push(['validate', value])
if (value.revision !== inventory.revision) {
const error = new Error('revision changed')
error.code = 'REVISION_CONFLICT'
throw error
}
return value
},
applyUserPluginActions: async value => {
calls.push(['apply', value.taskId, value.revision, value.actions])
value.onProgress({ phase: 'paused' })
await completion
value.onProgress({ phase: 'completed' })
},
})
const socketPath = join(root, 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
assert.deepEqual(await client.request('GET', `${API_PREFIX}user-plugins`), inventory)
const request = {
profile: 'web', revision: inventory.revision,
actions: [{ name: 'faulty-plugin', action: 'disable' }],
}
const started = await client.request('POST', `${API_PREFIX}user-plugins/apply`, request)
assert.match(started.taskId, /^[0-9a-f-]{36}$/)
let status
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
status = await client.request('GET', `${API_PREFIX}status`)
if (status.userPluginOperation.phase === 'paused') break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(status.userPluginOperation.status, 'running')
assert.equal(status.userPluginOperation.phase, 'paused')
assert.equal((await client.request('GET', `${API_PREFIX}user-plugins/task/${started.taskId}`)).status, 'running')
for (const [path, body] of [
['restart-dsh', undefined],
['update', undefined],
['bundled-plugins/action', { id: 'diagnostics', action: 'disable' }],
['user-plugins/apply', request],
]) {
await assert.rejects(client.request('POST', `${API_PREFIX}${path}`, body), error => error.statusCode === 409)
}
finish()
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
status = await client.request('GET', `${API_PREFIX}status`)
if (status.userPluginOperation.status === 'success') break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(status.userPluginOperation.phase, 'completed')
assert.equal((await client.request('GET', `${API_PREFIX}user-plugins/task/${started.taskId}`)).status, 'success')
assert.deepEqual(calls[0], ['validate', { revision: inventory.revision, actions: request.actions }])
assert.deepEqual(calls[1].slice(0, 3), ['apply', started.taskId, inventory.revision])
await assert.rejects(client.request('POST', `${API_PREFIX}user-plugins/apply`, {
...request, revision: `sha256:${'b'.repeat(64)}`,
}), error => error.statusCode === 409)
await assert.rejects(
client.request('GET', `${API_PREFIX}user-plugins/task/123e4567-e89b-42d3-a456-426614174000`),
error => error.statusCode === 404,
)
await logs.queue
assert.deepEqual((await logs.query({ sources: ['audit'] })).map(entry => entry.message), [
'user-plugin.apply.started', 'user-plugin.apply.completed',
])
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management resumes a persisted User Plugin transaction after its socket is available', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-user-plugin-resume-'))
const logs = new JsonlLogManager({ root: join(root, 'logs') })
let recover
const recovery = new Promise(resolve => { recover = resolve })
const server = createManagementServer({
coordinator: new Coordinator(),
logs,
recoverUserPluginTransaction: async () => recovery,
})
const socketPath = join(root, 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
await assert.rejects(client.request('POST', `${API_PREFIX}restart-dsh`), error => error.statusCode === 409)
recover({
taskId: 'resume-task', phase: 'failed', error: 'interrupted change restored', recoveryResult: 'success',
})
let status
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
status = await client.request('GET', `${API_PREFIX}status`)
if (status.userPluginOperation.taskId === 'resume-task') break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(status.userPluginOperation.status, 'failed')
assert.equal(status.userPluginOperation.error, 'interrupted change restored')
await logs.queue
assert.equal((await logs.query({ sources: ['audit'] })).at(-1).message, 'user-plugin.recovery.completed')
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('standalone Management disables a startup-faulting Bundle while DSH is already down', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-fault-plugin-'))
const dshHome = join(root, 'dsh')
const profileRoot = join(dshHome, 'profiles/web')
const pluginRoot = join(profileRoot, 'node_modules/startup-fault')
const selectionPath = join(root, 'platform/state/management/user-plugins.json')
await mkdir(pluginRoot, { recursive: true })
await writeFile(join(profileRoot, 'package.json'), JSON.stringify({
name: 'dsh-profile-web',
dependencies: { 'startup-fault': '1.0.0' },
dsh: { profile: { bundles: ['startup-fault'] } },
}))
await writeFile(join(profileRoot, 'pnpm-lock.yaml'), 'lockfileVersion: 9\n')
await writeFile(join(pluginRoot, 'package.json'), JSON.stringify({
name: 'startup-fault', version: '1.0.0', dsh: { bundle: { patch: './cordis.patch.yml' } },
}))
await writeFile(join(pluginRoot, 'cordis.patch.yml'), '- insert: [{ id: startup-fault, name: startup-fault }]\n')
const inventory = new UserPluginInventory({ dshHome, selectionPath })
const logs = new JsonlLogManager({ root: join(root, 'logs') })
let paused = 0
let restarted = 0
const transactions = new UserPluginTransactionManager({
inventory,
selectionStore: new UserPluginSelectionStore(selectionPath),
snapshots: new UserPluginSnapshots({ root: join(root, 'platform/store/snapshots/user-plugins'), profileRoot }),
journal: new UserPluginJournal(join(root, 'platform/state/management/user-plugin-transaction.json')),
pauseDsh: async () => { paused += 1 },
restartDelayMs: 0,
restartDsh: async () => {
restarted += 1
const manifest = JSON.parse(await readFile(join(profileRoot, 'package.json'), 'utf8'))
if (manifest.dsh.profile.bundles.includes('startup-fault')) throw new Error('startup-fault crashed DSH')
},
report: (message, fields) => logs.diagnostic('user-plugin-manager', message, fields),
})
const server = createManagementServer({
coordinator: new Coordinator(),
logs,
platformStatus: async () => ({ recoveryMode: 'startup-fault crashed DSH' }),
listUserPlugins: () => inventory.read(),
validateUserPluginActions: value => transactions.validate(value),
applyUserPluginActions: value => transactions.apply(value),
})
const socketPath = join(root, 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
const listed = await client.request('GET', `${API_PREFIX}user-plugins`)
assert.deepEqual(listed.plugins.map(plugin => [plugin.name, plugin.enabled]), [['startup-fault', true]])
assert.equal((await client.request('GET', `${API_PREFIX}status`)).recoveryMode, 'startup-fault crashed DSH')
const task = await client.request('POST', `${API_PREFIX}user-plugins/apply`, {
profile: 'web', revision: listed.revision,
actions: [{ name: 'startup-fault', action: 'disable' }],
})
let state
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
state = await client.request('GET', `${API_PREFIX}user-plugins/task/${task.taskId}`)
if (state.status !== 'running') break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(state.status, 'success')
assert.equal(state.strategy, 'next-start')
assert.equal(paused, 0)
assert.equal(restarted, 0)
const manifest = JSON.parse(await readFile(join(profileRoot, 'package.json'), 'utf8'))
assert.deepEqual(manifest.dsh.profile.bundles, [])
await logs.queue
assert.deepEqual((await logs.query({ sources: ['user-plugin-manager'] })).map(entry => entry.message), [
'user-plugin.transaction.started', 'user-plugin.transaction.completed',
])
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management changes a bundled plugin as an audited task and excludes runtime changes', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-plugin-action-'))
const coordinator = new Coordinator()
const logs = new JsonlLogManager({ root: join(root, 'logs') })
let finish
const completion = new Promise(resolve => { finish = resolve })
const calls = []
const server = createManagementServer({
coordinator,
logs,
listBundledPlugins: async () => [{ id: 'diagnostics', installed: true, enabled: true, protected: false }],
configureBundledPlugin: async (id, action) => {
calls.push([id, action])
await completion
},
restartDelayMs: 0,
restartDsh: async () => {},
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
assert.deepEqual((await client.request('GET', '/_dsh_platform/api/v1/bundled-plugins')).plugins, [{
id: 'diagnostics', installed: true, enabled: true, protected: false,
}])
const task = await client.request('POST', '/_dsh_platform/api/v1/bundled-plugins/action', {
id: 'diagnostics', action: 'disable',
})
assert.equal(typeof task.taskId, 'string')
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS && calls.length === 0; attempt += 1) {
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.deepEqual(calls, [['diagnostics', 'disable']])
assert.equal((await client.request('GET', '/_dsh_platform/api/v1/status')).systemPluginOperation.status, 'running')
assert.equal((await client.request('GET', `/_dsh_platform/api/v1/bundled-plugins/task/${task.taskId}`)).status, 'running')
await assert.rejects(
client.request('GET', '/_dsh_platform/api/v1/bundled-plugins/task/123e4567-e89b-42d3-a456-426614174000'),
error => error.statusCode === 404,
)
for (const [method, path, body] of [
['POST', '/_dsh_platform/api/v1/bundled-plugins/action', { id: 'diagnostics', action: 'uninstall' }],
['POST', '/_dsh_platform/api/v1/restart-dsh'],
['POST', '/_dsh_platform/api/v1/update'],
]) {
await assert.rejects(client.request(method, path, body), error => error.statusCode === 409)
}
finish()
await new Promise(resolve => setImmediate(resolve))
await logs.queue
const changed = await client.request('GET', '/_dsh_platform/api/v1/status')
assert.equal(changed.systemPluginOperation.status, 'success')
assert.equal(changed.systemPluginOperation.restartRequired, true)
assert.equal((await client.request('GET', `/_dsh_platform/api/v1/bundled-plugins/task/${task.taskId}`)).status, 'success')
assert.deepEqual(
(await logs.query({ sources: ['audit'] })).map(entry => entry.message),
['system-plugin.disable.started', 'system-plugin.disable.completed'],
)
await client.request('POST', '/_dsh_platform/api/v1/restart-dsh')
let restarted
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
restarted = await client.request('GET', '/_dsh_platform/api/v1/status')
if (restarted.dshLifecycle.state === 'running') break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(restarted.dshLifecycle.state, 'running')
assert.equal(restarted.systemPluginOperation.restartRequired, false)
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management completes System Plugin changes for the next start while DSH is unavailable', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-system-plugin-offline-'))
let configured = false
const server = createManagementServer({
coordinator: new Coordinator(),
logs: new JsonlLogManager({ root: join(root, 'logs') }),
platformStatus: async () => ({
recoveryMode: 'startup failed',
dshLifecycle: { state: 'failed' },
}),
configureBundledPlugin: async () => { configured = true },
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
await client.request('POST', `${API_PREFIX}bundled-plugins/action`, {
id: 'diagnostics', action: 'disable',
})
let status
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
status = await client.request('GET', `${API_PREFIX}status`)
if (status.systemPluginOperation.status === 'success') break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(configured, true)
assert.equal(status.systemPluginOperation.strategy, 'next-start')
assert.equal(status.systemPluginOperation.restartRequired, false)
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management toggle endpoint accepts only enable and disable actions', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-plugin-toggle-'))
const calls = []
const server = createManagementServer({
coordinator: new Coordinator(),
logs: new JsonlLogManager({ root: join(root, 'logs') }),
configureBundledPlugin: async (id, action) => { calls.push([id, action]) },
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
await assert.rejects(client.request('POST', `${API_PREFIX}bundled-plugins/toggle`, {
id: 'diagnostics', action: 'install',
}), error => error.statusCode === 400)
const task = await client.request('POST', `${API_PREFIX}bundled-plugins/toggle`, {
id: 'diagnostics', action: 'disable',
})
assert.equal(typeof task.taskId, 'string')
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS && calls.length === 0; attempt += 1) {
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.deepEqual(calls, [['diagnostics', 'disable']])
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management discards unapplied System Plugin changes and clears restart state', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-plugin-discard-'))
let discarded = 0
const logs = new JsonlLogManager({ root: join(root, 'logs') })
const server = createManagementServer({
coordinator: new Coordinator(),
logs,
configureBundledPlugin: async () => {},
discardBundledPluginChanges: async () => {
discarded += 1
return { plugins: [{ id: 'diagnostics', pendingRestart: false }] }
},
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
await client.request('POST', `${API_PREFIX}bundled-plugins/action`, {
id: 'diagnostics', action: 'disable',
})
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
if ((await client.request('GET', `${API_PREFIX}status`)).systemPluginOperation.restartRequired) break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
let result
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
try {
result = await client.request('POST', `${API_PREFIX}bundled-plugins/discard`)
break
} catch (error) {
if (error.statusCode !== 409) throw error
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
}
assert.notEqual(result, undefined)
assert.equal(discarded, 1)
assert.deepEqual(result, { plugins: [{ id: 'diagnostics', pendingRestart: false }] })
assert.equal((await client.request('GET', `${API_PREFIX}status`)).systemPluginOperation.restartRequired, false)
assert.deepEqual((await logs.query({ sources: ['audit'] })).map(entry => entry.message), [
'system-plugin.disable.started',
'system-plugin.disable.completed',
'system-plugin.changes.discarded',
])
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management completes the System Plugin change when DSH restart fails', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-plugin-restart-failure-'))
const logs = new JsonlLogManager({ root: join(root, 'logs') })
const server = createManagementServer({
coordinator: new Coordinator(),
logs,
configureBundledPlugin: async () => {},
restartDelayMs: 0,
restartDsh: async () => { throw new Error('restart failed') },
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
await client.request('POST', '/_dsh_platform/api/v1/bundled-plugins/action', {
id: 'diagnostics', action: 'disable',
})
let status
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
status = await client.request('GET', '/_dsh_platform/api/v1/status')
if (status.systemPluginOperation.status === 'success') break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(status.systemPluginOperation.restartRequired, true)
await client.request('POST', '/_dsh_platform/api/v1/restart-dsh')
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
status = await client.request('GET', '/_dsh_platform/api/v1/status')
if (status.dshLifecycle.state === 'failed') break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(status.dshLifecycle.state, 'failed')
assert.equal(status.systemPluginOperation.strategy, 'next-start')
assert.equal(status.systemPluginOperation.activationError, 'restart failed')
assert.equal(status.systemPluginOperation.restartRequired, false)
await logs.queue
assert.equal((await logs.query({ sources: ['audit'] })).find(entry => entry.message === 'dsh.restart.failed').level, 'error')
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management audit failures do not block a completed System Plugin operation', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-audit-failure-'))
let configured = false
const logs = {
diagnostic: () => { throw new Error('audit storage unavailable') },
query: async () => [],
on: () => {},
off: () => {},
}
const server = createManagementServer({
coordinator: new Coordinator(),
logs,
configureBundledPlugin: async () => { configured = true },
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
await client.request('POST', `${API_PREFIX}bundled-plugins/action`, {
id: 'diagnostics', action: 'disable',
})
let status
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS; attempt += 1) {
status = await client.request('GET', `${API_PREFIX}status`)
if (status.systemPluginOperation.status === 'success') break
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.equal(configured, true)
assert.equal(status.systemPluginOperation.status, 'success')
assert.equal(status.systemPluginOperation.restartRequired, true)
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management exposes a dedicated recovery action only for Platform Management', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-plugin-recovery-'))
const calls = []
const logs = new JsonlLogManager({ root: join(root, 'logs') })
const server = createManagementServer({
coordinator: new Coordinator(),
logs,
recoverBundledPlugin: async (id, action) => { calls.push([id, action]) },
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
await assert.rejects(client.request('POST', `${API_PREFIX}bundled-plugins/recovery-action`, {
id: 'diagnostics', action: 'uninstall',
}), error => error.statusCode === 400)
const task = await client.request('POST', `${API_PREFIX}bundled-plugins/recovery-action`, {
id: 'platform-management', action: 'disable',
})
assert.equal(typeof task.taskId, 'string')
for (let attempt = 0; attempt < ASYNC_POLL_ATTEMPTS && calls.length === 0; attempt += 1) {
await new Promise(resolve => setTimeout(resolve, ASYNC_POLL_INTERVAL_MS))
}
assert.deepEqual(calls, [['platform-management', 'disable']])
await new Promise(resolve => setImmediate(resolve))
await logs.queue
assert.deepEqual(
(await logs.query({ sources: ['audit'] })).map(entry => entry.message),
['system-plugin.recovery.disable.started', 'system-plugin.recovery.disable.completed'],
)
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management separates a known Stable target from update availability', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-current-'))
const coordinator = new Coordinator()
coordinator.check = async () => ({
value: { targetSequence: 2, desired: { dsh: { version: 'rc.7' } } },
updateAvailable: false,
})
const server = createManagementServer({
coordinator,
logs: new JsonlLogManager({ root: join(root, 'logs') }),
})
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
try {
assert.deepEqual(await new LocalApiClient(socketPath).request('POST', '/_dsh_platform/api/v1/check'), {
available: false,
targetSequence: 2,
desired: { dsh: { version: 'rc.7' } },
})
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management records a completion audit for a successful update task', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-audit-'))
const coordinator = new Coordinator()
coordinator.startReconcile = () => ({ taskId: 'task-success', completion: Promise.resolve() })
const logs = new JsonlLogManager({ root: join(root, 'logs') })
const server = createManagementServer({ coordinator, logs })
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
try {
const client = new LocalApiClient(socketPath)
await client.request('POST', '/_dsh_platform/api/v1/update')
await new Promise(resolve => setImmediate(resolve))
await logs.queue
assert.deepEqual(
(await logs.query({ sources: ['audit'] })).map(entry => [entry.message, entry.taskId]),
[['update.started', 'task-success'], ['update.completed', 'task-success']],
)
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management records correlated rollback and return-stable audit lifecycles', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-rollback-audit-'))
const coordinator = new Coordinator()
coordinator.startCompleteRollback = (planId, options) => {
assert.equal(planId, 'plan-a')
if (options.requireConfirmation) {
return { taskId: 'return-stable-failure', completion: Promise.reject(new Error('restore failed')) }
}
return { taskId: 'rollback-success', completion: Promise.resolve() }
}
const logs = new JsonlLogManager({ root: join(root, 'logs') })
const server = createManagementServer({ coordinator, logs })
const socketPath = join(root, 'run', 'management.sock')
await listenManagement(server, socketPath)
try {
const client = new LocalApiClient(socketPath)
await client.request('POST', `${API_PREFIX}rollback`, { planId: 'plan-a' })
await client.request('POST', `${API_PREFIX}return-stable`, {
planId: 'plan-a', confirmDataLoss: true,
})
await new Promise(resolve => setImmediate(resolve))
await logs.queue
assert.deepEqual(
(await logs.query({ sources: ['audit'] })).map(entry => [entry.message, entry.taskId]),
[
['rollback.started', 'rollback-success'],
['rollback.completed', 'rollback-success'],
['return-stable.started', 'return-stable-failure'],
['return-stable.failed', 'return-stable-failure'],
],
)
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('management serves only the fixed persistent Platform Management assets', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-console-'))
const coordinator = new Coordinator()
const logs = new JsonlLogManager({ root: join(root, 'logs') })
const server = createManagementServer({ coordinator, logs })
const socketPath = join(root, 'management.sock')
await listenManagement(server, socketPath)
try {
const redirect = await rawRequest(socketPath, '/_dsh_platform/console')
assert.equal(redirect.status, 308)
assert.equal(redirect.headers.location, '/_dsh_platform/console/')
const page = await rawRequest(socketPath, '/_dsh_platform/console/')
assert.equal(page.status, 200)
assert.match(page.headers['content-type'], /^text\/html/)
assert.match(page.body.toString('utf8'), /<link rel="icon" href="data:image\/svg\+xml,/)
assert.match(page.headers['content-security-policy'], /script-src 'self'/)
assert.match(page.headers['content-security-policy'], /connect-src 'self' http: https:/)
assert.match(page.body, /DSH Management Console/)
const script = await rawRequest(socketPath, '/_dsh_platform/console/app.js')
assert.equal(script.status, 200)
assert.match(script.body, /new EventSource/)
const themeInit = await rawRequest(socketPath, '/_dsh_platform/console/theme-init.js')
assert.equal(themeInit.status, 200)
assert.match(themeInit.headers['content-type'], /^text\/javascript/)
assert.match(themeInit.body, /console-theme/)
const head = await rawRequest(socketPath, '/_dsh_platform/console/style.css', 'HEAD')
assert.equal(head.status, 200)
assert.equal(head.body, '')
const xterm = await rawRequest(socketPath, '/_dsh_platform/console/vendor/xterm.mjs')
assert.equal(xterm.status, 200)
assert.match(xterm.headers['content-type'], /^text\/javascript/)
assert.match(xterm.body, /export\{/)
const fit = await rawRequest(socketPath, '/_dsh_platform/console/vendor/addon-fit.mjs')
assert.equal(fit.status, 200)
assert.match(fit.body, /FitAddon/)
assert.match((await rawRequest(socketPath, '/_dsh_platform/console/vendor/xterm.css')).headers['content-type'], /^text\/css/)
assert.equal((await rawRequest(socketPath, '/_dsh_platform/console/vendor/xterm.mjs.map')).status, 404)
assert.equal((await rawRequest(socketPath, '/_dsh_platform/console/../server.mjs')).status, 404)
assert.equal((await rawRequest(socketPath, '/_dsh_platform/console/app.js', 'POST')).status, 405)
} finally {
await new Promise(resolve => server.close(resolve))
}
})
test('Platform Management script references only DOM IDs declared by its document', async () => {
const publicRoot = new URL('../../control-plane/services/management/public/', import.meta.url)
const html = await readFile(new URL('index.html', publicRoot), 'utf8')
const script = await readFile(new URL('app.js', publicRoot), 'utf8')
const ids = new Set([...html.matchAll(/\bid="([a-z0-9-]+)"/g)].map(match => match[1]))
const references = [...script.matchAll(/elements(?:\.([A-Za-z][A-Za-z0-9]*)|\[['"]([a-z0-9-]+)['"]\])/g)]
.map(match => match[1] ?? match[2])
assert.equal(references.length > 0, true)
for (const id of references) assert.equal(ids.has(id), true, `Console element ${id} is not declared`)
assert.doesNotMatch(script, /innerHTML|outerHTML|insertAdjacentHTML/)
assert.match(script, /selectTab\(window\.location\.hash === '#auth-settings' \? 'auth-settings' : 'maintenance'\)/)
})
test('standalone file task queue stays below file actions and scrolls within a fixed height', async () => {
const publicRoot = new URL('../../control-plane/services/management/public/', import.meta.url)
const html = await readFile(new URL('index.html', publicRoot), 'utf8')
const script = await readFile(new URL('app.js', publicRoot), 'utf8')
const style = await readFile(new URL('style.css', publicRoot), 'utf8')
const browserOffset = html.indexOf('class="file-browser"')
const selectionOffset = html.indexOf('class="file-selection"')
const taskOffset = html.indexOf('id="file-task-state"')
const archiveOffset = html.indexOf('id="file-archive-panel"')
assert.equal(browserOffset < selectionOffset && selectionOffset < taskOffset && taskOffset < archiveOffset, true)
assert.match(style, /\.file-task-list\s*\{[^}]*max-height:\s*180px;[^}]*overflow-y:\s*auto;/)
assert.match(style, /\.file-main\s*\{[^}]*display:\s*flex;[^}]*flex-direction:\s*column;/)
assert.match(style, /\.file-pagination\s*\{[^}]*margin-top:\s*auto;/)
assert.match(script, /task\.status === 'failed' && Date\.parse\(task\.updatedAt\) >= recentCutoff/)
assert.doesNotMatch(script, /\['success', 'failed', 'cancelled'\]/)
assert.match(script, /fileUploadQueue = files\.map/)
assert.match(script, /request\.upload\.onprogress/)
assert.match(script, /\.\.\.fileUploadQueue, \.\.\.backend/)
assert.match(script, /task\.local === true\) task\.cancel\(\)/)
assert.match(script, /item\.webkitGetAsEntry\?\.\(\)/)
assert.match(script, /collectDroppedEntry\(child, relativePath\)/)
assert.match(script, /fileDropTarget\.addEventListener\('drop'/)
assert.match(html, /class="file-drop-overlay"/)
assert.match(style, /\.file-main\.file-dragging \.file-drop-overlay\s*\{[^}]*display:\s*grid;/)
assert.match(style, /\.proxy-provider-list \{[^}]*max-height: 320px;[^}]*overflow-y: auto;/)
assert.match(html, /id="proxy-advanced"[\s\S]*id="proxy-remote-dns-row"[^>]*hidden[\s\S]*id="proxy-remote-dns"/)
assert.doesNotMatch(style, /\.proxy-check-row/)
assert.match(style, /\.proxy-scope-description \{[^}]*-webkit-line-clamp: 1;/)
assert.match(script, /function refreshProxyDescriptions\(\)[\s\S]*preserveScrollableAncestors/)
assert.match(script, /function renderProxyProviders\(\)[\s\S]*displayName[\s\S]*info\.className = 'proxy-provider-info'/)
assert.match(script, /proxyConfiguration = await api\('proxy'\)[\s\S]*renderProxyConfiguration\(\)[\s\S]*void refreshProxyProviders\(\)/)
assert.match(script, /if \(tab === 'proxy'\) \{[\s\S]*if \(proxyLoaded\) void refreshProxyProviders\(\)[\s\S]*else void loadProxy\(\)/)
assert.match(script, /function refreshVisibleProxyProviders\(\)[\s\S]*proxyLoaded[\s\S]*panel-proxy[\s\S]*refreshProxyProviders\(\)/)
assert.match(script, /window\.addEventListener\('focus', refreshVisibleProxyProviders\)/)
assert.doesNotMatch(script, /Promise\.all\(\[api\('proxy'\), api\('proxy\/provider-inventory'\)\]\)/)
assert.match(script, /proxy-provider-search[\s\S]*addEventListener\('input', renderProxyProviders\)/)
assert.match(script, /proxy-clear-password[\s\S]*getAttribute\('aria-pressed'\) === 'true'/)
assert.match(script, /route\.className = 'proxy-provider-route'[\s\S]*input\.dataset\.providerPolicy = provider\.id[\s\S]*input\.checked = policy\.proxyEnabled === true/)
assert.match(html, /class="proxy-scope-card"[\s\S]*class="toggle"[\s\S]*data-proxy-scope="updates"/)
assert.match(html, /id="proxy-clear-password"[^>]*aria-pressed="false"/)
assert.match(html, /class="proxy-setting-row[^"]*"[\s\S]*class="toggle"[\s\S]*id="proxy-all-proxy"/)
assert.match(html, /id="proxy-provider-search"[^>]*type="search"/)
assert.match(html, /id="proxy-test-dialog"[\s\S]*id="proxy-test-stages"/)
assert.doesNotMatch(html, /id="proxy-test-close"/)
assert.match(html, /<footer><p id="proxy-test-result"[\s\S]*<button id="proxy-test-cancel"/)
assert.match(html, /class="proxy-setting-row[^"]*"[\s\S]*id="proxy-enabled"/)
assert.ok(html.indexOf('id="proxy-master-title"') < html.indexOf('id="proxy-title"'))
assert.ok(html.indexOf('id="proxy-enabled"') < html.indexOf('id="proxy-test"'))
assert.match(html, /<h2 id="proxy-master-title"[^>]*>[\s\S]*id="proxy-component-alert"[^>]*hidden/)
assert.match(html, /<path d="M12 6\.5v7"\/><path d="M12 17\.5h\.01"\/>/)
assert.match(html, /id="proxy-component-dialog"[\s\S]*proxyComponentIssueDetail/)
assert.match(style, /\.proxy-master-row > div > small \{ font-size: 13px; line-height: 20px; \}/)
assert.match(style, /\.proxy-advanced-setting > div > small \{ font-size: 13px; line-height: 20px; \}/)
assert.match(html, /<h3 data-i18n="proxyRules"[\s\S]*<h3 data-i18n="proxyAllProxy"/)
assert.doesNotMatch(html, /<span data-i18n="proxyDirectRules"/)
assert.match(style, /\.proxy-test-stage > span:nth-child\(2\) \{[^}]*display: grid;[^}]*gap: 1px;/)
assert.match(style, /\.proxy-test-dialog footer \{[^}]*display: grid;[^}]*grid-template-columns: minmax\(0, 1fr\) auto;/)
assert.match(style, /\.proxy-test-dialog footer > \.operation-result \{[^}]*margin: 0;/)
assert.doesNotMatch(style, /@media \(max-width: 640px\)[\s\S]*\.proxy-test-dialog \{[^}]*height: 100dvh;/)
assert.match(style, /\.proxy-scope-dialog \{[^}]*height: min\(760px, calc\(100dvh - 32px\)\)/)
assert.match(style, /\.proxy-scope-catalog \{[^}]*min-height: 0;[^}]*overflow: auto;/)
assert.match(script, /detail\.className = 'proxy-scope-description'[\s\S]*refreshProxyDescriptions\(\)/)
assert.match(script, /function pendingProxyTestStages\(proxy = \{\}\)[\s\S]*stage !== 'target-dns'[\s\S]*proxy\.protocol === 'socks5'[\s\S]*status: 'pending'/)
assert.match(script, /async function startProxyTest\(\)[\s\S]*status: 'starting'[\s\S]*pendingProxyTestStages\(\{[\s\S]*protocol:[\s\S]*remoteDns:[\s\S]*showModal\(\)/)
assert.match(script, /function failedProxyTest\(error,[\s\S]*pendingProxyTestStages\(\)/)
assert.match(script, /const expandedProxyTestStages = new Set\(\)/)
assert.match(script, /item\.setAttribute\('role', 'button'\)[\s\S]*item\.setAttribute\('aria-expanded'[\s\S]*preserveScrollableAncestors\(item[\s\S]*detail\.hidden = !expanded/)
assert.match(script, /statusLabel\.textContent = status/)
assert.match(script, /proxy-test-cancel'[\s\S]*textContent = t\(running \? 'cancel' : 'close'\)/)
assert.match(script, /proxy-enabled'[\s\S]*saveProxyImmediate\(configuration => \{ configuration\.enabled = event\.target\.checked \}\)/)
assert.doesNotMatch(script, /proxy-enabled-label|proxy-test-close/)
assert.match(html, /id="proxy-title"[\s\S]*id="proxy-test"[\s\S]*id="proxy-save"/)
assert.match(html, /id="proxy-advanced-toggle"[^>]*aria-controls="proxy-advanced"[\s\S]*id="proxy-advanced"[\s\S]*id="proxy-system-rules"[\s\S]*id="proxy-direct-rules"[\s\S]*id="proxy-all-proxy"[\s\S]*id="proxy-remote-dns-row"/)
assert.doesNotMatch(html, /id="proxy-rules-save"|id="proxy-password-state"|id="proxy-operation-result"/)
assert.doesNotMatch(html, /<section aria-labelledby="proxy-test-title">/)
assert.match(html, /id="proxy-provider-info-dialog"[\s\S]*id="proxy-provider-info-detail"/)
assert.match(script, /proxy-provider-info-dialog[\s\S]*event\.target === event\.currentTarget[\s\S]*\.close\(\)/)
assert.match(script, /function splitDirectRules\(value\)[\s\S]*noProxy:[\s\S]*bypass:/)
assert.match(html, /id="proxy-direct-rules"/)
assert.match(html, /id="proxy-system-rules-dialog"[\s\S]*id="proxy-system-rules-list"/)
assert.doesNotMatch(html, /id="proxy-no-proxy"|id="proxy-bypass"/)
assert.doesNotMatch(style, /\.proxy-provider-description/)
assert.match(html, /class="log-summary-row"><p id="log-summary"[\s\S]*id="auto-scroll" type="checkbox" checked/)
assert.match(style, /\.log-auto-scroll \{[^}]*margin-left: auto;/)
assert.match(script, /operationState === 'success' \|\| operation\?\.state === 'running'/)
assert.match(script, /visibleOperationTasks\.delete\(taskId\)[\s\S]*3_000/)
assert.match(script, /fileOperationTimer = window\.setTimeout\(\(\) => fileOperationMessage\(''\), 3_000\)/)
assert.match(html, /id="file-editor-status" role="status" aria-live="polite"/)
assert.match(script, /function renderFileEditorState\(\)[\s\S]*fileEditorSaving[\s\S]*fileEditorDirty/)
assert.match(script, /const content = elements\['file-editor-content'\]\.value[\s\S]*body: \{ path, content, revision, create \}[\s\S]*fileEditorDirty = elements\['file-editor-content'\]\.value !== fileEditorOriginal/)
assert.match(style, /\.file-editor-footer \{[^}]*justify-content: space-between;/)
assert.match(style, /@media \(max-width: 640px\)[\s\S]*\.plugin-draft-actions \{ display: grid; width: 100%; grid-template-columns: 1fr; \}/)
})
test('standalone console keeps localized feature parity on the shared Management API', async () => {
const publicRoot = new URL('../../control-plane/services/management/public/', import.meta.url)
const html = await readFile(new URL('index.html', publicRoot), 'utf8')
const script = await readFile(new URL('app.js', publicRoot), 'utf8')
const style = await readFile(new URL('style.css', publicRoot), 'utf8')
const serverSource = await readFile(new URL('../../control-plane/services/management/server.mjs', import.meta.url), 'utf8')
const maintenanceSource = await readFile(new URL('../stage0/lib/maintenance-server.mjs', import.meta.url), 'utf8')
const pluginSource = await readFile(new URL('../../environment/resources/plugins/platform-management/package/lib/client.js', import.meta.url), 'utf8')
for (const panel of ['updates', 'proxy', 'auth-settings', 'maintenance', 'plugins', 'skills', 'user-skills', 'user-plugins', 'terminal', 'files']) {
assert.match(html, new RegExp(`id="panel-${panel}"`))
}
const extensionTabs = [
'tab-maintenance', 'tab-files', 'tab-terminal', 'tab-plugins',
'tab-skills', 'tab-user-plugins', 'tab-user-skills', 'tab-proxy', 'tab-updates', 'tab-auth-settings',
]
.map(id => html.indexOf(`id="${id}"`))
assert.deepEqual(extensionTabs, [...extensionTabs].sort((left, right) => left - right))
assert.match(html, /id="tab-maintenance"[^>]*aria-selected="true"/)
assert.match(html, /id="panel-maintenance"[^>]*aria-labelledby="tab-maintenance">/)
assert.match(html, /id="panel-updates"[^>]*hidden>/)
assert.match(script, /void selectTab\('maintenance'\)/)
for (const route of [
'status', 'check', 'update', 'channel', 'automatic-check', 'holds/retry', 'rollback',
'return-stable', 'start-dsh', 'stop-dsh', 'restart-dsh', 'runtime/reset', 'bundled-plugins', 'bundled-plugins/recovery-action',
'bundled-plugins/discard', 'system-skills', 'system-skills/action', 'user-skills', 'user-skills/action', 'user-plugins', 'user-plugins/apply', 'user-plugins/task/', 'logs/stream',
'terminal/sessions',
'files/config', 'files/list', 'files/content', 'files/upload', 'files/download', 'files/tasks',
'proxy/provider-inventory', 'proxy/test', 'proxy/test/tasks/',
]) assert.match(script, new RegExp(route.replace('/', '\\/')))
assert.match(script, /const COPY = Object\.freeze\(\{[\s\S]*zh:[\s\S]*en:/)
assert.match(script, /projected\.enabled \? t\('userPluginEnabled'\) : t\('userPluginDisabled'\)/)
assert.match(script, /skill\.enabled \? t\('userSkillEnabled'\) : t\('userSkillDisabled'\)/)
assert.match(script, /dialogFocusTriggers = new WeakMap/)
assert.match(script, /dialogOpenObserver = new MutationObserver/)
assert.match(html, /<select id="language-switch"[^>]*data-i18n-aria-label="switchLanguage"/)
assert.match(html, /<option value="zh">中文<\/option>[\s\S]*<option value="en">English<\/option>/)
assert.match(html, /<script src="\.\/theme-init\.js"><\/script>[\s\S]*<link rel="stylesheet" href="\.\/style\.css">/)
assert.match(html, /<button id="theme-switch" class="theme-switch"[^>]*>[\s\S]*data-theme-icon="system"[\s\S]*data-theme-icon="light"[\s\S]*data-theme-icon="dark"/)
assert.equal((html.match(/class="theme-icon"[^>]*>[\s\S]*?<svg viewBox="0 0 24 24">/g) ?? []).length, 3)
assert.match(script, /LANGUAGE_KEY = 'dsh-platform:console-language'/)
assert.match(script, /THEME_KEY = 'dsh-platform:console-theme'/)
assert.match(script, /fetch\(`\$\{managementLoginPath\(\)\}\/session-context`/)
assert.match(html, /id="auth-isolation-compare"[\s\S]*id="auth-root-warning"[\s\S]*id="auth-mode"/)
assert.doesNotMatch(html, /authRuntimeTitle|auth-agent-warning/)
assert.match(html, /<form id="auth-settings-form" class="auth-settings-form" method="post" action="" novalidate>/)
assert.match(html, /data-i18n="authMainPasswordTitle">Administrator account<\/h3><button id="auth-account-save"[^>]+data-i18n="authSaveApply"/)
assert.match(html, /id="auth-account-save"[\s\S]*id="auth-username"[\s\S]*id="auth-current-password"/)
assert.match(html, /data-i18n="authOriginTitle">Management origin<\/h3>[\s\S]*id="auth-origin-save"[^>]+data-i18n="authSaveApply"/)
assert.match(html, /id="auth-origin-settings" hidden>[\s\S]*id="auth-origin" type="url"[\s\S]*id="auth-local-port" type="number" min="1" max="65535" step="1" inputmode="numeric" value="3081"[\s\S]*id="auth-origin-detect"/)
assert.doesNotMatch(html, /Compatibility path \(3080\)/)
assert.doesNotMatch(html, /id="auth-settings-save"/)
assert.match(html, /class="auth-additional-heading"[^>]*>[\s\S]*data-i18n="authAdditionalTitle"[\s\S]*class="toggle"[^>]*data-i18n-aria-label="authAdditionalEnabled"[\s\S]*id="auth-additional-enabled"/)
assert.match(html, /class="auth-two-factor auth-additional-heading"[^>]*>[\s\S]*data-i18n="authTotpTitle"[\s\S]*id="auth-totp-enabled"/)
assert.ok(html.indexOf('id="auth-totp-enabled"') < html.indexOf('id="auth-additional-enabled"'))
assert.doesNotMatch(html, /id="auth-totp-fields"/)
assert.match(html, /id="auth-totp-dialog"[\s\S]*id="auth-totp-qr"[\s\S]*id="auth-totp-secret-toggle"[\s\S]*id="auth-totp-code"[\s\S]*id="auth-totp-confirm"/)
assert.doesNotMatch(html, /id="auth-current-additional-password"/)
assert.match(html, /id="auth-additional-fields" class="auth-password-grid" hidden/)
assert.doesNotMatch(html, />Require an additional password for Management</)
assert.match(html, /id="auth-session-list" class="auth-session-list"/)
assert.doesNotMatch(html, /auth-revoke-(?:other|all)-(?:dsh|management)/)
assert.match(style, /\.auth-settings-form \{ display: grid; width: 100%; gap: 16px; \}/)
assert.match(style, /\.auth-password-grid \{[^}]*align-items: start;/)
assert.doesNotMatch(style, /\.auth-settings-form \{[^}]*max-width:/)
assert.match(style, /\.auth-session-revoke \{[^}]*color: var\(--danger\);/)
assert.match(script, /body: \{ sessionId: button\.dataset\.sessionId \}/)
assert.match(html, /id="auth-username"[^>]+pattern="\[\^\\p\{Cc\}/)
assert.match(html, /id="auth-username-error"[^>]+data-i18n="authUsernameFormat"[^>]+hidden/)
assert.match(html, /id="auth-current-password"[^>]+maxlength="1024"/)
assert.doesNotMatch(html, /id="auth-current-password"[^>]+minlength=/)
for (const id of ['auth-password', 'auth-password-confirm', 'auth-additional-password', 'auth-additional-password-confirm']) {
assert.match(html, new RegExp(`id="${id}"[^>]+minlength="8"[^>]+pattern="\\[\\^\\\\p\\{Cc\\}`))
assert.match(html, new RegExp(`id="${id}-error"[^>]+data-i18n="authPasswordFormat"[^>]+hidden`))
}
assert.match(script, /function validateAuthenticationSettingsFormat\(\)/)
assert.match(script, /function validatePasswordConfirmation\(passwordId, confirmationId\)/)
assert.match(script, /function authenticationAccountDraft\(\)/)
assert.match(script, /function validateCurrentPassword\(draft/)
assert.match(script, /function renderAuthenticationAccountSaveState\(\)/)
assert.match(script, /await api\('auth-totp\/enrollments'/)
assert.match(script, /disabling \? 'auth-totp\/disable-confirmations\/confirm' : 'auth-totp\/enrollments\/confirm'/)
assert.match(script, /disabling \? 'auth-totp\/disable-confirmations\/cancel' : 'auth-totp\/enrollments\/cancel'/)
assert.match(script, /await api\(disabling \? 'auth-totp\/disable-confirmations\/confirm'/)
assert.match(script, /function showTotpRetryCountdown\(error\)/)
assert.match(script, /body\.totpEnabled = false[\s\S]*body\.totpDisableConfirmationToken = pendingTotpChange\.confirmation\.confirmationToken/)
assert.match(script, /body\.totpEnabled = true[\s\S]*body\.totpEnrollmentToken = pendingTotpChange\.enrollment\.enrollmentToken/)
assert.match(script, /pending\.confirmed = true[\s\S]*showAuthenticationStatus\(t\('authTotpConfirmedDraft'\)\)/)
assert.match(script, /elements\['auth-totp-enabled'\]\.addEventListener\('change',[\s\S]*changeTotpEnabled/)
assert.match(script, /function trapTotpDialogFocus\(event\)[\s\S]*event\.key !== 'Tab'[\s\S]*elements\['auth-totp-dialog'\]\.addEventListener\('keydown', trapTotpDialogFocus\)/)
assert.match(script, /if \(resetToggle\) elements\['auth-totp-enabled'\]\.focus\(\{ preventScroll: true \}\)/)
assert.match(script, /function discardTotpChangeOnPageLeave\(\)[\s\S]*keepalive: true[\s\S]*window\.addEventListener\('pagehide', discardTotpChangeOnPageLeave\)/)
assert.match(script, /auth-account-save'\]\.disabled = totpUnverified \|\| !accountDraftChanged\(\)/)
assert.match(style, /\.auth-totp-control\[data-state="unverified"\][^}]+background: var\(--warning\)/)
assert.match(script, /if \(!accountDraftChanged\(draft\)\) return/)
assert.match(script, /authCurrentPasswordRequired: '请输入当前主密码。'/)
assert.match(script, /authCurrentPasswordIncorrect: '当前主密码不正确。'/)
assert.match(script, /authManagementPasswordRequired: '请输入新的管理中心密码。'/)
assert.match(script, /renderPasswordConfirmation\('auth-password', 'auth-password-confirm'/)
assert.match(script, /renderPasswordConfirmation\('auth-additional-password', 'auth-additional-password-confirm'/)
assert.match(script, /'TOTP_DISABLE_CONFIRMATION_INVALID'/)
assert.match(script, /error\.code === 'FRESH_AUTH_FAILED'/)
assert.match(script, /authSavedAllSessionsRevoked/)
assert.match(script, /authSavedManagementSessionsRevoked/)
assert.match(script, /window\.location\.replace\(returnPath\)/)
assert.match(script, /window\.location\.assign\(new URL\(['"]\/['"], result\.loginOrigin\)\)/)
assert.doesNotMatch(script, /window\.location\.(?:assign|replace)\(new URL\('\/auth\/management'/)
assert.match(script, /const continuationOrigin = typeof result\.targetOrigin === 'string'/)
assert.match(script, /isolatedEntry\?\.managementLocalOrigin/)
assert.match(script, /function renderAdditionalPasswordFields\(\)[\s\S]*auth-additional-fields'/)
assert.match(script, /authenticationSettings\?\.account\?\.managementAdditionalCredential\?\.enabled === true[\s\S]*session\.managementActive === true/)
assert.match(script, /auth-additional-enabled'\]\.addEventListener\('change'[\s\S]*renderAdditionalPasswordFields/)
assert.match(script, /authMainPasswordTitle: '管理员账户'/)
assert.match(script, /authMainPasswordTitle: 'Administrator account'/)
assert.match(script, /authCurrentPasswordPlaceholder: '请输入当前主密码'/)
assert.match(script, /authCurrentPasswordPlaceholder: 'Enter the current main password'/)
assert.match(script, /authAdditionalTitle: '管理中心密码'/)
assert.match(script, /authAdditionalTitle: 'Management console password'/)
assert.match(script, /authNewPassword: '新密码'/)
assert.match(script, /authConfirmPassword: '确认密码'/)
assert.match(script, /authAdditionalPassword: '新密码'/)
assert.match(script, /authConfirmAdditionalPassword: '确认密码'/)
assert.match(script, /async function saveAccountSettings\(\)[\s\S]*auth-account-save'[\s\S]*api\('auth-settings'/)
assert.match(script, /async function saveManagementOrigin\(\)[\s\S]*auth-origin-save'[\s\S]*changeManagementOrigin/)
assert.match(script, /management-origin\/transitions\/failure/)
assert.match(script, /stage: 'browser-probe'/)
assert.match(script, /mode: access\.mode/)
assert.match(script, /auth-origin-settings'\]\.hidden = !isolated/)
assert.match(script, /auth-public-origin-field'\]\.hidden = selected !== 'isolated-public'/)
assert.match(script, /auth-local-port-field'\]\.hidden = !local/)
assert.match(script, /authLocalPort: '宿主机端口'/)
assert.match(script, /const accessInput = elements\['auth-mode'\]\.value === 'isolated-local'[\s\S]*elements\['auth-local-port'\][\s\S]*elements\['auth-origin'\]/)
assert.match(script, /!accessInput\.reportValidity\(\)/)
assert.match(script, /changeManagementOrigin\(nextAccess\)/)
assert.doesNotMatch(html, /auth-origin-current-password/)
assert.doesNotMatch(script, /saveAuthenticationSettings/)
assert.match(script, /elements\[confirmationId\]\.addEventListener\('input'[\s\S]*renderPasswordConfirmation/)
assert.match(script, /auth-username'\]\.addEventListener\('input'/)
assert.match(html, /id="auth-public-origin-field"[\s\S]*id="auth-origin"[\s\S]*id="auth-local-port-field" hidden[\s\S]*id="auth-local-port"[\s\S]*id="auth-origin-detect"/)
assert.match(html, /id="auth-isolation-dialog"[\s\S]*class="auth-comparison-table"/)
assert.match(html, /id="auth-isolation-confirm-dialog"[\s\S]*data-i18n="authIsolationConfirm"/)
assert.match(script, /function detectedManagementOrigin\(\)[\s\S]*value\.port = '3081'/)
assert.match(script, /option\.disabled = rootEnabled && accessMode\(option\.value\) !== currentMode/)
assert.doesNotMatch(html, /authComparisonAgent|Agent process isolation|Agent 进程隔离/)
assert.match(script, /modeChanged && nextAccess\.mode === 'isolated' && !await confirmIsolationEnable\(\)/)
assert.match(script, /function clearProxySecrets\(\)[\s\S]*elements\['proxy-password'\]\.value = ''/)
assert.doesNotMatch(script, /function sharedDshProxyEnabled\(\)/)
assert.doesNotMatch(script, /data-provider-follow|followDsh/)
assert.match(script, /function localizedProxyTestDetail\(stage, fallback\)/)
assert.match(script, /detail\.textContent = localizedProxyTestDetail\(stage, status\)/)
assert.match(script, /proxyStageDetailAddress: '已解析 \{count\} 个代理地址记录。'/)
assert.match(script, /proxyStageDetailAddress: 'Resolved \{count\} proxy address record\(s\)\.'/)
assert.match(style, /\.proxy-provider-route \{[^}]*background: var\(--surface-raised\)/)
assert.match(style, /proxy-test-stage\[data-state="running"\][^{]*\{[^}]*animation: spin/)
assert.match(style, /progress-stage-marker\.active::before[^{]*\{[^}]*animation: spin/)
assert.match(script, /function saveProxyConfiguration\(\)[\s\S]*proxyCandidate\(\)/)
assert.doesNotMatch(script, /function saveProxyRules\(/)
assert.match(script, /function saveProxyImmediate\(mutate\)[\s\S]*rules: 'saved'/)
assert.match(script, /function proxyCandidate\([\s\S]*enabled: configuration\.enabled === true/)
assert.match(script, /saveProxyImmediate\(configuration => \{ configuration\.enabled = event\.target\.checked \}\)/)
assert.match(script, /const componentUnavailable = configuration\.componentReady === false/)
assert.match(script, /proxy-enabled'\]\.disabled = componentUnavailable/)
assert.match(script, /proxy-protocol', 'proxy-host', 'proxy-port', 'proxy-username', 'proxy-password'/)
assert.match(script, /proxy-clear-password', 'proxy-advanced-toggle', 'proxy-direct-rules'/)
assert.match(script, /proxy-system-rules', 'proxy-remote-dns', 'proxy-provider-search', 'proxy-scope-help'/)
assert.match(script, /for \(const input of document\.querySelectorAll\('\[data-proxy-scope\]'\)\)[\s\S]*input\.disabled = componentUnavailable/)
assert.match(script, /proxy-all-proxy'\]\.disabled = componentUnavailable/)
assert.match(script, /proxy-test'\]\.disabled = componentUnavailable/)
assert.match(script, /proxy-save'\]\.disabled = componentUnavailable/)
assert.match(script, /proxy-password'\]\.disabled = proxyConfiguration\?\.componentReady === false/)
assert.match(script, /draft\.clearPassword === 'true'[\s\S]*proxyConfiguration\?\.componentReady === false/)
assert.match(script, /const componentUnavailable = proxyConfiguration\?\.componentReady === false[\s\S]*proxy-test'\]\.disabled = running \|\| componentUnavailable/)
assert.match(script, /proxy-component-alert'\]\.hidden = !componentUnavailable/)
assert.match(script, /proxy-component-alert'[\s\S]*proxy-component-dialog'\]\.showModal/)
assert.doesNotMatch(script, /proxyReadyShort|proxyUnavailableShort/)
assert.match(script, /function renderProxySaveState\(\{ saved = false \} = \{\}\)[\s\S]*proxyUnsaved[\s\S]*3000/)
assert.match(script, /const displayName =[\s\S]*return query === '' \|\| displayName\.toLocaleLowerCase\(\)\.includes\(query\)/)
assert.doesNotMatch(script, /\[provider\.displayName, provider\.id, provider\.type\]/)
assert.doesNotMatch(script, /(?:localStorage|sessionStorage)\.setItem\([^\n]*proxy-password/)
assert.match(html, /id="proxy-transport-warning"[^>]*data-i18n="proxyTransportWarning"/)
assert.match(html, /id="proxy-scope-dialog"[\s\S]*id="proxy-scope-catalog"/)
assert.match(script, /const override = storageValue\(LANGUAGE_KEY\)[\s\S]*navigator\.language[\s\S]*=== 'zh' \? 'zh' : 'en'/)
assert.doesNotMatch(script, /name === 'dsh_locale'/)
assert.match(script, /switchLanguage: '语言'/)
assert.match(script, /switchLanguage: 'Language'/)
assert.match(script, /elements\['language-switch'\]\.value = locale/)
assert.match(script, /elements\['language-switch'\]\.addEventListener\('change',[\s\S]*writeStorage\(LANGUAGE_KEY, event\.target\.value\)[\s\S]*window\.location\.reload\(\)/)
assert.match(script, /THEME_ORDER = Object\.freeze\(\['system', 'light', 'dark'\]\)/)
assert.match(script, /elements\['theme-switch'\]\.addEventListener\('click',[\s\S]*writeStorage\(THEME_KEY,[\s\S]*applyTheme\(themePreference\)[\s\S]*renderThemeControl\(\)/)
assert.match(script, /document\.documentElement\.dataset\.theme = preference[\s\S]*delete document\.documentElement\.dataset\.theme/)
assert.match(script, /checkUpdates\('page-open'\)/)
assert.match(script, /if \(statusLoad !== undefined\) return statusLoad/)
assert.match(script, /statusLoadRevision \+= 1/)
assert.match(script, /while \(loadedRevision !== statusLoadRevision\)/)
const statusLoader = script.slice(script.indexOf('function loadStatus()'), script.indexOf('async function discardSystemPluginDraft()'))
assert.match(statusLoader, /next = await api\('status'\)[\s\S]*setConnection\('online'\)/)
assert.doesNotMatch(statusLoader, /loadInventory|loadInventories/)
assert.match(script, /if \(inventoryLoads\[key\] !== undefined\) return inventoryLoads\[key\]/)
assert.match(script, /inventoryLoadRevisions\[key\] \+= 1[\s\S]*while \(loadedRevision !== inventoryLoadRevisions\[key\]\)/)
const inventoryLoader = script.slice(script.indexOf('const INVENTORY_LOADERS'), script.indexOf('function loadStatus()'))
for (const [key, route] of [['plugins', 'bundled-plugins'], ['systemSkills', 'system-skills'], ['userSkills', 'user-skills'], ['userPlugins', 'user-plugins']]) {
assert.match(inventoryLoader, new RegExp(`${key}: Object\\.freeze\\(\\{ path: '${route}'`))
}
assert.match(inventoryLoader, /loader\.apply\(await api\(loader\.path\)\)[\s\S]*inventoriesLoaded\[key\] = true[\s\S]*render\(status\)/)
assert.doesNotMatch(inventoryLoader, /Promise\.all\(\[[\s\S]*bundled-plugins[\s\S]*system-skills/)
assert.match(script, /function renderUserSkills\(busy\)[\s\S]*userSkillInventory\.skills/)
assert.match(script, /function renderUserSkills\(busy\)[\s\S]*row\.className = 'user-plugin-row'/)
assert.match(script, /expandedUserSkillDescriptions\.has\(skill\.entryId\)[\s\S]*description\.className = `user-plugin-description/)
assert.match(script, /description\.scrollWidth > description\.clientWidth[\s\S]*description\.classList\.add\('expandable'\)/)
assert.match(script, /heading\.append\(userPluginBadge\([\s\S]*identity\.append\(heading, description, metadata\)/)
assert.match(script, /requestConfirmation\(\{[\s\S]*deleteUserSkillTitle[\s\S]*deleteUserSkillDetail/)
assert.match(script, /runSkillTask\('user-skills\/action', \{[\s\S]*entryId: skill\.entryId, revision: userSkillInventory\.revision, action/)
assert.match(script, /function waitForManagementTask\(taskId, operationKey\)[\s\S]*operation\?\.taskId === taskId[\s\S]*operation\.status !== 'running'/)
assert.match(script, /function runSkillTask\(path, body, operationKey\)[\s\S]*waitForManagementTask\(task\.taskId, operationKey\)[\s\S]*refreshInventory\(operationKey === 'systemSkillOperation' \? 'systemSkills' : 'userSkills'\)/)
assert.match(script, /system-skills\/action'[\s\S]*systemSkillOperation/)
assert.match(script, /user-skills\/action'[\s\S]*userSkillOperation/)
assert.match(script, /inventoryKeyForTab\(tab[\s\S]*'user-skills': 'userSkills'/)
assert.match(script, /userSkillsTab: '用户技能'/)
assert.match(script, /userSkillsTab: 'User skills'/)
assert.match(script, /const inventoryKey = inventoryKeyForTab\(tab\)[\s\S]*void loadInventory\(inventoryKey\)/)
assert.match(script, /if \(inventoriesLoaded\.plugins\) renderBundledPlugins/)
assert.match(script, /if \(inventoriesLoaded\.userSkills\) renderUserSkills/)
assert.match(script, /LIST_PAGE_SIZES = Object\.freeze\(\[5, 10, 20, 50\]\)/)
assert.match(script, /LIST_PAGE_SIZE_KEY_PREFIX = 'dsh-platform:console-page-size:'/)
assert.match(script, /function paginated\(key, values\)[\s\S]*values\.slice\(start, start \+ pageSize\)/)
assert.match(script, /elements\[`\$\{prefix\}-pagination`\]\.hidden = false/)
assert.match(script, /writeStorage\(`\$\{LIST_PAGE_SIZE_KEY_PREFIX\}\$\{key\}`/)
assert.match(script, /const userPluginDraft = new Map\(\)[\s\S]*for \(const plugin of paginated\('userPlugins', filtered\)\)/)
assert.match(script, /function filteredResources\(key, values\)[\s\S]*listQueries\[key\]/)
assert.match(script, /function resourceSearchValues\(key, value\) \{[\s\S]*if \(key === 'plugins' \|\| key === 'systemSkills'\) return \[value\.id\][\s\S]*if \(key === 'userSkills'\) return \[value\.name \?\? value\.entryName\][\s\S]*return \[value\.name\]/)
const resourceSearch = script.slice(script.indexOf('function resourceSearchValues('), script.indexOf('function filteredResources('))
assert.doesNotMatch(resourceSearch, /value\.(?:description|version|spec|source)/)
assert.match(script, /function expandableResourceDescription[\s\S]*scrollWidth > description\.clientWidth/)
assert.match(script, /function captureScrollablePositions\(element, includeElement = false\)[\s\S]*current\.scrollTop/)
assert.match(script, /function restoreScrollablePositions\(positions\)[\s\S]*current\.scrollTop = top[\s\S]*requestAnimationFrame/)
for (const [renderer, list] of [
['renderBundledPlugins', 'bundled-plugins'], ['renderSystemSkills', 'system-skills'],
['renderUserSkills', 'user-skills'], ['renderUserPlugins', 'user-plugin-list'],
]) {
const start = script.indexOf(`function ${renderer}(`)
const end = script.indexOf('\nfunction ', start + 1)
const source = script.slice(start, end)
assert.match(source, new RegExp(`captureScrollablePositions\\(elements\\['${list}'\\], true\\)`))
assert.match(source, /restoreScrollablePositions\(scrollPositions\)/)
}
assert.match(script, /function render\(next\) \{[\s\S]*\.resource-panel:not\(\[hidden\]\)[\s\S]*captureScrollablePositions\(activeResourcePanel, true\)[\s\S]*restoreScrollablePositions\(resourcePanelScrollPositions\)/)
assert.match(script, /function toggleExpandedElement[\s\S]*preserveScrollableAncestors\(element, \(\) =>/)
assert.match(script, /identity\.append\(\s*heading,\s*expandableResourceDescription\(pluginDescription\(plugin\)/)
assert.match(script, /identity\.append\(\s*heading,\s*expandableResourceDescription\(skill\.description/)
assert.match(style, /\.plugin-identity > \.resource-description \{[^}]*display: block;[^}]*margin-top: 2px;/)
assert.match(style, /\.user-plugin-main dl \{[^}]*grid-template-columns: repeat\(3, minmax\(0, 1fr\)\);/)
assert.match(style, /\.user-plugin-main > \.user-plugin-description \{[^}]*display: block;[^}]*width: 100%;[^}]*margin-top: 2px;/)
assert.match(script, /function expandableUserMetadata\(metadata, identity, expanded\)[\s\S]*value\.scrollWidth > value\.clientWidth/)
assert.match(script, /function toggleExpandedElement\(element, identity, expanded\)[\s\S]*classList\.toggle\('expanded', isExpanded\)/)
assert.doesNotMatch(script, /expandedUserSkillDescriptions[\s\S]{0,300}renderUserSkills\(runtimeBusy\(\)\)/)
assert.doesNotMatch(script, /expandedUserPluginDescriptions[\s\S]{0,300}renderUserPlugins\(runtimeBusy\(\)\)/)
assert.match(script, /expandedUserSkillMetadata[\s\S]*expandableUserMetadata\(metadata, skill\.entryId/)
assert.match(script, /expandedUserPluginMetadata[\s\S]*expandableUserMetadata\(metadata, plugin\.name/)
assert.match(style, /\.user-plugin-main dt, \.user-plugin-main dd \{[^}]*overflow: hidden;[^}]*text-overflow: ellipsis;[^}]*white-space: nowrap;/)
assert.match(style, /\.user-plugin-metadata\.expanded dd \{[^}]*overflow-wrap: anywhere;[^}]*white-space: normal;/)
assert.equal((style.match(/\.user-plugin-main dl \{/g) ?? []).length, 1)
for (const prefix of ['plugins', 'system-skills', 'user-skills', 'user-plugins']) {
assert.match(html, new RegExp(`id="${prefix}-search"`))
assert.match(html, new RegExp(`id="${prefix}-page-size"`))
assert.match(html, new RegExp(`id="${prefix}-page-previous"`))
assert.match(html, new RegExp(`id="${prefix}-page-next"`))
assert.match(html, new RegExp(`id="${prefix}-page-current"`))
assert.match(html, new RegExp(`id="${prefix}-page-jump"`))
}
for (const [emptyId, paginationId] of [
['empty-plugins', 'plugins-pagination'],
['empty-user-plugins', 'user-plugins-pagination'],
['empty-skills', 'system-skills-pagination'],
['empty-user-skills', 'user-skills-pagination'],
]) assert.equal(html.indexOf(`id="${emptyId}"`) < html.indexOf(`id="${paginationId}"`), true)
assert.match(html, /class="management-navigation"/)
assert.doesNotMatch(html, /class="page-heading"/)
assert.doesNotMatch(script, /intro: 'DSH Docker/)
assert.equal((html.match(/class="tab-panel resource-panel"/g) ?? []).length, 4)
assert.match(style, /html \{[^}]*height: 100%;[^}]*overflow: hidden;/)
assert.match(style, /body \{[^}]*height: 100dvh;[^}]*overflow: hidden;/)
assert.match(style, /main \{[^}]*height: calc\(100dvh - 64px\);[^}]*overflow: hidden;/)
assert.match(style, /body \{ position: fixed; inset: 0; width: 100%; height: 100dvh;[^}]*overflow: hidden; \}/)
assert.match(style, /\.management-navigation \{[^}]*width: 100%;[^}]*min-width: 0;[^}]*max-width: 100%;[^}]*flex: none;[^}]*background: var\(--bg\);/)
assert.doesNotMatch(style, /\.management-navigation \{[^}]*padding-top:/)
assert.doesNotMatch(style, /\.page-heading/)
assert.match(style, /\.tab-panel \{[^}]*min-height: 0;[^}]*flex: 1;[^}]*overflow-y: auto;[^}]*scrollbar-gutter: stable;/)
assert.match(style, /\.resource-panel \.plugin-list, \.resource-panel \.user-plugin-list \{[^}]*max-height: min\(52dvh, 520px\);[^}]*flex: 0 1 auto;[^}]*overflow-y: auto;/)
assert.match(style, /\.resource-panel \.plugin-list \{ min-height: 60px; \}/)
assert.match(style, /\.resource-panel \.user-plugin-list \{ min-height: 96px; \}/)
assert.match(style, /@media \(max-width: 640px\)[\s\S]*\.resource-panel \.plugin-list \{ min-height: 122px; \}[\s\S]*\.resource-panel \.user-plugin-list \{ min-height: 170px; \}/)
assert.match(style, /\.resource-panel \.list-pagination \{[^}]*position: static;/)
assert.doesNotMatch(style, /max-height: min\(calc\(56\.25vw - 27px\), 664px\)/)
assert.match(script, /commitListPageJump/)
assert.match(script, /Math\.min\(lastPage, Math\.max\(0, value - 1\)\)[\s\S]*input\.value = String\(listPages\[key\] \+ 1\)/)
assert.match(script, /listQueries\[key\] = event\.target\.value[\s\S]*listPages\[key\] = 0/)
assert.match(script, /connectEvents\(\)[\s\S]*void \(async \(\) => \{[\s\S]*const initial = await loadStatus\(\)/)
assert.doesNotMatch(script, /^await /m)
assert.match(script, /initial !== undefined && UPDATE_TERMINAL_STATES\.has/)
assert.match(script, /discardingPluginDraft[\s\S]*renderBundledPlugins\(plugins, pluginBusy\)/)
assert.match(script, /for \(const \[id, action\] of systemPluginDraft\) systemPluginApplyingDraft\.set\(id, action\)[\s\S]*waitForManagementTask/)
assert.match(script, /await discardSystemPluginDraft\(\)[\s\S]*checkUpdates\('page-open'\)/)
assert.doesNotMatch(script, /NOTICE_PREFIX|notificationCandidates|renderReminder|candidateIdentity/)
assert.doesNotMatch(html, /id="update-reminder"|id="reminder-later"|id="reminder-dismiss"/)
assert.doesNotMatch(style, /\.update-reminder/)
assert.match(script, /updateNotifications: '更新提醒'/)
assert.match(script, /updateNotifications: 'Update notifications'/)
assert.match(script, /updateNotificationsDetail: '自动检查发现新版本时,在 DSH 页面弹窗提醒更新。'/)
assert.match(script, /LOG_CLEAR_CUTOFF_KEY = 'dsh-platform:log-clear-cutoff'/)
assert.match(script, /sessionStorage\.setItem\(LOG_CLEAR_CUTOFF_KEY, logClearCutoff\)/)
assert.match(script, /timestamp <= Date\.parse\(logClearCutoff\)/)
assert.match(script, /DEFAULT_LOG_DISPLAY_LIMIT = 500/)
assert.match(script, /limitProcessedLogEntries\(logEntries, logDisplayLimit\)/)
assert.match(script, /expandedLogIdentities/)
assert.match(script, /details\.textContent = JSON\.stringify\(entry, null, 2\)/)
assert.match(script, /article\.setAttribute\('aria-expanded'/)
assert.match(script, /chevron\.className = 'log-chevron'/)
assert.match(script, /meta\.append\(levelLabel, sourceLabel, time\)/)
assert.match(script, /messageRow\.append\(message, chevron\)/)
assert.match(script, /message\.textContent = display\(logMessageSummary\(entry\.message\)\)/)
assert.match(script, /total: logDisplayLimit/)
assert.match(script, /writeStorage\(LOG_DISPLAY_LIMIT_KEY, String\(value\)\)/)
assert.match(html, /id="log-limit"/)
assert.match(script, /tab === 'maintenance' && autoScroll[\s\S]*requestAnimationFrame[\s\S]*scrollTop = elements\['log-list'\]\.scrollHeight/)
const checkUpdates = script.slice(script.indexOf('async function checkUpdates('), script.indexOf('async function saveAutomaticCheck('))
assert.match(checkUpdates, /await api\('check'/)
assert.doesNotMatch(checkUpdates, /await act\(/)
assert.match(html, /id="plugin-restart-required"/)
assert.match(html, /id="system-plugin-draft-summary"/)
assert.match(html, /data-channel="stable" aria-pressed="true"/)
assert.match(html, /id="upstream-version" hidden/)
assert.match(html, /id="update"[^>]*disabled/)
assert.match(html, /id="cancel-system-plugin-changes"/)
assert.match(html, /id="apply-system-plugin-changes"/)
assert.match(html, /id="runtime-reset"[^>]*aria-controls="runtime-reset-confirmation"[^>]*aria-expanded="false"/)
assert.match(html, /id="runtime-reset-confirmation"[^>]*hidden/)
assert.match(script, /runtimeReset: '重置运行时'/)
assert.match(script, /runtimeReset: 'Reset runtime'/)
assert.match(script, /function setRuntimeResetExpanded\(expanded\)/)
assert.match(script, /await act\('runtime\/reset', \{ method: 'POST' \}\)/)
assert.match(script, /next\?\.runtimeReset\?\.status === 'resetting'/)
assert.equal(html.indexOf('id="plugin-restart-required"') < html.indexOf('id="bundled-plugins"'), true)
assert.match(script, /plugins\.some\(plugin => plugin\.pendingRestart\)/)
assert.match(pluginSource, /statusLoadRevision\.current \+= 1/)
assert.match(pluginSource, /if \(statusLoad\.current !== undefined\) return statusLoad\.current/)
assert.match(pluginSource, /while \(loadedRevision !== statusLoadRevision\.current\)/)
assert.match(pluginSource, /const API = '\/_dsh_platform\/plugin-api\/v1'/)
assert.equal(pluginSource.match(/href: managementConsoleHref/g)?.length, 2)
assert.doesNotMatch(pluginSource, /href: '\/_dsh_platform\/auth\/management\/start/)
assert.doesNotMatch(pluginSource, /platformAuthRequired|platformSignIn|authRequired/)
assert.match(script, /pluginChangesPending: '有待应用的修改'/)
assert.match(html, /id="update-progress" class="update-progress"/)
assert.match(html, /id="progress-stage-log" class="progress-stage-log" hidden/)
assert.match(html, /id="progress-dismiss"[\s\S]*data-i18n="dismissProgress"/)
assert.doesNotMatch(html, /id="progress-steps"|id="progress-metrics"|id="progress-detail"/)
assert.match(script, /function progressStageDefinitions\(update\)/)
assert.match(script, /function stageMetricLines\(value, stage, state\)/)
assert.match(script, /function stageItems\(stage, update, state\)/)
assert.match(script, /stageItemsCompleted: '已完成 \{completed\}\/\{total\} 项'/)
assert.match(script, /itemMarker\.textContent = ''/)
assert.match(script, /metricBytesCopied: '已复制 \{processed\} \/ \{total\}'/)
assert.match(script, /metricArtifacts: '已验证 \{processed\} \/ \{total\} 个 Artifact'/)
assert.match(script, /function probationRemainingSeconds\(update\)[\s\S]*probation:\(\\d\+\)/)
assert.match(script, /metricProbationRemaining: '剩余观察 \{seconds\} 秒'/)
assert.match(script, /taskId: String\(taskId\), operation: String\(update\.operation \?\? 'update'\), limit: '1000'/)
assert.match(script, /function progressLogStage\(phase, update = progressLogUpdate\)/)
assert.match(script, /function isRecoveryOperation\(operation\)[\s\S]*operation === 'return-stable'/)
assert.match(script, /returnStableProgress: '返回稳定通道'/)
assert.match(script, /'restoring-data': 3/)
assert.match(script, /const UPDATE_RECOVERY_STAGE_ITEMS = Object\.freeze\(\[[\s\S]*'itemSwitchPrevious'[\s\S]*'itemRestoreSnapshot'[\s\S]*'itemStartRuntime'[\s\S]*'itemCheckHealth'/)
assert.match(script, /phase === 'restoring-data'[\s\S]*'recovery:snapshot': 1[\s\S]*'recovery:health': 3/)
assert.match(script, /returnStableToTarget: '返回稳定通道·\{target\}'/)
assert.match(script, /progressLogStageExpansion\.set\(previousActiveStage, false\)/)
assert.match(script, /function transactionStageState\(index, currentIndex, status\)[\s\S]*status === 'success'[\s\S]*return 'completed'/)
assert.match(script, /progressLogStageExpansion\.set\(activeStage\.key, update\.status !== 'success'\)/)
assert.match(script, /elements\.progress\.dataset\.complete = String\(progress === 100\)/)
assert.match(script, /stageSummary\.addEventListener\('click',[\s\S]*progressLogStageTouched\.add\(group\.key\)/)
assert.match(script, /toggle\.addEventListener\('click',[\s\S]*const nextOpen = !stageDetails\.open[\s\S]*stageDetails\.open = nextOpen/)
assert.match(script, /stageDetails\.addEventListener\('toggle',[\s\S]*toggle\.textContent = t\(stageDetails\.open \? 'collapseStage' : 'expandStage'/)
assert.match(script, /progressLogStageExpansion\.set\(group\.key, nextOpen\)[\s\S]*toggle\.textContent = t\(nextOpen \? 'collapseStage' : 'expandStage'/)
assert.match(script, /if \(update\.status === 'success'\) \{\s*if \(previousStatus !== 'success'\) \{[\s\S]*progressLogStageExpansion\.set\(activeStage\.key, false\)/)
assert.doesNotMatch(script, /if \(update\.status === 'success'\) \{\s*if \(previousStatus !== 'success'\) progressLogStageTouched\.delete\(activeStage\.key\)\s*progressLogStageExpansion\.set\(activeStage\.key, false\)/)
assert.doesNotMatch(script, /stageDetails\.addEventListener\('toggle',[\s\S]{0,160}progressLogStageTouched\.add/)
assert.match(script, /function progressLogPhase\(update\) \{[\s\S]*update\?\.phase[\s\S]*update\?\.operation[\s\S]*update\?\.status/)
assert.match(script, /progressLogAutoScroll = event\.target\.checked/)
assert.match(script, /elements\['log-search'\]\.value = String\(progressLogUpdate\.taskId\)/)
assert.match(script, /const failedDismissed = update\.status === 'failed'[\s\S]*dismissedProgressTaskId/)
assert.match(script, /const result = progressVisible \|\| failedDismissed \? '' : update\.error/)
assert.match(script, /elements\['progress-dismiss'\]\.addEventListener\('click'/)
assert.match(style, /\.progress-log-group-list[\s\S]*max-height: 250px/)
assert.match(style, /\.progress\[data-complete='true'\] span \{ width: 100% !important; transition: none; \}/)
assert.match(style, /\.progress-log-group-list\.populated \{ height: clamp\(160px, 24dvh, 240px\);/)
assert.doesNotMatch(style, /\.progress-log-entry:last-child \{[^}]*border-bottom: 0;/)
assert.match(style, /\.progress-log-entry summary[\s\S]*grid-template-columns: auto minmax\(0, 1fr\) auto/)
assert.match(style, /\.progress-log-message \{[^}]*grid-column: 1 \/ 3;/)
assert.match(script, /chevron\.className = 'progress-log-chevron'/)
assert.match(style, /\.progress-log-entry\[open\] \.progress-log-chevron::before \{ transform: rotate\(180deg\); \}/)
assert.match(script, /rollbackDetailData: '正在校验并恢复更新前的数据快照。'/)
assert.match(style, /\.progress-stage-marker \{ --marker-size: 10px;/)
assert.match(style, /\.progress-stage-item-marker \{ --marker-size: 10px;/)
assert.doesNotMatch(script, /[✓⟳✗○]/u)
assert.match(script, /pluginChangesPending: 'Changes pending'/)
assert.match(script, /pendingSystemPluginChanges: '有 \{count\} 项修改待应用'/)
assert.match(script, /systemPluginApplyingItem: '\{action\} @dsh-docker\/\{id\}(\{current\}\/\{total\})'/)
assert.match(script, /function systemPluginSummary\(\)[\s\S]*systemPluginProgress\?\.phase === 'restarting'[\s\S]*pendingSystemPluginChanges/)
assert.match(script, /function reconcileSystemPluginProgress\(next\)[\s\S]*lifecycle\?\.taskId !== systemPluginProgress\.taskId[\s\S]*\['running', 'failed', 'stopped'\]/)
assert.match(script, /systemPluginProgress = \{ phase: 'restarting', total: changes\.length, taskId: restart\.taskId \}/)
assert.match(script, /systemPluginProgress = \{ phase: 'applying', id, action, current: index \+ 1, total: changes\.length \}/)
assert.match(script, /userPluginRestartRequired: '需要重新启动 DSH'/)
assert.match(script, /userPluginRestartRequired: 'Restart DSH required'/)
assert.doesNotMatch(html, /id="user-plugin-restart-required"/)
assert.match(script, /const applyingAction = userPluginApplyingDraft\.get\(plugin\.name\)[\s\S]*plugin\.pendingRestart[\s\S]*pluginPendingRestart/)
assert.match(script, /const userPluginApplyingDraft = new Map\(\)/)
assert.match(script, /const applyingAction = userPluginApplyingDraft\.get\(plugin\.name\)[\s\S]*statusEnabling[\s\S]*statusDisabling[\s\S]*statusUninstalling/)
assert.match(script, /for \(const \[name, action\] of userPluginDraft\) userPluginApplyingDraft\.set\(name, action\)[\s\S]*await refreshInventory\('userPlugins'\)[\s\S]*userPluginApplyingDraft\.clear\(\)/)
assert.match(script, /plugin\.description\?\.\[locale\]/)
assert.match(script, /pluginPendingRestart: '待重启'/)
assert.match(script, /PLUGIN_DRAFT_KEY = 'dsh-platform:system-plugin-draft'/)
assert.match(script, /const systemPluginDraft = new Map\(\)/)
assert.match(script, /function setSystemPluginDraft\(plugin, action\)[\s\S]*systemPluginDraft\.set\(plugin\.id, action\)/)
assert.match(script, /const restartRequired = systemPluginDraft\.size > 0 \|\| values\.some\(plugin => plugin\.pendingRestart\)[\s\S]*const applyingAction = restartRequired[\s\S]*systemPluginApplyingDraft\.get\(plugin\.id\)/)
assert.match(script, /userPluginBadge\(t\(stateKey[\s\S]*applyingAction !== undefined \|\| action !== undefined \? 'pending' : plugin\.enabled \? 'enabled'/)
const systemPluginRenderer = script.slice(script.indexOf('function renderBundledPlugins('), script.indexOf('function renderSystemSkills('))
assert.doesNotMatch(systemPluginRenderer, /pluginPendingRestart/)
assert.match(systemPluginRenderer, /action !== undefined[\s\S]*pendingInstall[\s\S]*pendingUninstall[\s\S]*pendingEnable[\s\S]*pendingDisable/)
assert.match(script, /function pluginButton\([\s\S]*setSystemPluginDraft\(plugin, action\)/)
assert.match(script, /async function applySystemPluginDraft\(\)[\s\S]*for \(const \[id, action\] of systemPluginDraft\)[\s\S]*waitForManagementTask\(task\.taskId, 'systemPluginOperation'\)[\s\S]*api\('restart-dsh'/)
assert.match(script, /operationKey === 'systemPluginOperation'[\s\S]*api\(`bundled-plugins\/task\/\$\{taskId\}`\)/)
assert.match(script, /async function cancelSystemPluginDraft\(\)[\s\S]*systemPluginDraft\.clear\(\)[\s\S]*bundled-plugins\/discard/)
assert.match(script, /function hasTaskId\(operation\)[\s\S]*typeof operation\?\.taskId === 'string'[\s\S]*operation\.taskId\.length > 0/)
assert.match(script, /restart\.state === 'running' && hasTaskId\(restart\)[\s\S]*sessionStorage\.removeItem\(PLUGIN_DRAFT_KEY\)/)
assert.doesNotMatch(script, /if \(hadDraft\) sessionStorage\.removeItem\(PLUGIN_DRAFT_KEY\)/)
assert.match(script, /\(acting && !checking\)/)
assert.match(script, /const checkingProgress = update\.operation === 'check'[\s\S]*checkingProgress[\s\S]*t\('statusChecking'\)[\s\S]*updateToTarget/)
assert.doesNotMatch(script, /可离线恢复|Offline recovery|recovery-badge/)
assert.doesNotMatch(script, /插件设置并重启 DSH|settings and restarting DSH/)
assert.doesNotMatch(script, /shell\.overlay|settings\.section|dsh-platform:update-notice-owner/)
assert.doesNotMatch(script, /^import .*vendor\/xterm\.mjs/m)
assert.match(script, /import\('\.\/vendor\/xterm\.mjs'\)/)
assert.match(script, /import\('\.\/vendor\/addon-fit\.mjs'\)/)
assert.match(script, /terminalLoading: '正在加载终端组件'/)
assert.match(script, /terminalLoading: 'Loading terminal components'/)
assert.match(script, /cursorStyle: 'block'/)
assert.match(script, /cursorInactiveStyle: 'outline'/)
assert.match(style, /#terminal-screen \.xterm-viewport \{ position: static;/)
assert.match(script, /const badge = applyingAction[\s\S]*plugin\.pendingRestart[\s\S]*plugin\.reservedNameConflict[\s\S]*plugin\.damaged[\s\S]*plugin\.enabled/)
assert.match(script, /const applying = operation\.status === 'running'[\s\S]*hidden = count === 0 && !restartRequired && !applying/)
assert.doesNotMatch(style, /user-plugin-badges/)
assert.match(script, /user-plugin-draft-actions'\]\.hidden = count === 0 && !restartRequired/)
assert.match(script, /userPluginDraft\.size === 0[\s\S]*userPluginInventory\.restartRequired === true[\s\S]*act\('restart-dsh', \{ method: 'POST' \}\)/)
assert.match(script, /terminalEmulator\?\.focus\(\)/)
assert.match(serverSource, /style-src 'self' 'unsafe-inline'/)
assert.match(serverSource, /script-src 'self'; style-src/)
assert.match(html, /id="terminal-loader"[^>]*hidden/)
assert.doesNotMatch(html, /href="\.\/vendor\/xterm\.css"/)
assert.match(script, /stylesheet\.href = '\.\/vendor\/xterm\.css'/)
assert.match(script, /if \(tab === 'maintenance'\) \{\s*connectLogs\(\)/)
assert.match(script, /function connectLogs\(\{ force = false \} = \{\}\)/)
assert.match(script, /addEventListener\('heartbeat'/)
assert.match(script, /Date\.now\(\) - logLastActivity > 35_000/)
assert.match(html, /id="refresh-logs"[^>]*data-i18n="refreshLogs"/)
assert.match(html, /id="export-logs"[^>]*data-i18n="exportLogs"/)
assert.match(script, /function refreshLogs\(\)[\s\S]*api\(`logs\?limit=/)
assert.match(script, /function filteredRawLogs\(\)/)
assert.match(script, /application\/x-ndjson;charset=utf-8/)
assert.match(script, /dsh-platform-logs-.*\.jsonl/)
assert.match(script, /logIdentities\.has\(identity\)/)
assert.match(script, /function scheduleLogRender\(\)/)
assert.match(script, /maintenance: 'DSH 生命周期'/)
assert.match(script, /maintenance: 'DSH lifecycle'/)
assert.match(html, /id="start-dsh"[\s\S]*id="stop-dsh"[\s\S]*id="restart-dsh"/)
assert.match(html, /id="stop-dialog"/)
assert.match(script, /act\('start-dsh', \{ method: 'POST' \}\)/)
assert.match(script, /act\('stop-dsh', \{ method: 'POST' \}\)/)
assert.match(script, /TERMINAL_SESSION_KEY = 'dsh-platform:terminal-session'/)
assert.match(script, /sessionStorage\.setItem\(TERMINAL_SESSION_KEY, value\)/)
assert.match(script, /new WebSocket\(terminalWebSocketUrl\(sessionId\)\)/)
assert.match(script, /terminalEmulator\.reset\(\)[\s\S]*new WebSocket/)
assert.match(script, /terminalReconnectDeadline \?\?= Date\.now\(\) \+ 30_000/)
assert.match(script, /terminalFit\.fit\(\)/)
assert.match(script, /filesTab: '文件管理'/)
assert.match(script, /filesTab: 'Files'/)
assert.match(script, /if \(tab === 'files' && !filesLoaded\) void initializeFiles/)
assert.match(script, /api\('files\/config'\)/)
assert.match(script, /elements\['file-shortcuts'\]\.replaceChildren/)
assert.doesNotMatch(html, /data-file-location="\/workspace"/)
assert.doesNotMatch(script, /scrollIntoView\(\{ block: 'nearest', inline: 'nearest' \}\)/)
assert.match(script, /new XMLHttpRequest\(\)/)
assert.match(script, /fileClipboard = null/)
assert.match(script, /fileOwner: '用户:用户组'/)
assert.match(script, /fileOwner: 'User:group'/)
assert.match(script, /operation: 'size'/)
assert.match(script, /calculateDirectorySize/)
assert.match(script, /operation: 'attributes'/)
assert.match(script, /attributes: \{[\s\S]*user, group, mode,[\s\S]*recursive:/)
assert.match(script, /FILE_ATTRIBUTES_UNSUPPORTED[^\n]*attributesUnsupported/)
assert.match(script, /syncPermissionChecks/)
assert.match(script, /syncModeFromPermissions/)
assert.match(script, /elements\['file-attributes-group'\]\.value = event\.target\.value/)
assert.match(html, /data-i18n="fileOwner"/)
assert.match(html, /class="file-sort-arrows"/)
assert.match(script, /function renderFileSort\(\)/)
assert.match(script, /button\.closest\('th'\)\.setAttribute\('aria-sort'/)
assert.match(style, /\.file-searchbar label \{[^}]*display: inline-flex;[^}]*align-items: center;/)
assert.match(style, /\.resource-heading-detail \{[^}]*display: flex;[^}]*align-items: center;/)
assert.match(style, /\.resource-search \{[^}]*width: min\(320px, 45%\);[^}]*margin: 0 0 0 auto;/)
assert.match(style, /@media \(max-width: 640px\)[\s\S]*\.resource-heading-detail \{[^}]*flex-direction: column;[^}]*\}[\s\S]*\.resource-search \{[^}]*width: 100%;[^}]*margin-left: 0;/)
assert.match(style, /\.file-table \{[^}]*min-width: 600px;/)
assert.match(style, /button\[data-sort-order='asc'\]/)
assert.match(script, /const visibleOperationTasks = new Set\(\)/)
assert.match(script, /function operationResultVisible\(operation, activeStatus\)/)
assert.match(script, /elements\['restart-state'\]\.hidden = !restartVisible/)
assert.match(script, /elements\['runtime-reset-progress'\]\.hidden = !resetActive/)
assert.match(script, /RUNTIME_RESET_PHASES\[next\.operation\]/)
assert.match(script, /runtimeResetProgress = resetActive \? Math\.max\(runtimeResetProgress, resetPhase\.progress\) : 0/)
assert.match(html, /id="runtime-reset-progress-track"[^>]*role="progressbar"/)
assert.match(script, /elements\['runtime-reset'\]\.disabled = busy \|\| next\.current === null/)
assert.match(html, /id="runtime-reset"[^>]*disabled/)
assert.match(script, /elements\['plugin-operation'\]\.hidden = !pluginOperationVisible \|\| pluginOperation\.status !== 'failed'/)
assert.match(script, /pendingInstall: '待安装'[\s\S]*statusInstalling: '安装中'[\s\S]*resourceEnabled: '已启用'/)
assert.match(script, /heading\.append\([\s\S]*userPluginBadge\(t\(stateKey[\s\S]*name,[\s\S]*expandableResourceDescription/)
const bundledPluginRenderer = script.slice(script.indexOf('function renderBundledPlugins('), script.indexOf('function renderSystemSkills('))
const systemSkillRenderer = script.slice(script.indexOf('function renderSystemSkills('), script.indexOf('function userSkillSource('))
assert.doesNotMatch(bundledPluginRenderer, /label\.textContent = projected\.enabled/)
assert.doesNotMatch(systemSkillRenderer, /label\.textContent = skill\.enabled/)
assert.match(html, /id="file-attributes"[^>]*aria-controls="file-attributes-panel"/)
assert.match(html, /id="file-attributes-panel"[^>]*hidden/)
assert.match(html, /data-permission-bit="256"/)
assert.match(html, /id="file-attributes-recursive"/)
assert.match(style, /\.file-permission-grid \{[\s\S]*grid-template-columns:/)
assert.doesNotMatch(script, /window\.(?:alert|confirm|prompt)/)
assert.match(html, /id="text-input-dialog"/)
assert.match(html, /id="confirmation-dialog"/)
assert.match(script, /function requestTextInput\(/)
assert.match(script, /function requestConfirmation\(/)
assert.match(html, /id="file-editor-lines"/)
assert.match(html, /id="file-new"[^>]*aria-controls="file-create-panel"[^>]*aria-expanded="false"/)
assert.match(html, /id="file-create-panel"[^>]*hidden/)
assert.match(html, /data-file-create-kind="touch"[^>]*aria-pressed="true"/)
assert.match(html, /data-file-create-kind="mkdir"[^>]*aria-pressed="false"/)
assert.match(script, /function fileNameIsValid\(value\)[\s\S]*new TextEncoder\(\)\.encode\(value\)\.byteLength <= 255/)
assert.match(script, /const destination = filePath === '\/' \? `\/\$\{name\}` : `\$\{filePath\}\/\$\{name\}`/)
assert.doesNotMatch(script, /file-new[\s\S]{0,200}window\.prompt/)
assert.doesNotMatch(script, /chooseConflict|window\.prompt\(t\('chooseConflict'/)
assert.match(html, /id="file-conflict-dialog"/)
assert.match(html, /name="file-conflict-choice" value="overwrite"/)
assert.match(html, /name="file-conflict-choice" value="rename"/)
assert.match(html, /name="file-conflict-choice" value="skip"/)
assert.match(html, /id="file-conflict-all"/)
assert.match(html, /id="file-conflict-confirm"[^>]*data-i18n="confirmChoice"/)
assert.match(script, /error\.code === 'FILE_EXISTS'/)
assert.match(script, /if \(decision\.applyAll\) conflictForAll = decision\.choice/)
assert.match(style, /\.file-conflict-options \{[^}]*display: grid/)
assert.match(style, /\.file-conflict-dialog \.confirm\[hidden\] \{ display: none; \}/)
assert.match(maintenanceSource, /files\.\$\{operation\}\.rejected/)
assert.match(maintenanceSource, /result\.path \?\? result\.destination \?\? result\.sources/)
assert.match(style, /\.file-create-panel \{[^}]*grid-template-columns:/)
assert.match(html, /id="file-back"[^>]*disabled/)
assert.match(html, /id="file-forward"[^>]*data-i18n-title="forward"[^>]*disabled/)
assert.match(html, /id="file-up"[^>]*disabled/)
assert.match(script, /let fileFuture = \[\]/)
assert.match(script, /elements\['file-forward'\]\.disabled = fileLoading \|\| fileFuture\.length === 0/)
assert.match(script, /elements\['file-up'\]\.disabled = fileLoading \|\| filePath === '\/'/)
assert.match(script, /fileHistory\.push\(filePath\)[\s\S]*fileFuture = \[\]/)
assert.match(script, /elements\['file-forward'\]\.addEventListener\('click', async/)
assert.match(style, /\.file-pathbar \.file-nav-button \{[^}]*display: grid[^}]*place-items: center[^}]*width: 34px[^}]*height: 34px/)
assert.match(style, /\.file-nav-icon \{[^}]*width: 8px[^}]*height: 14px[^}]*clip-path: polygon/)
assert.match(style, /\.file-editor-frame \{[\s\S]*grid-template-columns: auto minmax\(0, 1fr\)/)
assert.match(style, /@media \(max-width: 640px\)[\s\S]*\.file-table thead th:nth-child/)
assert.doesNotMatch(style, /\.file-load-more \{[^}]*!important/)
assert.doesNotMatch(pluginSource, /files\/list|filesTab|文件管理/)
assert.match(style, /\.terminal-frame \{[\s\S]*max-height: min\(760px, 78dvh\);[\s\S]*aspect-ratio: 16 \/ 9;/)
assert.match(style, /\.file-browser \{[^}]*max-height: min\(760px, 78dvh\);[^}]*aspect-ratio: 16 \/ 9;/)
assert.match(style, /@media \(max-width: 640px\)[\s\S]*\.terminal-frame \{ height: clamp\(300px, 56dvh, 440px\);[^}]*aspect-ratio: auto; \}/)
assert.match(style, /@media \(max-width: 640px\)[\s\S]*\.file-main \{[^}]*min-height: 300px;[^}]*max-height: 60dvh;/)
assert.match(script, /userPluginsTab: '用户插件'/)
assert.match(script, /userPluginsTab: 'User plugins'/)
assert.match(script, /skillsTab: '系统技能'/)
assert.match(script, /skillsTab: 'System skills'/)
assert.match(html, /id="tab-skills"/)
assert.match(html, /id="panel-skills"/)
assert.match(script, /function renderSystemSkills\(values, busy\)/)
assert.match(script, /skill\.id, action/)
assert.match(script, /applyUserPluginChanges: '应用并重新启动 DSH'/)
assert.match(script, /applyUserPluginChangesOffline: '应用修改'/)
assert.match(script, /applyUserPluginChanges: 'Apply and restart DSH'/)
assert.match(script, /applyUserPluginChangesOffline: 'Apply changes'/)
assert.match(script, /userPluginRecoveryDetail: 'DSH 启动或运行失败,但你仍可修改用户插件。故障日志可前往“运行维护”查看。'/)
assert.match(script, /systemPluginRecoveryDetail: 'DSH 启动或运行失败,但你仍可修改系统插件。故障日志可前往“运行维护”查看。'/)
assert.match(script, /systemSkillRecoveryDetail: 'DSH 启动或运行失败,但你仍可修改系统技能。故障日志可前往“运行维护”查看。'/)
assert.match(script, /userSkillRecoveryDetail: 'DSH 启动或运行失败,但你仍可修改用户技能。故障日志可前往“运行维护”查看。'/)
assert.doesNotMatch(script, /localizedError\(recoveryReason\)/)
for (const id of ['system-plugin-recovery', 'system-skill-recovery', 'user-skill-recovery', 'user-plugin-recovery']) {
assert.match(html, new RegExp(`id="${id}"`))
}
assert.match(script, /operation\.strategy === 'next-start'[\s\S]*systemPluginApplyingDraft\.clear\(\)/)
assert.match(script, /!dshUnavailable && plugins\.some\(plugin => plugin\.pendingRestart\)/)
assert.match(script, /const userPluginDraft = new Map\(\)/)
assert.match(script, /expandedUserPluginDescriptions/)
assert.match(script, /plugin\.description/)
assert.match(script, /description\.scrollWidth > description\.clientWidth/)
assert.match(script, /revision: userPluginInventory\.revision/)
assert.match(script, /error\.statusCode === 409[\s\S]*userPluginDraft\.clear\(\)[\s\S]*userPluginRevisionConflict/)
assert.match(script, /waitForUserPluginTask[\s\S]*catch \(error\)[\s\S]*lastError = error/)
assert.match(script, /userPluginPhaseRestoring: '正在恢复 Web Profile'/)
assert.match(script, /userPluginPhaseRestoring: 'Restoring Web Profile'/)
assert.doesNotMatch(script, /(?:localStorage|sessionStorage).*user-plugin-draft/)
assert.match(html, /id="user-plugin-recovery"/)
assert.match(html, /id="user-plugin-draft-actions"[^>]*hidden/)
assert.match(html, /id="cancel-user-plugin-changes"/)
assert.match(html, /id="apply-user-plugin-changes"/)
assert.match(script, /user-plugin-draft-actions'\]\.hidden = count === 0 && !restartRequired/)
assert.match(script, /const dshUnavailable = status\?\.recoveryMode[\s\S]*applyUserPluginChangesOffline/)
assert.doesNotMatch(style, /\.draft-actions/)
assert.match(style, /\.tabs \{[\s\S]*width: 100%;[\s\S]*min-width: 0;[\s\S]*max-width: 100%;[\s\S]*overflow-x: auto/)
assert.match(style, /\.resource-panel \{ padding-bottom: 0; overflow-x: hidden; overflow-y: auto; overflow-anchor: none; \}/)
assert.match(style, /\.resource-panel > section \{ height: 100%; min-height: 0; overflow: visible; \}/)
assert.match(style, /\.resource-panel \.resource-section-heading,[\s\S]*\.resource-panel \.list-pagination,[\s\S]*\.resource-panel \.operation-result \{ flex: none; \}/)
assert.match(style, /@media \(max-height: 600px\) \{\s*\.resource-panel > section \{ gap: 8px; padding: 12px 0; \}/)
assert.match(style, /\.resource-panel \.plugin-list, \.resource-panel \.user-plugin-list \{[\s\S]*max-height: min\(52dvh, 520px\);[\s\S]*flex: 0 1 auto;[\s\S]*overflow-y: auto;[\s\S]*overflow-anchor: none;[\s\S]*scrollbar-gutter: stable/)
assert.doesNotMatch(style, /\.resource-panel \.plugin-list, \.resource-panel \.user-plugin-list \{ max-height: min\(calc\(56\.25vw/)
assert.match(style, /@media \(hover: hover\) and \(pointer: fine\) \{\s*\.tabs \{ scroll-snap-type: none; \}/)
assert.match(script, /function makeHorizontalTabStripScrollable\(tablist\)/)
assert.match(script, /const stableScrollPositions = new WeakMap\(\)[\s\S]*if \(scrollRestoreGenerations\.has\(element\)\) return[\s\S]*scrollRestoreGenerations\.get\(current\) !== generation/)
assert.match(script, /function preserveResourceRowPosition\(element, update\)[\s\S]*closest\('\.resource-panel'\)[\s\S]*current === panel\) break[\s\S]*current\.scrollTop \+= offset/)
assert.match(script, /checkbox\.addEventListener\('change', event => preserveResourceRowPosition\(event\.currentTarget, \(\) => setSystemPluginDraft/)
assert.match(script, /checkbox\.addEventListener\('change', event => preserveResourceRowPosition\(event\.currentTarget, \(\) => setUserPluginDraft/)
assert.doesNotMatch(script, /scrollIntoView\(\{ block: 'nearest', inline: 'nearest' \}\)/)
assert.match(script, /const tablist = activeTab\.parentElement[\s\S]*tablist\.scrollLeft = right - tablist\.clientWidth/)
assert.match(script, /addEventListener\('wheel',[\s\S]*\{ passive: false \}\)/)
assert.match(script, /if \(event\.deltaX !== 0\) return/)
assert.match(script, /requestAnimationFrame\(animateWheel\)/)
assert.match(script, /addEventListener\('pointermove'/)
assert.match(script, /if \(Math\.abs\(distance\) >= 4 && !dragged\) \{\s*dragged = true\s*tablist\.setPointerCapture\?\.\(pointerId\)/)
assert.doesNotMatch(script, /dragTarget = event\.target\s*tablist\.setPointerCapture/)
assert.match(script, /const displacedClickTarget = !dragged && event\.target !== dragTarget \? dragTarget : undefined[\s\S]*displacedClickTarget\?\.click\(\)/)
assert.match(script, /makeHorizontalTabStripScrollable\(document\.querySelector\('\.tabs'\)\)/)
assert.match(style, /\.topbar-inner \{[\s\S]*width: min\(1180px, calc\(100% - 48px\)\)/)
assert.match(style, /main \{[\s\S]*width: min\(1180px, calc\(100% - 48px\)\)/)
assert.match(style, /:root\[data-theme="dark"\][\s\S]*@media \(prefers-color-scheme: dark\)[\s\S]*:root:not\(\[data-theme\]\)/)
assert.match(style, /\.topbar-actions \{[^}]*display: flex/)
assert.match(style, /@media \(max-width: 640px\)/)
assert.match(style, /\.log-resize-frame \{[^}]*height: 480px;[^}]*min-height: 140px;[^}]*max-height: min\(1080px, 105dvh\);/)
assert.match(style, /\.log-resize-handle \{[^}]*height: 16px;[^}]*cursor: ns-resize;/)
assert.match(script, /makeLogListVerticallyResizable\(elements\['log-resize-frame'\], elements\['log-resize-handle'\]\)/)
assert.match(script, /element\.style\.height = `\$\{String\(height\)\}px`/)
assert.match(script, /scrollContainer\.scrollTop \+= Math\.min\(overflow, 24\)/)
assert.match(style, /@media \(max-width: 640px\)[\s\S]*\.log-resize-frame \{ height: min\(260px, 36dvh\); \}/)
assert.match(style, /\.log-entry \.log-details/)
assert.match(style, /\.log-entry\[aria-expanded='true'\] \.log-chevron/)
assert.match(style, /\.log-entry\[aria-expanded='false'\] \.log-message-row > pre \{[^}]*white-space: nowrap;/)
assert.match(style, /\.log-chevron::before \{[^}]*width: 8px[^}]*height: 5px[^}]*clip-path: polygon[^}]*transform-origin: center/)
assert.match(style, /\.log-chevron \{[^}]*top: 2px/)
assert.doesNotMatch(style, /\.log-chevron(?:::before)? \{[^}]*transition:/)
assert.match(style, /\.log-entry\[aria-expanded='true'\] \.log-chevron::before \{[^}]*transform: rotate\(180deg\)/)
assert.match(style, /\.user-plugin-description\.expanded/)
assert.match(style, /\.resource-description\.expanded/)
assert.match(style, /\.plugin-row \{[^}]*min-height:\s*52px/)
assert.match(script, /function commitFilePageJump[\s\S]*Math\.min\(lastPage, Math\.max\(0, requested - 1\)\)[\s\S]*input\.value = String\(page \+ 1\)/)
assert.match(style, /\.plugin-actions \.toggle \{ width: auto; \}/)
assert.match(style, /button\.compact \{[^}]*border-radius: 6px;/)
assert.match(style, /\.user-plugin-badge \{[^}]*border-radius: 4px;/)
assert.match(style, /\.proxy-provider-heading > h2 \{[^}]*font-size: 16px;[^}]*line-height: 24px;/)
assert.match(style, /\.user-plugin-row \{[\s\S]*grid-template-columns: minmax\(0, 1fr\) auto/)
assert.match(style, /@media \(max-width: 640px\)[\s\S]*\.user-plugin-row \{ grid-template-columns: 1fr/)
})
test('production Management wires Runtime reset to the Bootstrap control boundary', async () => {
const source = await readFile(new URL('../../control-plane/services/management/index.mjs', import.meta.url), 'utf8')
const serverStart = source.indexOf('server = createManagementServer({')
assert.notEqual(serverStart, -1)
const serverSource = source.slice(serverStart)
assert.match(serverSource, /resetRuntime: \(\) => bootstrap\.request\('POST', '\/v1\/deployments\/runtime\/reset'\)/)
})
test('CLI parser keeps rollback local and update wait behavior explicit', async () => {
assert.deepEqual(parseCli(['update', '--wait']), { command: 'update', wait: true })
assert.deepEqual(parseCli(['trust', 'status']), { command: 'trust', operation: 'status' })
assert.throws(() => parseCli(['update', '--force']))
const calls = []
const output = []
const management = {
request: async (method, path, body) => {
calls.push({ method, path, body })
if (path.endsWith('/rollback-plan')) return { plan: { planId: 'plan-a' } }
return path.endsWith('/rollback') ? { taskId: 'rollback-task' } : {}
},
}
assert.equal(await runCli({ argv: ['rollback'], management, write: line => output.push(line) }), 0)
assert.deepEqual(calls, [
{ method: 'GET', path: '/_dsh_platform/api/v1/rollback-plan', body: undefined },
{ method: 'POST', path: '/_dsh_platform/api/v1/rollback', body: { planId: 'plan-a' } },
])
assert.match(output[0], /rollback-task/)
})
test('management CLI creates a root-only one-time authentication reset key', async () => {
assert.deepEqual(parseCli(['access', 'generate-key']), { command: 'access', operation: 'generate-key' })
assert.throws(() => parseCli(['access', 'create']))
assert.throws(() => parseCli(['access']))
const calls = []
const output = []
const tty = { isTTY: true }
assert.equal(await runCli({
argv: ['access', 'generate-key'],
access: {
request: async (method, path) => {
calls.push([method, path])
if (method === 'GET') return { state: 'migration-required', account: null }
return { key: 'dshak_example', expiresAt: '2026-08-28T00:10:00.000Z' }
},
},
getuid: () => 0,
input: tty,
output: tty,
ask: async () => 'y',
write: line => output.push(line),
}), 0)
assert.deepEqual(calls, [
['GET', '/v1/recovery/status'],
['POST', '/v1/recovery/generate-key'],
])
assert.deepEqual(JSON.parse(output[0]), {
key: 'dshak_example', expiresAt: '2026-08-28T00:10:00.000Z',
})
await assert.rejects(runCli({
argv: ['access', 'generate-key'], access: { request: async () => ({}) },
getuid: () => 1000, input: tty, output: tty,
}), /requires root/)
})
test('management CLI exposes standalone two-factor disable without session logout', async () => {
assert.deepEqual(parseCli(['access', 'disable-two-factor']), {
command: 'access', operation: 'disable-two-factor',
})
const calls = []
const tty = { isTTY: true }
assert.equal(await runCli({
argv: ['access', 'disable-two-factor'],
access: { request: async (method, path, body) => {
calls.push({ method, path, body })
if (method === 'GET') return { state: 'initialized', account: { revision: 'revision-a' } }
return { account: { revision: 'revision-b' }, allSessionsRevoked: false }
} },
getuid: () => 0,
input: tty,
output: tty,
ask: async prompt => { assert.equal(prompt, 'Disable two-factor authentication? y/[n]: '); return 'y' },
write: () => {},
}), 0)
assert.deepEqual(calls, [
{ method: 'GET', path: '/v1/recovery/status', body: undefined },
{ method: 'POST', path: '/v1/recovery/reset-access', body: {
revision: 'revision-a', managementPasswordAction: 'preserve', totpAction: 'disable',
} },
])
})
test('management CLI clears all or only Management sessions', async () => {
assert.deepEqual(parseCli(['access', 'clear-sessions']), {
command: 'access', operation: 'clear-sessions',
})
assert.deepEqual(parseCli(['access', 'clear-sessions', '--management-only']), {
command: 'access', operation: 'clear-sessions', managementOnly: true,
})
const tty = { isTTY: true }
for (const [argv, expectedScope] of [
[['access', 'clear-sessions'], false],
[['access', 'clear-sessions', '--management-only'], true],
]) {
let submitted
await runCli({
argv,
access: { request: async (method, path, body) => {
if (method === 'GET') return { state: 'initialized', account: { revision: 'revision-a' } }
submitted = { method, path, body }
return { status: 'cleared' }
} },
getuid: () => 0,
input: tty,
output: tty,
ask: async () => 'y',
write: () => {},
})
assert.deepEqual(submitted, {
method: 'POST', path: '/v1/recovery/clear-sessions', body: { managementOnly: expectedScope },
})
}
})
test('management CLI clears login retry wait only after Root TTY confirmation', async () => {
assert.deepEqual(parseCli(['access', 'clear-retry']), { command: 'access', operation: 'clear-retry' })
assert.deepEqual(parseCli(['access', 'clear-retry', '--global-only']), {
command: 'access', operation: 'clear-retry', globalOnly: true,
})
assert.deepEqual(parseCli(['access', 'clear-retry', '--two-factor']), {
command: 'access', operation: 'clear-retry', credential: 'totp',
})
assert.deepEqual(parseCli(['access', 'clear-retry', '--global-only', '--two-factor']), {
command: 'access', operation: 'clear-retry', globalOnly: true, credential: 'totp',
})
assert.throws(() => parseCli(['access', 'clear-retry', 'now']))
const tty = { isTTY: true }
const calls = []
const output = []
assert.equal(await runCli({
argv: ['access', 'clear-retry'],
access: {
request: async (method, path, body) => {
calls.push([method, path, body])
if (method === 'GET') return {
state: 'initialized',
authenticationRetry: { consecutiveFailures: 5, retryAfterSeconds: 1 },
account: { revision: 'revision-a' },
}
return {
status: 'cleared', scope: 'all', cleared: true, activeSources: 1,
consecutiveFailures: 5, retryAfterSeconds: 1,
sourceRetryAfterSeconds: 0, globalFailures: 5, globalRetryAfterSeconds: 0,
}
},
},
getuid: () => 0,
input: tty,
output: tty,
ask: async prompt => {
assert.equal(prompt, 'Clear all administrator login retry limits? y/[n]: ')
return 'y'
},
write: line => output.push(line),
}), 0)
assert.deepEqual(calls, [
['GET', '/v1/recovery/status', undefined],
['POST', '/v1/recovery/clear-retry', { scope: 'all' }],
])
assert.deepEqual(JSON.parse(output[0]), {
status: 'cleared', scope: 'all', cleared: true, activeSources: 1,
consecutiveFailures: 5, retryAfterSeconds: 1,
sourceRetryAfterSeconds: 0, globalFailures: 5, globalRetryAfterSeconds: 0,
})
await assert.rejects(runCli({
argv: ['access', 'clear-retry'], access: { request: async () => ({}) },
getuid: () => 1000, input: tty, output: tty,
}), /requires root/)
await assert.rejects(runCli({
argv: ['access', 'clear-retry'], access: { request: async () => ({}) },
getuid: () => 0, input: { isTTY: false }, output: tty,
}), /interactive container console/)
const globalCalls = []
assert.equal(await runCli({
argv: ['access', 'clear-retry', '--global-only'],
access: {
request: async (method, path, body) => {
globalCalls.push([method, path, body])
if (method === 'GET') return { state: 'initialized', account: { revision: 'revision-a' } }
return { status: 'cleared', scope: 'global', cleared: true, globalFailures: 20 }
},
},
getuid: () => 0,
input: tty,
output: tty,
ask: async prompt => {
assert.equal(prompt, 'Clear instance-wide administrator login rate limits? y/[n]: ')
return 'y'
},
write: () => {},
}), 0)
assert.deepEqual(globalCalls, [
['GET', '/v1/recovery/status', undefined],
['POST', '/v1/recovery/clear-retry', { scope: 'global' }],
])
const totpCalls = []
assert.equal(await runCli({
argv: ['access', 'clear-retry', '--two-factor'],
access: { request: async (method, path, body) => {
totpCalls.push([method, path, body])
return method === 'GET'
? { state: 'initialized', account: { revision: 'revision-a' } }
: { status: 'cleared', scope: 'all', credential: 'totp', cleared: 2 }
} },
getuid: () => 0, input: tty, output: tty,
ask: async prompt => {
assert.equal(prompt, 'Clear two-factor daily limits? The fixed 10-second retry remains active. y/[n]: ')
return 'y'
},
write: () => {},
}), 0)
assert.deepEqual(totpCalls, [
['GET', '/v1/recovery/status', undefined],
['POST', '/v1/recovery/clear-retry', { scope: 'all', credential: 'totp' }],
])
})
test('access clear-retry accepts only retry scope and credential selectors', async () => {
assert.deepEqual(parseCli(['access', 'clear-retry']), {
command: 'access', operation: 'clear-retry',
})
assert.deepEqual(parseCli(['access', 'clear-retry', '--main-password']), {
command: 'access', operation: 'clear-retry', credential: 'main',
})
assert.deepEqual(parseCli(['access', 'clear-retry', '--two-factor']), {
command: 'access', operation: 'clear-retry', credential: 'totp',
})
assert.throws(
() => parseCli(['access', 'clear-retry', '--main-password', '--management-password']),
error => error.message.includes('\ncommands:\n')
&& error.message.includes('access clear-retry [--global-only] [--main-password|--management-password|--two-factor]'),
)
let recoverError
let commandError
try { parseCli(['access', 'clear-retry', '--bad-option']) } catch (error) { recoverError = error }
try { parseCli(['unknown-command']) } catch (error) { commandError = error }
assert.equal(recoverError.message, commandError.message)
assert.match(recoverError.message, /^usage: dsh-platform <command> \[options\]\ncommands:\n/)
assert.doesNotMatch(recoverError.message, /requires --image-baseline/)
const tty = { isTTY: true }
const calls = []
const output = []
assert.equal(await runCli({
argv: ['access', 'clear-retry', '--management-password'],
access: { request: async (method, path, body) => {
calls.push(['access', method, path, body])
return { status: 'cleared', scope: 'all', credential: 'management', cleared: true }
} },
getuid: () => 0,
input: tty,
output: tty,
ask: async prompt => {
assert.equal(prompt, 'Clear Management console password login retry limits? y/[n]: ')
return 'y'
},
write: line => output.push(line),
}), 0)
assert.deepEqual(calls, [
['access', 'GET', '/v1/recovery/status', undefined],
['access', 'POST', '/v1/recovery/clear-retry', { scope: 'all', credential: 'management' }],
])
assert.deepEqual(JSON.parse(output[0]), { status: 'cleared', scope: 'all', credential: 'management', cleared: true })
})
test('hidden access input preserves the TTY stream for subsequent prompts', async () => {
const input = new PassThrough()
input.isTTY = true
input.setRawMode = value => { input.isRaw = value }
const output = new PassThrough()
output.isTTY = true
const first = readSecret(input, output, 'First password: ')
input.write('first secret\n')
assert.equal(await first, 'first secret')
assert.equal(input.destroyed, false)
assert.equal(input.isRaw, false)
const second = readSecret(input, output, 'Second password: ')
input.write('second secret\n')
assert.equal(await second, 'second secret')
assert.equal(input.destroyed, false)
assert.equal(input.isRaw, false)
})
test('management CLI defaults every direct access mutation to no', async () => {
const tty = { isTTY: true }
for (const operation of [
'set-username',
'reset-password',
'reset-management-password',
'disable-management-password',
'generate-key',
'clear-retry',
]) {
const calls = []
const prompts = []
const output = []
assert.equal(await runCli({
argv: ['access', operation],
access: {
request: async (method, path, body) => {
calls.push({ method, path, body })
return {
state: 'initialized',
account: {
revision: 'revision-a',
managementAdditionalCredential: { enabled: true, version: 2 },
},
}
},
},
getuid: () => 0,
input: tty,
output: tty,
ask: async prompt => {
prompts.push(prompt)
return ''
},
readPassword: async () => { throw new Error('password must not be requested') },
write: line => output.push(line),
}), 0)
assert.deepEqual(calls, [
{ method: 'GET', path: '/v1/recovery/status', body: undefined },
])
assert.equal(prompts.length, 1)
assert.match(prompts[0], /y\/\[n\]: $/)
assert.deepEqual(JSON.parse(output[0]), { status: 'cancelled' })
}
})
test('management CLI resets administrator access through one atomic recovery request', async () => {
assert.deepEqual(parseCli(['access', 'reset']), { command: 'access', operation: 'reset' })
const calls = []
const prompts = []
const output = []
const passwords = ['new administrator password', 'new management password']
const answers = ['y', 'operator', 'y', 'y', 'y']
const tty = { isTTY: true }
assert.equal(await runCli({
argv: ['access', 'reset'],
access: {
request: async (method, path, body) => {
calls.push({ method, path, body })
if (method === 'GET') return {
state: 'initialized',
account: {
revision: 'revision-a',
managementAdditionalCredential: { enabled: true, version: 2 },
totp: { enabled: true, version: 1 },
},
}
return { account: { revision: 'revision-b', mainCredentialVersion: 2 } }
},
},
getuid: () => 0,
input: tty,
output: tty,
readPassword: async (_input, _output, prompt) => {
prompts.push(prompt)
return passwords.shift()
},
ask: async prompt => {
prompts.push(prompt)
return answers.shift()
},
write: line => output.push(line),
}), 0)
assert.deepEqual(prompts, [
'Change administrator username? y/[n]: ',
'New administrator username: ',
'Change administrator password? y/[n]: ',
'New administrator password: ',
'Change Management console password? (y)es/[n]o/(d)isable: ',
'New management password: ',
'Disable two-factor authentication? y/[n]: ',
])
assert.deepEqual(calls, [
{ method: 'GET', path: '/v1/recovery/status', body: undefined },
{
method: 'POST',
path: '/v1/recovery/reset-access',
body: {
revision: 'revision-a',
username: 'operator',
password: 'new administrator password',
managementPasswordAction: 'reset',
managementPassword: 'new management password',
totpAction: 'disable',
},
},
])
assert.equal(JSON.parse(output[0]).account.mainCredentialVersion, 2)
})
test('management CLI skips the additional-password choice when it is disabled', async () => {
const calls = []
const answers = ['n', 'y']
const tty = { isTTY: true }
assert.equal(await runCli({
argv: ['access', 'reset'],
access: {
request: async (method, path, body) => {
calls.push({ method, path, body })
if (method === 'GET') return {
state: 'initialized',
account: {
revision: 'revision-a',
managementAdditionalCredential: { enabled: false, version: 1 },
},
}
return { account: { revision: 'revision-b' } }
},
},
getuid: () => 0,
input: tty,
output: tty,
readPassword: async () => 'new administrator password',
ask: async () => answers.shift(),
write: () => {},
}), 0)
assert.deepEqual(calls.at(-1), {
method: 'POST',
path: '/v1/recovery/reset-access',
body: {
revision: 'revision-a',
password: 'new administrator password',
managementPasswordAction: 'preserve',
},
})
})
test('management CLI preserves or disables an existing additional password by choice', async () => {
const tty = { isTTY: true }
for (const [choice, action] of [['', 'preserve'], ['d', 'disable']]) {
let submitted
const answers = ['n', 'y', choice]
assert.equal(await runCli({
argv: ['access', 'reset'],
access: {
request: async (method, _path, body) => {
if (method === 'GET') return {
state: 'initialized',
account: {
revision: 'revision-a',
managementAdditionalCredential: { enabled: true, version: 2 },
},
}
submitted = body
return { account: { revision: 'revision-b' } }
},
},
getuid: () => 0,
input: tty,
output: tty,
readPassword: async () => 'new administrator password',
ask: async () => answers.shift(),
write: () => {},
}), 0)
assert.equal(submitted.managementPasswordAction, action)
assert.equal('managementPassword' in submitted, false)
}
})
test('management CLI combined reset can disable only two-factor authentication', async () => {
const calls = []
const answers = ['n', 'n', 'n', 'y']
const tty = { isTTY: true }
assert.equal(await runCli({
argv: ['access', 'reset'],
access: {
request: async (method, path, body) => {
calls.push({ method, path, body })
if (method === 'GET') return {
state: 'initialized',
account: {
revision: 'revision-a',
managementAdditionalCredential: { enabled: true, version: 2 },
totp: { enabled: true, version: 1 },
},
}
return { account: { revision: 'revision-b', totp: { enabled: false, version: 2 } } }
},
},
getuid: () => 0,
input: tty,
output: tty,
ask: async () => answers.shift(),
write: () => {},
}), 0)
assert.deepEqual(calls.at(-1), {
method: 'POST',
path: '/v1/recovery/reset-access',
body: {
revision: 'revision-a',
managementPasswordAction: 'preserve',
totpAction: 'disable',
},
})
})
test('management CLI rejects ambiguous choices and cancels an empty combined reset', async () => {
const tty = { isTTY: true }
for (const answers of [['yes'], ['n', 'n', 'invalid']]) {
const calls = []
await assert.rejects(runCli({
argv: ['access', 'reset'],
access: {
request: async (method, path, body) => {
calls.push({ method, path, body })
return {
state: 'initialized',
account: {
revision: 'revision-a',
managementAdditionalCredential: { enabled: true, version: 2 },
},
}
},
},
getuid: () => 0,
input: tty,
output: tty,
ask: async () => answers.shift(),
readPassword: async () => { throw new Error('password must not be requested') },
write: () => {},
}), /choice must be y or n|management password choice must be y, n, or d/)
assert.deepEqual(calls, [
{ method: 'GET', path: '/v1/recovery/status', body: undefined },
])
}
const calls = []
const output = []
const answers = ['n', 'n', '']
assert.equal(await runCli({
argv: ['access', 'reset'],
access: {
request: async (method, path, body) => {
calls.push({ method, path, body })
return {
state: 'initialized',
account: {
revision: 'revision-a',
managementAdditionalCredential: { enabled: true, version: 2 },
},
}
},
},
getuid: () => 0,
input: tty,
output: tty,
ask: async () => answers.shift(),
write: line => output.push(line),
}), 0)
assert.deepEqual(calls, [
{ method: 'GET', path: '/v1/recovery/status', body: undefined },
])
assert.deepEqual(JSON.parse(output[0]), { status: 'cancelled' })
})
test('management CLI does not submit partially collected access recovery input', async () => {
const calls = []
const answers = ['y', 'operator', 'y']
const tty = { isTTY: true }
await assert.rejects(runCli({
argv: ['access', 'reset'],
access: {
request: async (method, path, body) => {
calls.push({ method, path, body })
return {
state: 'initialized',
account: {
revision: 'revision-a',
managementAdditionalCredential: { enabled: true, version: 2 },
},
}
},
},
getuid: () => 0,
input: tty,
output: tty,
ask: async () => answers.shift(),
readPassword: async () => { throw new Error('access recovery cancelled') },
write: () => {},
}), /access recovery cancelled/)
assert.deepEqual(calls, [
{ method: 'GET', path: '/v1/recovery/status', body: undefined },
])
})
test('update wait ignores a terminal state from an older task', async () => {
const output = []
const statuses = [
{ update: { taskId: 'old-task', status: 'failed' } },
{ update: { taskId: 'new-task', status: 'planning' } },
{ update: { taskId: 'new-task', status: 'success' } },
]
const management = {
request: async (method, path) => {
if (method === 'POST' && path.endsWith('/update')) return { taskId: 'new-task' }
return statuses.shift()
},
}
let waits = 0
const exitCode = await runCli({
argv: ['update', '--wait'],
management,
write: line => output.push(line),
delay: async () => { waits += 1 },
})
assert.equal(exitCode, 0)
assert.equal(waits, 2)
assert.match(output.at(-1), /new-task/)
})
test('update wait reconnects across a Bootstrap handoff and follows the resumed task', async () => {
const output = []
const unavailable = Object.assign(new Error('management socket is restarting'), { code: 'ENOENT' })
const statuses = [
unavailable,
{ update: { taskId: 'resumed-task', operation: 'update', status: 'planning' } },
{ update: { taskId: 'resumed-task', operation: 'update', status: 'success' } },
]
const management = {
request: async (method, path) => {
if (method === 'POST' && path.endsWith('/update')) return { taskId: 'original-task' }
const next = statuses.shift()
if (next instanceof Error) throw next
return next
},
}
let waits = 0
const exitCode = await runCli({
argv: ['update', '--wait'],
management,
write: line => output.push(line),
delay: async () => { waits += 1 },
})
assert.equal(exitCode, 0)
assert.equal(waits, 2)
assert.match(output.at(-1), /resumed-task/)
})
test('update wait does not hide non-transient Management failures', async () => {
const management = {
request: async method => {
if (method === 'POST') return { taskId: 'original-task' }
throw Object.assign(new Error('permission denied'), { code: 'EACCES' })
},
}
await assert.rejects(runCli({
argv: ['update', '--wait'], management, write: () => {}, delay: async () => {},
}), /permission denied/)
})
test('management CLI emits each JSON result as one log-safe line', async () => {
const output = []
const status = {
officialDshVersion: null,
dshLifecycle: {
state: 'running', action: null, taskId: null, attempt: 0, maxAttempts: 3,
error: null, updatedAt: null,
},
}
assert.equal(await runCli({
argv: ['status'],
management: { request: async () => status },
write: line => output.push(line),
}), 0)
assert.deepEqual(output, [JSON.stringify(status)])
assert.equal(output[0].includes('\n'), false)
})
test('lifecycle CLI has a fixed DSH scope and waits only for its own task', async () => {
assert.deepEqual(parseCli(['start']), { command: 'start', wait: false })
assert.deepEqual(parseCli(['stop', '--wait']), { command: 'stop', wait: true })
assert.deepEqual(parseCli(['restart']), { command: 'restart', wait: false })
assert.deepEqual(parseCli(['restart', '--wait']), { command: 'restart', wait: true })
assert.throws(() => parseCli(['restart', 'gateway']))
assert.throws(() => parseCli(['restart', '--component', 'gateway']))
const immediateCalls = []
assert.equal(await runCli({
argv: ['restart'],
management: {
request: async (method, path) => {
immediateCalls.push([method, path])
return { taskId: 'immediate-task' }
},
},
write: () => {},
}), 0)
assert.deepEqual(immediateCalls, [['POST', '/_dsh_platform/api/v1/restart-dsh']])
const output = []
const statuses = [
{ dshLifecycle: { taskId: 'old-task', state: 'running' } },
{ dshLifecycle: { taskId: 'restart-task', state: 'restarting' } },
{ dshLifecycle: { taskId: 'restart-task', state: 'running' } },
]
const calls = []
const management = {
request: async (method, path) => {
calls.push([method, path])
if (method === 'POST') return { taskId: 'restart-task' }
return statuses.shift()
},
}
let waits = 0
const exitCode = await runCli({
argv: ['restart', '--wait'],
management,
write: line => output.push(line),
delay: async () => { waits += 1 },
})
assert.equal(exitCode, 0)
assert.equal(waits, 2)
assert.deepEqual(calls[0], ['POST', '/_dsh_platform/api/v1/restart-dsh'])
assert.match(output[0], /restart-task/)
assert.match(output.at(-1), /running/)
})
test('CLI parses channel controls and refuses noninteractive Stable return', async () => {
assert.deepEqual(parseCli(['channel', 'experimental']), { command: 'channel', channel: 'experimental' })
assert.deepEqual(parseCli(['retry']), { command: 'retry' })
assert.deepEqual(parseCli(['return-stable']), { command: 'return-stable' })
const management = {
request: async () => ({ plan: { planId: 'plan-a', snapshot: { createdAt: '2026-08-19T00:00:00.000Z' } } }),
}
await assert.rejects(runCli({
argv: ['return-stable'], management, input: { isTTY: false }, output: { isTTY: false }, write: () => {},
}), /interactive/)
})
test('trust reset refuses non-root and non-interactive callers before mutation', async () => {
await assert.rejects(resetTrust({ getuid: () => 1000 }), /root/)
await assert.rejects(resetTrust({ getuid: () => 0, input: { isTTY: false }, output: { isTTY: false } }), /interactive/)
})
test('image baseline recovery is root/TTY-only and requires the complete image identity', async () => {
assert.deepEqual(parseCli(['recover']), { command: 'recover' })
const calls = []
const recovery = {
request: async (method, path, body) => {
calls.push({ method, path, body })
if (method === 'GET') return { imageBaseline: { imageBuildId: `sha256:${'a'.repeat(64)}`, dsh: '0.1.0-rc.10' } }
return { status: 'recovered' }
},
}
await assert.rejects(recoverImageBaseline({ recovery, getuid: () => 1000 }), /root/)
await assert.rejects(recoverImageBaseline({
recovery, getuid: () => 0, input: { isTTY: false }, output: { isTTY: false },
}), /interactive/)
const expected = `RECOVER IMAGE BASELINE sha256:${'a'.repeat(64)}`
const value = await recoverImageBaseline({
recovery,
getuid: () => 0,
input: { isTTY: true },
output: { isTTY: true },
ask: async prompt => prompt,
})
assert.equal(value.status, 'recovered')
assert.deepEqual(calls, [
{ method: 'GET', path: '/v1/status', body: undefined },
{ method: 'POST', path: '/v1/recover-image-baseline', body: { confirm: expected.slice('RECOVER IMAGE BASELINE '.length) } },
])
})
test('scheduler applies bounded jitter and performs checks without activating updates', async () => {
let delay
let callback
let checks = 0
const scheduler = new UpdateScheduler({
check: async () => { checks += 1 },
intervalSeconds: 100,
random: () => 0,
setTimer: (fn, milliseconds) => { callback = fn; delay = milliseconds; return { unref() {} } },
clearTimer: () => {},
})
scheduler.start()
assert.equal(delay, 90_000)
await callback()
assert.equal(checks, 1)
scheduler.configure({ enabled: false, intervalSeconds: 3_600 })
assert.equal(scheduler.timer, undefined)
scheduler.configure({ enabled: true, intervalSeconds: 3_600 })
assert.equal(delay, 3_240_000)
scheduler.stop()
})
test('scheduler configuration during a running check does not revive an old timer', async () => {
const timers = []
let finish
const scheduler = new UpdateScheduler({
check: () => new Promise(resolve => { finish = resolve }),
intervalSeconds: 100,
setTimer: callback => { const timer = { callback, unref() {} }; timers.push(timer); return timer },
clearTimer: () => {},
})
scheduler.start()
const running = timers[0].callback()
scheduler.configure({ enabled: false, intervalSeconds: 3_600 })
finish()
await running
assert.equal(timers.length, 1)
assert.equal(scheduler.timer, undefined)
})
test('scheduler reports a failed automatic check and continues scheduling', async () => {
const errors = []
const timers = []
const scheduler = new UpdateScheduler({
check: async () => { throw Object.assign(new Error('metadata offline'), { code: 'ENETDOWN' }) },
onError: error => { errors.push(error) },
intervalSeconds: 100,
setTimer: callback => { const timer = { callback, unref() {} }; timers.push(timer); return timer },
clearTimer: () => {},
})
scheduler.start()
await timers[0].callback()
assert.equal(errors[0].code, 'ENETDOWN')
assert.equal(timers.length, 2)
scheduler.stop()
})
test('management does not check metadata before the first scheduled interval', async () => {
const source = await readFile(new URL('../../control-plane/services/management/index.mjs', import.meta.url), 'utf8')
assert.doesNotMatch(source, /setImmediate\(\(\) => \{ coordinator\.check\(\)\.catch/)
assert.match(source, /check: \(\) => coordinator\.check\('automatic'\)/)
assert.match(source, /allowUnavailableMetadata: imageInventory\.authority === 'development'/)
})
test('management exposes authenticated file inventory, search, upload, and ranged download primitives', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-management-files-'))
const files = join(root, 'files')
await mkdir(files)
await writeFile(join(files, 'alpha.txt'), '0123456789')
const logs = new JsonlLogManager({ root: join(root, 'logs') })
let server
const fileTasks = new FileTaskManager({ root: join(root, 'tasks'), onState: state => server?.emit('management-state', { fileTask: state }) })
await fileTasks.initialize()
server = createManagementServer({
coordinator: new Coordinator(), logs,
fileInventory: new FileInventory(), fileTransfers: new FileTransferManager(), fileTasks, fileEditor: new AtomicFileEditor(),
fileLocations: { defaultPath: '/custom/workspace', shortcuts: ['/custom/workspace', '/custom/dsh', '/custom/platform', '/'] },
})
const socketPath = join(root, 'management.sock')
await listenManagement(server, socketPath)
const client = new LocalApiClient(socketPath)
try {
assert.deepEqual(await client.request('GET', `${API_PREFIX}files/config`), {
defaultPath: '/custom/workspace', shortcuts: ['/custom/workspace', '/custom/dsh', '/custom/platform', '/'],
})
const encodedRoot = encodeURIComponent(files)
const listed = await client.request('GET', `${API_PREFIX}files/list?path=${encodedRoot}`)
assert.deepEqual(listed.entries.map(entry => entry.name), ['alpha.txt'])
await writeFile(join(files, 'beta.txt'), 'beta')
const secondPage = await client.request('GET', `${API_PREFIX}files/list?path=${encodedRoot}&limit=1&offset=1`)
assert.deepEqual(secondPage.entries.map(entry => entry.name), ['beta.txt'])
assert.equal(await client.request('GET', `${API_PREFIX}files/stat?path=${encodeURIComponent(join(files, 'missing'))}&optional=true`), null)
const content = await client.request('GET', `${API_PREFIX}files/content?path=${encodeURIComponent(join(files, 'alpha.txt'))}`)
assert.equal(content.content, '0123456789')
const saved = await client.request('PUT', `${API_PREFIX}files/content`, {
path: join(files, 'alpha.txt'), content: 'edited', revision: content.revision,
})
assert.equal(saved.size, 6)
assert.equal(await readFile(join(files, 'alpha.txt'), 'utf8'), 'edited')
const refreshed = await client.request('GET', `${API_PREFIX}files/list?path=${encodedRoot}`)
const search = await client.request('POST', `${API_PREFIX}files/tasks`, { operation: 'search', path: files, revision: refreshed.revision, query: 'alpha' })
await fileTasks.completion(search.taskId)
assert.equal((await client.request('GET', `${API_PREFIX}files/tasks/${search.taskId}`)).results[0].name, 'alpha.txt')
const uploadPath = join(files, 'uploaded.txt')
const uploaded = await new Promise((resolve, reject) => {
const request = httpRequest({
socketPath, method: 'POST',
path: `${API_PREFIX}files/upload?path=${encodeURIComponent(uploadPath)}&conflict=reject`,
headers: { 'content-length': '8' },
}, response => {
const chunks = []
response.on('data', chunk => chunks.push(chunk))
response.on('end', () => resolve({ status: response.statusCode, value: JSON.parse(Buffer.concat(chunks)) }))
})
request.once('error', reject)
request.end('uploaded')
})
assert.equal(uploaded.status, 201)
assert.equal(await readFile(uploadPath, 'utf8'), 'uploaded')
const duplicate = await new Promise((resolve, reject) => {
const request = httpRequest({
socketPath, method: 'POST',
path: `${API_PREFIX}files/upload?path=${encodeURIComponent(uploadPath)}&conflict=reject`,
headers: { 'content-length': '9' },
}, response => {
const chunks = []
response.on('data', chunk => chunks.push(chunk))
response.on('end', () => resolve({ status: response.statusCode, value: JSON.parse(Buffer.concat(chunks)) }))
})
request.once('error', reject)
request.end('duplicate')
})
assert.deepEqual(duplicate, { status: 409, value: { error: 'upload target already exists', code: 'FILE_EXISTS' } })
assert.equal(await readFile(uploadPath, 'utf8'), 'uploaded')
const downloaded = await new Promise((resolve, reject) => {
const request = httpRequest({
socketPath, method: 'GET',
path: `${API_PREFIX}files/download?path=${encodeURIComponent(uploadPath)}&revision=${encodeURIComponent(uploaded.value.revision)}`,
headers: { range: 'bytes=2-5' },
}, response => {
const chunks = []
response.on('data', chunk => chunks.push(chunk))
response.on('end', () => resolve({ status: response.statusCode, body: Buffer.concat(chunks).toString() }))
})
request.once('error', reject)
request.end()
})
assert.deepEqual(downloaded, { status: 206, body: 'load' })
const downloadTask = fileTasks.list().find(task => task.operation === 'download')
assert.notEqual(downloadTask, undefined)
await fileTasks.completion(downloadTask.taskId)
const transferTasks = (await client.request('GET', `${API_PREFIX}files/tasks`)).tasks
assert.equal(transferTasks.some(task => task.operation === 'upload' && task.status === 'success' && task.processedBytes === 8), true)
assert.equal(transferTasks.some(task => task.operation === 'upload' && task.status === 'failed' && task.errorCode === 'FILE_EXISTS'), true)
assert.equal(transferTasks.some(task => task.operation === 'download' && task.status === 'success' && task.processedBytes === 4), true)
await new Promise(resolve => setTimeout(resolve, 20))
const audit = await logs.query({ sources: ['audit'] })
assert.equal(audit.some(entry => entry.message === 'files.upload.completed' && entry.size === 8), true)
assert.equal(audit.some(entry => entry.message === 'files.download.completed'), true)
} finally {
await new Promise(resolve => server.close(resolve))
}
})