92 lines
5.6 KiB
JavaScript
92 lines
5.6 KiB
JavaScript
/** Read-only audit of already REA-exported WorkBuddy source; never reads the installed app. */
|
|
import fs from 'node:fs'
|
|
import crypto from 'node:crypto'
|
|
import path from 'node:path'
|
|
import { parse } from '@babel/parser'
|
|
|
|
const input = process.env.YCODE_EXPERT_AUDIT_INPUT || '.tmp/rea-runtime-scripts.json'
|
|
const bundle = JSON.parse(fs.readFileSync(input, 'utf8'))
|
|
const sha = text => crypto.createHash('sha256').update(text).digest('hex')
|
|
const modules = bundle.items.filter(item => typeof item.source?.artifact?.text === 'string')
|
|
for (const item of modules) {
|
|
if (sha(item.source.artifact.text) !== item.source.artifact.sha256) throw new Error(`REA text SHA mismatch: ${item.file_path}`)
|
|
}
|
|
const selected = modules.filter(item => /(?:contexts-|services-|runtime-|provider-|desktop-sdk-|main-content-core-|expert-|wb-input-add-|wb-Coc|adapters-)/.test(item.file_path))
|
|
const filter = process.argv[2]
|
|
const needle = process.argv[3]
|
|
const manifest = { source: input, evidenceId: bundle.evidence_id, version: 'WorkBuddy 5.8.2',
|
|
rootSha256: '035254bc76310ea46317433e4840602094543ef323d2d5c5aff7c131729de918',
|
|
verifiedModules: modules.length, offsetUnit: 'UTF-16 code units, end exclusive', modules: [], supplementary: [] }
|
|
for (const item of selected) {
|
|
const text = item.source.artifact.text
|
|
const basename = path.win32.basename(item.file_path)
|
|
if (filter && !basename.includes(filter)) continue
|
|
if (needle) {
|
|
const matches = [...text.matchAll(new RegExp(needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'))].slice(0, 16)
|
|
console.log(JSON.stringify({ basename, sha256: sha(text), matches: matches.map(match => ({ offset: match.index,
|
|
snippet: text.slice(Math.max(0, match.index - 180), match.index + 1300) })) }, null, 2))
|
|
continue
|
|
}
|
|
const ast = parse(text, { sourceType: 'module' })
|
|
const definitions = []
|
|
const visit = node => {
|
|
if (!node || typeof node !== 'object') return
|
|
let name
|
|
if (node.type === 'FunctionDeclaration' || node.type === 'ClassDeclaration') name = node.id?.name
|
|
if (node.type === 'VariableDeclarator') name = node.id?.name
|
|
if (node.type === 'AssignmentExpression') name = node.left?.name
|
|
if (node.type === 'ClassMethod' || node.type === 'ObjectMethod') name = node.key?.name
|
|
if (name && /expert/i.test(name)) definitions.push({ name, type: node.type, start: node.start, end: node.end,
|
|
sha256: sha(text.slice(node.start, node.end)) })
|
|
for (const [key, child] of Object.entries(node)) {
|
|
if (key === 'loc' || key === 'tokens' || key === 'comments') continue
|
|
if (Array.isArray(child)) child.forEach(visit)
|
|
else if (child && typeof child === 'object') visit(child)
|
|
}
|
|
}
|
|
visit(ast.program)
|
|
manifest.modules.push({ basename, filePath: item.file_path, sha256: sha(text), length: text.length,
|
|
imports: ast.program.body.filter(node => node.type === 'ImportDeclaration').map(node => ({
|
|
source: node.source.value, start: node.start, end: node.end,
|
|
bindings: node.specifiers.map(specifier => ({ local: specifier.local.name,
|
|
imported: specifier.imported?.name ?? specifier.type }))
|
|
})), definitions })
|
|
}
|
|
if (!needle) {
|
|
for (const file of ['.tmp/rea-experts-main-evidence.json', '.tmp/rea-experts-host-evidence.json']) {
|
|
if (!fs.existsSync(file)) continue
|
|
const evidence = JSON.parse(fs.readFileSync(file, 'utf8'))
|
|
if (evidence.normalized_result?.root_sha256 !== manifest.rootSha256) throw new Error(`Root pin mismatch: ${file}`)
|
|
const files = evidence.normalized_result.files.map(item => {
|
|
if (sha(item.text) !== item.sha256) throw new Error(`REA supplementary SHA mismatch: ${item.path}`)
|
|
return { path: item.path, sha256: item.sha256, length: item.text.length }
|
|
})
|
|
manifest.supplementary.push({ file, evidenceId: evidence.evidence_id, files })
|
|
}
|
|
const currentPath = '.tmp/rea-expert-runtime-scripts-20261016.json'
|
|
if (fs.existsSync(currentPath)) {
|
|
const current = JSON.parse(fs.readFileSync(currentPath, 'utf8'))
|
|
for (const item of current.items) {
|
|
if (sha(item.source.artifact.text) !== item.source.artifact.sha256) throw new Error(`Current REA SHA mismatch: ${item.file_path}`)
|
|
}
|
|
manifest.supplementary.push({ file: currentPath, evidenceId: current.evidence_id, verifiedModules: current.items.length })
|
|
}
|
|
const cssPath = '.tmp/rea-css-recovered/contexts-BkjwYSZT.css'
|
|
const cssManifest = JSON.parse(fs.readFileSync('.tmp/rea-css-recovered/manifest.json', 'utf8'))
|
|
const css = cssManifest.files.find(file => file.file === path.basename(cssPath))
|
|
if (!css || sha(fs.readFileSync(cssPath)) !== css.sha256) throw new Error('REA expert CSS SHA mismatch')
|
|
manifest.supplementary.push({ file: cssPath, evidenceId: cssManifest.sourceEvidenceId, sha256: css.sha256 })
|
|
const layoutPath = '.tmp/rea-expert-entry-static-20261016/layout.json'
|
|
if (fs.existsSync(layoutPath)) {
|
|
const layout = JSON.parse(fs.readFileSync(layoutPath, 'utf8'))
|
|
const imagePath = path.join(path.dirname(layoutPath), 'workbuddy.png')
|
|
if (sha(fs.readFileSync(imagePath)) !== layout.artifact.sha256) throw new Error('REA expert screenshot SHA mismatch')
|
|
manifest.supplementary.push({ file: layoutPath, evidenceId: layout.evidenceId, viewport: layout.viewport,
|
|
imageSha256: layout.artifact.sha256 })
|
|
}
|
|
fs.writeFileSync(process.env.YCODE_EXPERT_AUDIT_OUTPUT || '.tmp/experts-source-audit.json', JSON.stringify(manifest, null, 2))
|
|
console.log(JSON.stringify({ evidenceId: manifest.evidenceId, verifiedModules: modules.length,
|
|
indexedExpertDefinitions: manifest.modules.reduce((total, module) => total + module.definitions.length, 0),
|
|
astModules: manifest.modules.length, supplementaryRecords: manifest.supplementary.length }))
|
|
}
|