Files
ycode/scripts/updates/contract-selftest.mjs
T

85 lines
2.6 KiB
JavaScript

import assert from 'node:assert/strict'
import crypto from 'node:crypto'
import fsp from 'node:fs/promises'
import os from 'node:os'
import path from 'node:path'
import { pathToFileURL } from 'node:url'
import { build } from 'esbuild'
import {
DEFAULT_BASE_URL,
DEFAULT_PUBLIC_KEY,
REPO_ROOT,
generateEd25519KeyPair,
normalizeBaseUrl,
readPublicKey,
signPayload
} from './lib.mjs'
async function main() {
const temporary = await fsp.mkdtemp(path.join(os.tmpdir(), 'ycode-contract-selftest-'))
try {
const bundlePath = path.join(temporary, 'manifest.mjs')
await build({
entryPoints: [path.join(REPO_ROOT, 'src', 'main', 'updates', 'manifest.ts')],
bundle: true,
platform: 'node',
format: 'esm',
outfile: bundlePath,
logLevel: 'silent'
})
const backend = await import(`${pathToFileURL(bundlePath).href}?v=${Date.now()}`)
assert.equal(typeof backend.verifySignedManifest, 'function')
const trustAnchor = await readPublicKey(DEFAULT_PUBLIC_KEY)
const trustKey = crypto.createPublicKey(trustAnchor)
assert.equal(trustKey.asymmetricKeyType, 'ed25519')
const keys = generateEd25519KeyPair()
const baseUrl = normalizeBaseUrl(DEFAULT_BASE_URL)
const payload = {
schemaVersion: 1,
version: '9.9.9',
publishedAt: '2026-10-20T10:00:00.000Z',
notes: { zh: '契约自测', en: 'Contract self-test' },
platforms: {
'windows-x64': {
url: `${baseUrl}versions/9.9.9/YCode-9.9.9-Setup-x64.exe`,
size: 123,
sha256: 'a'.repeat(64)
}
}
}
const document = {
payload,
signature: signPayload(payload, keys.privatePem)
}
const raw = Buffer.from(`${JSON.stringify(document)}\n`, 'utf8')
const verified = backend.verifySignedManifest(raw, {
manifestUrl: `${baseUrl}latest.json`,
publicKeyPem: keys.publicPem
})
assert.equal(verified.payload.version, payload.version)
assert.equal(verified.asset.url, payload.platforms['windows-x64'].url)
const tampered = structuredClone(document)
tampered.payload.notes.en = 'tampered'
assert.throws(
() => backend.verifySignedManifest(Buffer.from(JSON.stringify(tampered), 'utf8'), {
manifestUrl: `${baseUrl}latest.json`,
publicKeyPem: keys.publicPem
}),
/签名验证失败/
)
console.log('Release manifest matches update_backend parser/signature/path policy.')
console.log('Repository public key is a valid Ed25519 SPKI PEM trust anchor.')
} finally {
await fsp.rm(temporary, { recursive: true, force: true })
}
}
main().catch((error) => {
console.error(error)
process.exitCode = 1
})