dsh 0.2.0-rc.2: in-container update (experimental channel), path-agnostic compose, upstream patches adapted to 0.1.x/0.2.x
This commit is contained in:
commit
e6dcef9bf5
302 files changed
+75178
No files matched your search
@@ -0,0 +1,170 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { mkdtemp, mkdir, readFile, readdir, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import test from 'node:test'
|
||||
import { parseComponentManifest, parseEnvironmentManifest } from '../lib/contracts.mjs'
|
||||
import {
|
||||
materializeSystemSkillCatalog,
|
||||
readSystemSkillCatalog,
|
||||
retainLegacySystemSkillCatalog,
|
||||
} from '../../control-plane/modules/skill-manager/index.mjs'
|
||||
|
||||
const platformRoot = dirname(dirname(fileURLToPath(import.meta.url)))
|
||||
const containerRoot = dirname(platformRoot)
|
||||
const definition = join(containerRoot, 'environment', 'definition.json')
|
||||
const tool = join(platformRoot, 'tools', 'package-environment.mjs')
|
||||
|
||||
async function build() {
|
||||
const root = await mkdtemp(join(tmpdir(), 'dsh-environment-package-'))
|
||||
const output = join(root, 'output')
|
||||
const result = spawnSync(process.execPath, [tool, definition, output], { encoding: 'utf8' })
|
||||
assert.equal(result.status, 0, result.stderr)
|
||||
return output
|
||||
}
|
||||
|
||||
test('packages the initial Environment deterministically from real resources', async () => {
|
||||
const first = await build()
|
||||
const second = await build()
|
||||
const firstManifest = await readFile(join(first, 'environment.manifest.json'))
|
||||
const secondManifest = await readFile(join(second, 'environment.manifest.json'))
|
||||
assert.deepEqual(firstManifest, secondManifest)
|
||||
const manifest = parseEnvironmentManifest(firstManifest)
|
||||
assert.deepEqual(manifest.components.map(component => component.id), ['dsh-runtime'])
|
||||
assert.deepEqual(manifest.patches.map(patch => patch.id), [
|
||||
'directory-picker', 'browser-loopback', 'managed-lifecycle', 'native-corners',
|
||||
])
|
||||
assert.deepEqual(manifest.systemPlugins.map(plugin => plugin.id), [
|
||||
'platform-management', 'settings-navigation', 'settings-document-editor',
|
||||
])
|
||||
for (const reference of [...manifest.components, ...manifest.patches, ...manifest.systemPlugins]) {
|
||||
assert.deepEqual(Object.keys(reference).sort(), ['id', 'sha256'])
|
||||
}
|
||||
assert.deepEqual(await readdir(join(first, 'artifacts')), await readdir(join(second, 'artifacts')))
|
||||
const skillArtifact = manifest.artifacts.find(artifact => artifact.id === 'system-skill-catalog')
|
||||
assert.equal(skillArtifact?.mediaType, 'application/vnd.dsh-platform.system-skill-catalog.v1+tar+gzip')
|
||||
const skillArchive = join(first, 'artifacts', 'system-skill-catalog')
|
||||
const skillListing = spawnSync('tar', ['-tzf', skillArchive], { encoding: 'utf8' })
|
||||
assert.equal(skillListing.status, 0, skillListing.stderr)
|
||||
assert.match(skillListing.stdout, /^skills\/catalog\.json$/m)
|
||||
assert.match(skillListing.stdout, /^skills\/dsh-docker-operations\/SKILL\.md$/m)
|
||||
const navigationArchive = join(first, 'artifacts', 'system-plugin-settings-navigation')
|
||||
const listing = spawnSync('tar', ['-tzf', navigationArchive], { encoding: 'utf8' })
|
||||
assert.equal(listing.status, 0, listing.stderr)
|
||||
assert.match(listing.stdout, /^package\/lib\/client\.bundle\.js$/m)
|
||||
assert.match(listing.stdout, /^package\/cordis\.patch\.json$/m)
|
||||
})
|
||||
|
||||
test('can emit flat Artifact URLs for GitHub Release assets', async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), 'dsh-environment-flat-'))
|
||||
const output = join(root, 'output')
|
||||
const result = spawnSync(process.execPath, [
|
||||
tool, definition, output, '1', '1', 'https://release.example/platform-1/', 'flat',
|
||||
], { encoding: 'utf8' })
|
||||
assert.equal(result.status, 0, result.stderr)
|
||||
const manifest = parseEnvironmentManifest(await readFile(join(output, 'environment.manifest.json')))
|
||||
assert.equal(manifest.artifacts.every(artifact => artifact.url.startsWith('https://release.example/platform-1/')), true)
|
||||
assert.equal(manifest.artifacts.every(artifact => !artifact.url.includes('/artifacts/')), true)
|
||||
})
|
||||
|
||||
test('materializes the verified System Skill catalog from an Environment Artifact', async () => {
|
||||
const environmentRoot = await build()
|
||||
const outputRoot = await mkdtemp(join(tmpdir(), 'dsh-system-skill-catalogs-'))
|
||||
const materialized = await materializeSystemSkillCatalog({ environmentRoot, outputRoot })
|
||||
const catalog = await readSystemSkillCatalog(materialized)
|
||||
assert.deepEqual(catalog.map(skill => skill.id), ['dsh-docker-operations'])
|
||||
|
||||
await writeFile(join(environmentRoot, 'artifacts', 'system-skill-catalog'), 'tampered')
|
||||
await assert.rejects(
|
||||
materializeSystemSkillCatalog({ environmentRoot, outputRoot }),
|
||||
/differs from its Environment manifest/,
|
||||
)
|
||||
})
|
||||
|
||||
test('retains a legacy Bootstrap System Skill catalog without reading Stage-0 state', async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), 'dsh-legacy-system-skill-'))
|
||||
const source = join(root, 'seed', 'bootstrap', '1.0.9', 'control-plane', 'skills')
|
||||
const skill = join(source, 'legacy-skill')
|
||||
const output = join(root, 'environments', 'versions', '.system-skill-catalogs')
|
||||
await mkdir(skill, { recursive: true })
|
||||
await writeFile(join(source, 'catalog.json'), JSON.stringify({
|
||||
schema: 1,
|
||||
skills: [{
|
||||
id: 'legacy-skill',
|
||||
source: 'legacy-skill',
|
||||
description: { en: 'Legacy skill', zh: 'Legacy skill' },
|
||||
}],
|
||||
}))
|
||||
await writeFile(join(skill, 'SKILL.md'), '---\nname: legacy-skill\ndescription: Legacy skill\n---\n')
|
||||
|
||||
const retained = await retainLegacySystemSkillCatalog({ sourceRoot: source, outputRoot: output })
|
||||
assert.equal(retained, join(output, 'legacy-bootstrap'))
|
||||
assert.deepEqual((await readSystemSkillCatalog(retained)).map(entry => entry.id), ['legacy-skill'])
|
||||
assert.equal(await retainLegacySystemSkillCatalog({ sourceRoot: join(root, 'missing'), outputRoot: output }), retained)
|
||||
|
||||
const bootstrap = await readFile(new URL('../bootstrap/index.mjs', import.meta.url), 'utf8')
|
||||
assert.match(bootstrap, /inventory\.bootstrap\.id, 'control-plane', 'skills'/)
|
||||
assert.doesNotMatch(bootstrap, /bootstrapStateRoot/)
|
||||
})
|
||||
|
||||
test('checked-in Component manifests satisfy the public contract', async () => {
|
||||
for (const path of [
|
||||
join(containerRoot, 'control-plane', 'services', 'gateway', 'component.json'),
|
||||
join(containerRoot, 'environment', 'dsh-runtime', 'component.json'),
|
||||
join(containerRoot, 'control-plane', 'services', 'management', 'component.json'),
|
||||
join(containerRoot, 'control-plane', 'hooks', 'recovery', 'component.json'),
|
||||
]) {
|
||||
const bytes = await readFile(path)
|
||||
const component = parseComponentManifest(bytes)
|
||||
assert.equal(Object.hasOwn(component, 'version'), false)
|
||||
}
|
||||
})
|
||||
|
||||
test('DSH Runtime uses the generic node home environment without package-manager overrides', async () => {
|
||||
const component = parseComponentManifest(await readFile(
|
||||
join(containerRoot, 'environment', 'dsh-runtime', 'component.json'),
|
||||
))
|
||||
assert.deepEqual(component.environment, {
|
||||
DSH_BUNDLED_SKILL_DIR: '/run/dsh-platform/views/skills',
|
||||
HOME: '/home/node',
|
||||
LOGNAME: 'node',
|
||||
USER: 'node',
|
||||
XDG_CACHE_HOME: '/home/node/.cache',
|
||||
XDG_CONFIG_HOME: '/home/node/.config',
|
||||
XDG_DATA_HOME: '/home/node/.local/share',
|
||||
})
|
||||
assert.doesNotMatch(JSON.stringify(component.environment), /NPM_CONFIG_CACHE|PNPM_HOME/)
|
||||
})
|
||||
|
||||
test('container images opt into the managed DSH lifecycle without exposing a user setting', async () => {
|
||||
const dockerfile = await readFile(join(dirname(containerRoot), 'Dockerfile'), 'utf8')
|
||||
assert.match(dockerfile, /ENV DSH_PLATFORM_DATA=\/data\/platform \\\n+ DSH_PLATFORM_MANAGED=1 \\\n+ DSH_PLATFORM_RUN=\/run\/dsh-platform \\/)
|
||||
})
|
||||
|
||||
test('platform CLI shim follows the current verified Bootstrap view', async () => {
|
||||
const dockerfile = await readFile(join(dirname(containerRoot), 'Dockerfile'), 'utf8')
|
||||
const shim = await readFile(join(platformRoot, 'tools', 'dsh-platform-shim.sh'), 'utf8')
|
||||
assert.match(dockerfile, /COPY container\/platform\/tools\/dsh-platform-shim\.sh \/usr\/local\/bin\/dsh-platform/)
|
||||
assert.match(shim, /views\/bootstrap\/control-plane\/services\/management\/dsh-platform\.mjs/)
|
||||
assert.match(shim, /opt\/dsh-platform\/runtime\/control-plane\/services\/management\/dsh-platform\.mjs/)
|
||||
assert.ok(shim.indexOf('managed_cli') < shim.indexOf('image_cli'))
|
||||
})
|
||||
|
||||
test('packager rejects source escapes and duplicate Artifact IDs without publishing output', async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), 'dsh-environment-invalid-'))
|
||||
const original = JSON.parse(await readFile(definition, 'utf8'))
|
||||
original.components[0].source = '../../../../README.md'
|
||||
original.components.push({ ...original.components[0] })
|
||||
const invalid = join(dirname(definition), `invalid-${process.pid}.json`)
|
||||
const output = join(root, 'output')
|
||||
try {
|
||||
await writeFile(invalid, JSON.stringify(original))
|
||||
const result = spawnSync(process.execPath, [tool, invalid, output], { encoding: 'utf8' })
|
||||
assert.notEqual(result.status, 0)
|
||||
await assert.rejects(readdir(output), { code: 'ENOENT' })
|
||||
} finally {
|
||||
await import('node:fs/promises').then(({ rm }) => rm(invalid, { force: true }))
|
||||
}
|
||||
})
|
||||
Reference in new issue
Block a user