44 lines
4.6 KiB
JavaScript
44 lines
4.6 KiB
JavaScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import {createHash, createPrivateKey, createPublicKey, sign, verify} from 'node:crypto'
|
|
import {mkdtemp, rm, writeFile, readdir, readFile, stat, chmod} from 'node:fs/promises'
|
|
import path from 'node:path'
|
|
import {tmpdir} from 'node:os'
|
|
import {deploymentRequest, createBootstrapMaterial, initializeBootstrap, main} from './database-writer-bootstrap-operator.mjs'
|
|
const hash = b => createHash('sha256').update(b).digest('hex')
|
|
const request = () => ({format: 'application-writer-bootstrap-request-v1', installationId: 'f8b410ef-11ba-4419-b6a6-e735e505450b', sourceHeadSha256: 'a'.repeat(64),
|
|
source: {systemIdentifier: '7387529813445422155', databaseOid: '16384', databaseName: 'operator-fixture', serverVersionNum: 180004, inRecovery: false},
|
|
roles: Object.fromEntries(['runtime', 'operator', 'capture', 'publisher', 'control'].map((name, i) => [name, {name: 'fixture_' + name, signedOid: String(20000 + i)}])),
|
|
tls: {serverName: 'db.example.invalid', caSha256: 'b'.repeat(64), spkiSha256: 'c'.repeat(64)}})
|
|
test('real distinct Ed25519 keypairs sign/verify and preserve externally pinned subject without authorization', () => {
|
|
const value = request(), a = createBootstrapMaterial(value, 'd'.repeat(64)), b = createBootstrapMaterial(value, 'd'.repeat(64))
|
|
const privateKey = createPrivateKey(a.privateKeyPem), publicKey = createPublicKey(a.publicKeyPem), message = Buffer.from('owned-key-roundtrip')
|
|
assert(verify(null, message, publicKey, sign(null, message, privateKey))); assert(!verify(null, Buffer.from('changed'), publicKey, sign(null, message, privateKey)))
|
|
assert.equal(hash(publicKey.export({format: 'der', type: 'spki'})), a.bootstrap.verificationSubject.publicKeySpkiSha256)
|
|
assert.notEqual(a.publicKeyPem, b.publicKeyPem); assert.equal(a.bootstrap.verificationSubject.installationId, value.installationId)
|
|
assert.equal(a.bootstrap.publicationAuthorized, false); assert.equal(a.bootstrap.readyAuthorized, false); assert.equal(a.bootstrap.approvedDefinitionSha256, null)
|
|
assert.equal(a.bootstrap.databaseObserved, false); assert(!JSON.stringify(a.bootstrap).includes('PRIVATE KEY')); value.roles.runtime.name = 'changed'; assert.notEqual(a.bootstrap.deploymentRequest.roles.runtime.name, 'changed')
|
|
})
|
|
test('missing roles/head/transport pin and malformed identities refuse rather than invent trust', () => {
|
|
for (const change of [v => delete v.roles.control, v => delete v.sourceHeadSha256, v => delete v.tls.spkiSha256, v => v.roles.operator = v.roles.runtime, v => v.source.databaseOid = 16384, v => v.source.inRecovery = true, v => v.extra = true]) {
|
|
const value = request(); change(value); assert.throws(() => deploymentRequest(value))
|
|
}
|
|
})
|
|
test('unknown/duplicate CLI options refuse without an implicit startup mode', async () => {
|
|
for (const args of [[], ['publish'], ['init', '--output', '/x', '--output', '/y', '--deployment-sha256', 'd'.repeat(64)]]) await assert.rejects(main(args))
|
|
})
|
|
test('actual protected filesystem init, no-replace and mismatched digest; unsupported Windows writes nothing', async () => {
|
|
const parent = await mkdtemp(path.join(tmpdir(), 'mm-bootstrap-init-')), output = path.join(parent, 'keys'), file = path.join(parent, 'deployment.json'), bytes = Buffer.from(JSON.stringify(request()))
|
|
try {
|
|
await chmod(parent, 0o700); await writeFile(file, bytes, {mode: 0o600})
|
|
const options = {outputDirectory: output, deploymentFile: file, deploymentSha256: hash(bytes)}
|
|
if (process.platform === 'win32') { await assert.rejects(initializeBootstrap(options), /Windows ACL backend unavailable/); assert.deepEqual(await readdir(parent), ['deployment.json']); return }
|
|
await assert.rejects(initializeBootstrap({...options, deploymentSha256: '0'.repeat(64)})); assert.deepEqual(await readdir(parent), ['deployment.json'])
|
|
const receipt = await initializeBootstrap(options); assert.equal(receipt.publicationAuthorized, false); assert(!JSON.stringify(receipt).includes('PRIVATE KEY'))
|
|
assert.equal((await stat(output)).mode & 0o777, 0o700); assert.equal((await stat(path.join(output, 'signing-private.pem'))).mode & 0o777, 0o600)
|
|
const first = await readFile(path.join(output, 'signing-private.pem')); await assert.rejects(initializeBootstrap(options), {code: 'EEXIST'}); assert.deepEqual(await readFile(path.join(output, 'signing-private.pem')), first)
|
|
assert.deepEqual((await readdir(output)).sort(), ['bootstrap.json', 'operator-public.pem', 'signing-private.pem'])
|
|
assert.equal(JSON.parse(await readFile(path.join(output, 'bootstrap.json'), 'utf8')).verificationSubject.publicKeySpkiSha256, receipt.publicKeySpkiSha256)
|
|
} finally { await rm(parent, {recursive: true, force: true}) }
|
|
})
|