feat: ship skill and MCP workflows with signed updater for v0.0.7
This commit is contained in:
1 parent
1b52df0603
commit
a01085c656
136 files changed
+18646
-217
No files matched your search
@@ -0,0 +1,84 @@
|
||||
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
|
||||
})
|
||||
Reference in new issue
Block a user