Files
ycode/scripts/rea/expert-package-text-regression.mjs

42 lines
3.5 KiB
JavaScript

/** Own ASAR fixture exercises the official local REA provider/public CLI only. */
import assert from 'node:assert/strict'
import fs from 'node:fs/promises'
import path from 'node:path'
import crypto from 'node:crypto'
import { createRequire } from 'node:module'
import { pathToFileURL } from 'node:url'
import { spawnSync } from 'node:child_process'
const root = await fs.mkdtemp(path.resolve('.tmp/rea-expert-package-fixture-'))
const requireRuntime = createRequire(path.resolve('.tmp/rea-css-runtime/package.json'))
const {createPackageWithOptions} = await import(pathToFileURL(requireRuntime.resolve('@electron/asar')).href)
const digest = bytes => crypto.createHash('sha256').update(bytes).digest('hex')
const source = path.join(root,'source'), archive = path.join(root,'fixture.asar')
const files = {'expert/SKILL.md':'---\nname: local-test\n---\n# 本地专家\n', 'expert/schema.yaml':'name: local-test\n',
'expert/schema.yml':'version: 1\n','expert/README.txt':'strict UTF-8\n', 'expert/register.py':'# retained, never executed\nprint("中文")\n', 'expert/bad.md':Buffer.from([0xc3,0x28]),
'expert/large.txt':Buffer.alloc(8*1024*1024+1,97),'expert/one.md':Buffer.alloc(8*1024*1024,97),
'expert/two.md':Buffer.alloc(8*1024*1024,98),'expert/extra.txt':'x','expert/unselected.md':'not selected'}
for(const [p,content] of Object.entries(files)){await fs.mkdir(path.dirname(path.join(source,p)),{recursive:true});await fs.writeFile(path.join(source,p),content)}
await createPackageWithOptions(source,archive,{unpackDir:'expert'})
await fs.rm(path.join(archive+'.unpacked','expert/unselected.md'))
const pin=digest(await fs.readFile(archive)), checks=[]
function cli(paths,expected=pin){return spawnSync(process.execPath,['.tmp/rea-css-runtime/scripts/rea.mjs','export-selected-artifact-text',archive,expected,JSON.stringify(paths)],{encoding:'utf8',maxBuffer:32*1024*1024})}
function reject(label,paths,pattern,expected=pin){const r=cli(paths,expected);assert.notEqual(r.status,0,label);assert.match(r.stderr,pattern,label);checks.push({label,pass:true})}
const selected=Object.keys(files).slice(0,5), r=cli(selected)
assert.equal(r.status,0,r.stderr)
const evidence=JSON.parse(r.stdout)
assert.equal(evidence.normalized_result.root_sha256,pin)
assert.deepEqual(evidence.normalized_result.files.map(f=>f.path),selected)
for(const f of evidence.normalized_result.files){assert.equal(f.text,files[f.path]);assert.equal(f.sha256,digest(files[f.path]));assert.equal(f.size_bytes,Buffer.byteLength(files[f.path]))}
checks.push({label:'five new suffixes, exact bytes/SHA/root and missing unselected unpacked ignored; Python not executed',pass:true})
reject('root mismatch',selected,/changed before interpretation/,'0'.repeat(64))
reject('canonical selection',['../expert/SKILL.md'],/not canonical/)
reject('unknown suffix',['expert/private.db'],/supported UTF-8/)
reject('strict UTF-8',['expert/bad.md'],/strict UTF-8/)
reject('per-file budget',['expert/large.txt'],/per-file budget/)
reject('aggregate budget',['expert/one.md','expert/two.md','expert/extra.txt'],/aggregate budget/)
reject('absent selected member',['expert/absent.md'],/absent from/)
reject('duplicate selected member',['expert/SKILL.md','expert/SKILL.md'],/Duplicate selected path/)
await fs.writeFile(path.join(root,'evidence.json'),JSON.stringify(evidence,null,2))
await fs.writeFile(path.join(root,'report.json'),JSON.stringify({result:'PASS',rootPin:pin,evidenceId:evidence.evidence_id,checks},null,2))
console.log(JSON.stringify({result:'PASS',root,checks:checks.length,evidenceId:evidence.evidence_id}))