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

354 lines
17 KiB
JavaScript

import assert from 'node:assert/strict'
import { createHash } from 'node:crypto'
import { mkdir, mkdtemp, readFile, stat, symlink, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import test from 'node:test'
import { MANIFEST_MEDIA_TYPE, SIGNATURE_MEDIA_TYPE, VerifiedObjectStore } from '../stage0/lib/artifacts.mjs'
import { TrustLedger } from '../stage0/lib/ledger.mjs'
import { document, officialDshPolicy, keyPair, keyring, registryCandidate, registryKeyPair, signature } from './helpers.mjs'
function descriptor(id, content, mediaType = 'application/octet-stream') {
return {
id,
mediaType,
sha256: createHash('sha256').update(content).digest('hex'),
size: content.byteLength,
url: `https://github.com/example/releases/download/v1/${id}`,
}
}
function releaseTarget(generation, sequence, artifacts, policy = officialDshPolicy()) {
const selected = artifacts[0]
const signatureArtifact = descriptor('stable-signature', Buffer.from('signature'), 'application/vnd.dsh-platform.signature.v1+json')
const targetArtifacts = artifacts.some(artifact => artifact.id === signatureArtifact.id)
? artifacts
: [...artifacts, signatureArtifact]
return {
schema: 1,
updateApi: 1,
keyringGeneration: generation,
targetSequence: sequence,
issuedAt: '2026-08-19T00:00:00.000Z',
artifacts: targetArtifacts,
desired: {
bootstrap: { version: '1.0.0', manifestArtifactId: selected.id, signatureArtifactId: signatureArtifact.id },
environment: { version: '1.0.0', manifestArtifactId: selected.id, signatureArtifactId: signatureArtifact.id },
dsh: {
version: '0.1.0-rc.7',
integrity: `sha512-${Buffer.alloc(64).toString('base64')}`,
},
},
officialDshPolicy: policy,
}
}
function manifest(generation, sequence, artifacts) {
return {
schema: 1,
manifestType: 'environment',
version: '1.0.0',
keyringGeneration: generation,
targetSequence: sequence,
issuedAt: '2026-08-19T00:00:00.000Z',
artifacts,
bootstrapApi: 1,
components: [],
patches: [],
systemPlugins: [],
}
}
async function fixture(targetArtifacts, policy = officialDshPolicy()) {
const directory = await mkdtemp(join(tmpdir(), 'dsh-object-store-'))
const recovery = keyPair()
const current = keyPair()
const next = keyPair()
const ledger = new TrustLedger(join(directory, 'trust'), recovery.publicKey)
const ringBytes = document(keyring(1, current, next))
await ledger.acceptKeyring(ringBytes, signature(ringBytes, recovery))
const artifacts = typeof targetArtifacts === 'function' ? targetArtifacts(current) : targetArtifacts
const targetBytes = document(releaseTarget(1, 1, artifacts, policy))
await ledger.acceptTarget(targetBytes, signature(targetBytes, current))
const untrustedRoot = join(directory, 'downloads', 'untrusted')
await mkdir(untrustedRoot, { recursive: true })
return {
current,
directory,
ledger,
next,
recovery,
store: new VerifiedObjectStore({ root: join(directory, 'trust'), untrustedRoot, ledger }),
untrustedRoot,
}
}
test('empty activation succeeds before release trust is initialized', async () => {
const directory = await mkdtemp(join(tmpdir(), 'dsh-empty-activation-'))
const recovery = keyPair()
const ledger = new TrustLedger(join(directory, 'trust'), recovery.publicKey)
const untrustedRoot = join(directory, 'downloads', 'untrusted')
await mkdir(untrustedRoot, { recursive: true })
const store = new VerifiedObjectStore({ root: join(directory, 'trust'), untrustedRoot, ledger })
assert.deepEqual(await store.activate([]), [])
})
async function importSignature(store, untrustedRoot, signatureBytes) {
const path = join(untrustedRoot, 'manifest.sig.json')
await writeFile(path, signatureBytes)
return store.importFromTarget('stable-signature', path)
}
async function officialSources(untrustedRoot, candidate, content, suffix = '') {
const metadataPath = join(untrustedRoot, `official-dsh${suffix}.json`)
const tarballPath = join(untrustedRoot, `official-dsh${suffix}.tgz`)
await writeFile(metadataPath, JSON.stringify({ versions: { [candidate.version]: candidate } }))
await writeFile(tarballPath, content)
return { metadataPath, tarballPath }
}
test('imports only target-authorized bytes from the untrusted directory', async () => {
const content = Buffer.from('verified artifact')
const expected = descriptor('gateway', content)
const { store, untrustedRoot, directory } = await fixture([expected])
const source = join(untrustedRoot, 'gateway.bin')
await writeFile(source, content)
const receipt = await store.importFromTarget('gateway', source)
assert.equal(receipt.objectSha256, expected.sha256)
assert.deepEqual(await readFile(receipt.path), content)
assert.equal((await stat(receipt.path)).mode & 0o777, 0o444)
await assert.rejects(store.importFromTarget('missing', source), /not authorized/)
await assert.rejects(store.importFromTarget('gateway', join(directory, 'outside.bin')), /untrusted/)
})
test('treats receipts written before authority typing as Stable receipts', async () => {
const content = Buffer.from('legacy stable artifact')
const { store, untrustedRoot } = await fixture([descriptor('legacy', content)])
const source = join(untrustedRoot, 'legacy')
await writeFile(source, content)
const receipt = await store.importFromTarget('legacy', source)
const persisted = JSON.parse(await readFile(store.receiptPath(receipt.token), 'utf8'))
delete persisted.authorityType
await writeFile(store.receiptPath(receipt.token), `${JSON.stringify(persisted)}\n`)
assert.equal((await store.readReceipt(receipt.token)).authorityType, 'stable')
})
test('verifies updater-downloaded official DSH metadata and tarball without networking', async () => {
const content = Buffer.from('official tarball')
const registry = registryKeyPair()
const candidate = registryCandidate(registry, '0.1.0-rc.8', content)
const policy = officialDshPolicy(registry)
const { current, ledger, untrustedRoot, directory } = await fixture(
[descriptor('stable-only', Buffer.alloc(0))],
policy,
)
const store = new VerifiedObjectStore({ root: join(directory, 'trust'), untrustedRoot, ledger })
const advanced = document(releaseTarget(1, 2, [descriptor('stable-only', Buffer.alloc(0))], policy))
await ledger.acceptTarget(advanced, signature(advanced, current))
const sources = await officialSources(untrustedRoot, candidate, content)
const receipt = await store.ensureOfficialDsh(candidate.version, sources.metadataPath, sources.tarballPath)
assert.equal(receipt.authorityType, 'official-dsh')
assert.equal(receipt.authorityVersion, candidate.version)
assert.equal(receipt.targetSequence, 2)
assert.deepEqual(await readFile(receipt.path), content)
await store.activate([receipt.token])
assert.equal((await store.readReceipt(receipt.token)).status, 'active')
})
test('official DSH import accepts only regular files inside the untrusted directory', async () => {
const content = Buffer.from('official tarball')
const registry = registryKeyPair()
const candidate = registryCandidate(registry, '0.1.0-rc.8', content)
const { store, untrustedRoot, directory } = await fixture(
[descriptor('stable-only', Buffer.alloc(0))],
officialDshPolicy(registry),
)
const outside = await officialSources(directory, candidate, content)
await assert.rejects(store.ensureOfficialDsh(candidate.version, outside.metadataPath, outside.tarballPath), /untrusted/)
const sources = await officialSources(untrustedRoot, candidate, content)
const metadataLink = join(untrustedRoot, 'metadata-link.json')
await symlink(sources.metadataPath, metadataLink)
await assert.rejects(store.ensureOfficialDsh(candidate.version, metadataLink, sources.tarballPath), /ELOOP|symbolic/i)
})
test('official DSH import rejects malformed metadata and mismatched tarball bytes', async () => {
const content = Buffer.from('official tarball')
const registry = registryKeyPair()
const candidate = registryCandidate(registry, '0.1.0-rc.8', content)
const { store, untrustedRoot } = await fixture(
[descriptor('stable-only', Buffer.alloc(0))],
officialDshPolicy(registry),
)
const malformed = join(untrustedRoot, 'malformed.json')
const tarball = join(untrustedRoot, 'official.tgz')
await writeFile(malformed, '{')
await writeFile(tarball, content)
await assert.rejects(store.ensureOfficialDsh(candidate.version, malformed, tarball), /valid JSON/)
const sources = await officialSources(untrustedRoot, candidate, Buffer.from('different bytes'), '-mismatch')
await assert.rejects(
store.ensureOfficialDsh(candidate.version, sources.metadataPath, sources.tarballPath),
{ code: 'TRUST_ARTIFACT_MISMATCH' },
)
})
test('revokes staged official DSH receipts after Registry delegation changes but retains active objects', async () => {
const content = Buffer.from('official tarball')
const registry = registryKeyPair()
const replacement = registryKeyPair()
const candidate = registryCandidate(registry, '0.1.0-rc.8', content)
const { current, directory, ledger, untrustedRoot } = await fixture(
[descriptor('stable-only', Buffer.alloc(0))],
officialDshPolicy(registry),
)
const store = new VerifiedObjectStore({ root: join(directory, 'trust'), untrustedRoot, ledger })
const first = await officialSources(untrustedRoot, candidate, content, '-active')
const active = await store.ensureOfficialDsh(candidate.version, first.metadataPath, first.tarballPath)
await store.activate([active.token])
const second = await officialSources(untrustedRoot, candidate, content, '-staged')
const staged = await store.ensureOfficialDsh(candidate.version, second.metadataPath, second.tarballPath)
const advanced = document(releaseTarget(
1,
2,
[descriptor('stable-only', Buffer.alloc(0))],
officialDshPolicy(replacement),
))
await ledger.acceptTarget(advanced, signature(advanced, current))
await store.reconcileRevocations((await ledger.currentKeyring()).value)
assert.equal((await store.readReceipt(active.token)).status, 'active')
assert.equal((await store.readReceipt(staged.token)).status, 'revoked')
})
test('rejects mismatched content and symbolic-link sources', async () => {
const expected = descriptor('gateway', Buffer.from('expected'))
const { store, untrustedRoot } = await fixture([expected])
const bad = join(untrustedRoot, 'bad.bin')
await writeFile(bad, 'different')
await assert.rejects(store.importFromTarget('gateway', bad), { code: 'TRUST_ARTIFACT_MISMATCH' })
const real = join(untrustedRoot, 'real.bin')
const link = join(untrustedRoot, 'link.bin')
await writeFile(real, 'expected')
await symlink(real, link)
await assert.rejects(store.importFromTarget('gateway', link), /ELOOP|symbolic/i)
})
test('verifies a signed manifest before authorizing its child artifacts', async () => {
const component = Buffer.from('component')
const manifestBytes = document(manifest(1, 1, [descriptor('component', component)]))
const manifestDescriptor = descriptor('environment-manifest', manifestBytes, MANIFEST_MEDIA_TYPE)
let signatureBytes
const { store, untrustedRoot } = await fixture(current => {
signatureBytes = document(signature(manifestBytes, current))
return [manifestDescriptor, descriptor('stable-signature', signatureBytes, SIGNATURE_MEDIA_TYPE)]
})
const manifestPath = join(untrustedRoot, 'manifest.json')
await writeFile(manifestPath, manifestBytes)
const imported = await store.importFromTarget('environment-manifest', manifestPath)
await assert.rejects(store.importFromManifest(imported.token, 'component', manifestPath), /verified manifest/)
const signatureReceipt = await importSignature(store, untrustedRoot, signatureBytes)
await store.acceptManifest(imported.token, signatureReceipt.token)
const componentPath = join(untrustedRoot, 'component.bin')
await writeFile(componentPath, component)
const child = await store.importFromManifest(imported.token, 'component', componentPath)
assert.equal(child.parentReceipt, imported.token)
})
test('revokes unactivated receipts after key rotation but retains active and previous objects', async () => {
const one = Buffer.from('one')
const two = Buffer.from('two')
const third = Buffer.from('three')
const descriptors = [descriptor('one', one), descriptor('two', two), descriptor('three', third)]
const { current, next, recovery, ledger, store, untrustedRoot } = await fixture(descriptors)
for (const [name, content] of [['one', one], ['two', two], ['three', third]]) {
await writeFile(join(untrustedRoot, name), content)
}
const first = await store.importFromTarget('one', join(untrustedRoot, 'one'))
const second = await store.importFromTarget('two', join(untrustedRoot, 'two'))
const unactivated = await store.importFromTarget('three', join(untrustedRoot, 'three'))
await store.activate([first.token])
await store.activate([second.token])
const future = keyPair()
const rotated = document(keyring(2, next, future, [current.keyId]))
const rotatedValue = await ledger.acceptKeyring(rotated, signature(rotated, recovery))
await assert.rejects(store.importFromTarget('three', join(untrustedRoot, 'three')), { code: 'TRUST_REVOKED' })
await assert.rejects(store.activate([unactivated.token]), { code: 'TRUST_REVOKED' })
const revoked = await store.reconcileRevocations(rotatedValue)
assert.deepEqual(revoked, [unactivated.token])
assert.equal((await store.readReceipt(first.token)).status, 'previous')
assert.equal((await store.readReceipt(second.token)).status, 'active')
await store.collectGarbage()
await assert.rejects(store.readReceipt(unactivated.token), /does not exist/)
assert.deepEqual(await readFile(store.objectPath(descriptors[0].sha256)), one)
assert.deepEqual(await readFile(store.objectPath(descriptors[1].sha256)), two)
})
test('activation includes manifest ancestors and rollback swaps current and previous', async () => {
const component = Buffer.from('component')
const other = Buffer.from('other')
const manifestBytes = document(manifest(1, 1, [descriptor('component', component)]))
const manifestDescriptor = descriptor('environment-manifest', manifestBytes, MANIFEST_MEDIA_TYPE)
let signatureBytes
const { store, untrustedRoot } = await fixture(current => {
signatureBytes = document(signature(manifestBytes, current))
return [
manifestDescriptor,
descriptor('stable-signature', signatureBytes, SIGNATURE_MEDIA_TYPE),
descriptor('other', other),
]
})
await writeFile(join(untrustedRoot, 'manifest'), manifestBytes)
await writeFile(join(untrustedRoot, 'component'), component)
await writeFile(join(untrustedRoot, 'other'), other)
const parent = await store.importFromTarget('environment-manifest', join(untrustedRoot, 'manifest'))
const signatureReceipt = await importSignature(store, untrustedRoot, signatureBytes)
await store.acceptManifest(parent.token, signatureReceipt.token)
const child = await store.importFromManifest(parent.token, 'component', join(untrustedRoot, 'component'))
const selected = await store.activate([child.token])
assert.deepEqual(new Set(selected), new Set([parent.token, child.token]))
assert.equal((await store.readReceipt(parent.token)).status, 'active')
const nextReceipt = await store.importFromTarget('other', join(untrustedRoot, 'other'))
await store.activate([nextReceipt.token])
assert.equal((await store.readReceipt(parent.token)).status, 'previous')
await store.rollback()
assert.equal((await store.readReceipt(parent.token)).status, 'active')
assert.equal((await store.readReceipt(nextReceipt.token)).status, 'previous')
})
test('rejects staged receipts after the current Release Key advances targetSequence', async () => {
const content = Buffer.from('old target artifact')
const expected = descriptor('artifact', content)
const { current, ledger, store, untrustedRoot } = await fixture([expected])
const source = join(untrustedRoot, 'artifact')
await writeFile(source, content)
const receipt = await store.importFromTarget('artifact', source)
const advanced = document(releaseTarget(1, 2, [expected]))
await ledger.acceptTarget(advanced, signature(advanced, current))
await assert.rejects(store.activate([receipt.token]), { code: 'TRUST_REVOKED' })
})
test('rejects child imports through a manifest from an older targetSequence', async () => {
const component = Buffer.from('component')
const componentDescriptor = descriptor('component', component)
const manifestBytes = document(manifest(1, 1, [componentDescriptor]))
const manifestDescriptor = descriptor('environment-manifest', manifestBytes, MANIFEST_MEDIA_TYPE)
let signatureBytes
const { current, ledger, store, untrustedRoot } = await fixture(release => {
signatureBytes = document(signature(manifestBytes, release))
return [manifestDescriptor, descriptor('stable-signature', signatureBytes, SIGNATURE_MEDIA_TYPE)]
})
await writeFile(join(untrustedRoot, 'manifest'), manifestBytes)
await writeFile(join(untrustedRoot, 'component'), component)
const parent = await store.importFromTarget('environment-manifest', join(untrustedRoot, 'manifest'))
const signatureReceipt = await importSignature(store, untrustedRoot, signatureBytes)
await store.acceptManifest(parent.token, signatureReceipt.token)
const advanced = document(releaseTarget(1, 2, [manifestDescriptor]))
await ledger.acceptTarget(advanced, signature(advanced, current))
await assert.rejects(
store.importFromManifest(parent.token, 'component', join(untrustedRoot, 'component')),
{ code: 'TRUST_REVOKED' },
)
})