chore: establish YCode replication baseline and TODO
This commit is contained in:
commit
6dc59f89ba
1118 files changed
+196002
No files matched your search
@@ -0,0 +1,154 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { createHash } from 'node:crypto'
|
||||
import fs from 'node:fs/promises'
|
||||
import os from 'node:os'
|
||||
import path from 'node:path'
|
||||
import { createRequire } from 'node:module'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
|
||||
const runtimeRoot = path.resolve(process.env.REA_RUNTIME_ROOT || '.tmp/rea-css-runtime')
|
||||
process.env.REA_RUNTIME_ROOT = runtimeRoot
|
||||
|
||||
const requireFromRuntime = createRequire(path.join(runtimeRoot, 'package.json'))
|
||||
const asarModule = await import(pathToFileURL(requireFromRuntime.resolve('@electron/asar')).href)
|
||||
const { createPackageWithOptions, getRawHeader, statFile } = asarModule
|
||||
const { exportSelectedArtifactText } = await import(
|
||||
pathToFileURL(path.resolve('scripts/rea/patches/SelectedArtifactText.js')).href,
|
||||
)
|
||||
|
||||
const digest = (bytes) => createHash('sha256').update(bytes).digest('hex')
|
||||
const archiveSha256 = async (archivePath) => digest(await fs.readFile(archivePath))
|
||||
const asarPath = (relativePath) => path.join(...relativePath.split('/'))
|
||||
const temporaryRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'rea-selected-text-'))
|
||||
|
||||
async function makeArchive(label, files, options = {}) {
|
||||
const source = path.join(temporaryRoot, `${label}-source`)
|
||||
const archivePath = path.join(temporaryRoot, `${label}.asar`)
|
||||
for (const [relativePath, contents] of Object.entries(files)) {
|
||||
const filePath = path.join(source, ...relativePath.split('/'))
|
||||
await fs.mkdir(path.dirname(filePath), { recursive: true })
|
||||
await fs.writeFile(filePath, contents)
|
||||
}
|
||||
await createPackageWithOptions(source, archivePath, options)
|
||||
return archivePath
|
||||
}
|
||||
|
||||
async function expectRejected(operation, pattern) {
|
||||
await assert.rejects(operation, pattern)
|
||||
}
|
||||
|
||||
try {
|
||||
const binaryBytes = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10, 255, 0, 128])
|
||||
const fontBytes = Buffer.from([0, 1, 0, 0, 0, 1, 128, 0, 0, 0, 255, 0])
|
||||
const binaryArchive = await makeArchive('selected-binary', { 'renderer/robot.png': binaryBytes, 'renderer/codicon.ttf': fontBytes, 'renderer/other.png': Buffer.from('UNSELECTED') })
|
||||
const binaryRootSha = await archiveSha256(binaryArchive)
|
||||
const binary = await exportSelectedArtifactText(binaryArchive, binaryRootSha, ['renderer/robot.png'], true)
|
||||
assert.equal(binary.operation, 'export_selected_asar_artifact_binary')
|
||||
assert.equal(binary.normalized_result.files.length, 1)
|
||||
assert.deepEqual(Buffer.from(binary.normalized_result.files[0].data_base64, 'base64'), binaryBytes)
|
||||
assert.equal(binary.normalized_result.files[0].sha256, digest(binaryBytes))
|
||||
const font = await exportSelectedArtifactText(binaryArchive, binaryRootSha, ['renderer/codicon.ttf'], true)
|
||||
assert.deepEqual(Buffer.from(font.normalized_result.files[0].data_base64, 'base64'), fontBytes)
|
||||
assert.equal(font.normalized_result.files[0].sha256, digest(fontBytes))
|
||||
await expectRejected(() => exportSelectedArtifactText(binaryArchive, binaryRootSha, ['renderer/codicon.ttf']), /must name/)
|
||||
await expectRejected(() => exportSelectedArtifactText(binaryArchive, binaryRootSha, ['renderer/robot.png']), /must name/)
|
||||
await expectRejected(() => exportSelectedArtifactText(binaryArchive, binaryRootSha, ['../renderer/robot.png'], true), /not canonical/)
|
||||
await expectRejected(() => exportSelectedArtifactText(binaryArchive, binaryRootSha, ['renderer/secret.db'], true), /supported image or font/)
|
||||
const selectedPath = 'renderer/assets/selected.js'
|
||||
const selectedText = 'export const selected = "ok";\n'
|
||||
const archivePath = await makeArchive(
|
||||
'missing-unpacked',
|
||||
{
|
||||
[selectedPath]: selectedText,
|
||||
'renderer/assets/missing.js': 'export const absent = true;\n',
|
||||
'renderer/assets/theme.css': '.fixture { color: red; }\n',
|
||||
},
|
||||
{ unpack: '**/missing.js' },
|
||||
)
|
||||
const missingMetadata = statFile(archivePath, asarPath('renderer/assets/missing.js'))
|
||||
assert.equal(missingMetadata.unpacked, true, 'fixture member should be marked unpacked')
|
||||
const missingCompanion = path.join(
|
||||
`${archivePath}.unpacked`,
|
||||
'renderer',
|
||||
'assets',
|
||||
'missing.js',
|
||||
)
|
||||
await fs.rm(missingCompanion)
|
||||
|
||||
const rootSha256 = await archiveSha256(archivePath)
|
||||
const evidence = await exportSelectedArtifactText(archivePath, rootSha256, [selectedPath])
|
||||
assert.equal(evidence.authority, 'shipped-artifact')
|
||||
assert.equal(evidence.subject.digest.sha256, rootSha256)
|
||||
assert.equal(evidence.normalized_result.root_sha256, rootSha256)
|
||||
assert.deepEqual(evidence.normalized_result.scope.selected_paths, [selectedPath])
|
||||
assert.match(evidence.normalized_result.scope.unselected_members, /availability are unknown/u)
|
||||
assert.deepEqual(evidence.normalized_result.files.map((file) => file.path), [selectedPath])
|
||||
assert.equal(evidence.normalized_result.files[0].text, selectedText)
|
||||
|
||||
await expectRejected(
|
||||
() => exportSelectedArtifactText(archivePath, '0'.repeat(64), [selectedPath]),
|
||||
/changed before interpretation/u,
|
||||
)
|
||||
await expectRejected(
|
||||
() => exportSelectedArtifactText(archivePath, rootSha256, ['../renderer/assets/selected.js']),
|
||||
/not canonical/u,
|
||||
)
|
||||
await expectRejected(
|
||||
() => exportSelectedArtifactText(archivePath, rootSha256, ['renderer\\assets\\selected.js']),
|
||||
/not canonical/u,
|
||||
)
|
||||
await expectRejected(
|
||||
() => exportSelectedArtifactText(archivePath, rootSha256, ['renderer/assets/missing.db']),
|
||||
/must name a supported UTF-8 text file/u,
|
||||
)
|
||||
|
||||
const hashMismatchArchive = path.join(temporaryRoot, 'hash-mismatch.asar')
|
||||
await fs.copyFile(archivePath, hashMismatchArchive)
|
||||
const packedEntry = statFile(hashMismatchArchive, asarPath(selectedPath))
|
||||
const header = getRawHeader(hashMismatchArchive)
|
||||
const payloadOffset = 8 + header.headerSize + Number(packedEntry.offset)
|
||||
const handle = await fs.open(hashMismatchArchive, 'r+')
|
||||
try {
|
||||
await handle.write(Buffer.from('x'), 0, 1, payloadOffset)
|
||||
} finally {
|
||||
await handle.close()
|
||||
}
|
||||
await expectRejected(
|
||||
async () => exportSelectedArtifactText(hashMismatchArchive, await archiveSha256(hashMismatchArchive), [selectedPath]),
|
||||
/SHA-256 mismatch/u,
|
||||
)
|
||||
|
||||
const perFileBudgetArchive = await makeArchive('per-file-budget', {
|
||||
'renderer/assets/large.js': Buffer.alloc(8 * 1024 * 1024 + 1, 0x61),
|
||||
})
|
||||
await expectRejected(
|
||||
async () => exportSelectedArtifactText(perFileBudgetArchive, await archiveSha256(perFileBudgetArchive), ['renderer/assets/large.js']),
|
||||
/per-file budget/u,
|
||||
)
|
||||
|
||||
const aggregateBudgetArchive = await makeArchive('aggregate-budget', {
|
||||
'renderer/assets/one.js': Buffer.alloc(8 * 1024 * 1024, 0x61),
|
||||
'renderer/assets/two.js': Buffer.alloc(8 * 1024 * 1024, 0x62),
|
||||
'renderer/assets/three.js': Buffer.from('x'),
|
||||
})
|
||||
await expectRejected(
|
||||
async () => exportSelectedArtifactText(
|
||||
aggregateBudgetArchive,
|
||||
await archiveSha256(aggregateBudgetArchive),
|
||||
['renderer/assets/one.js', 'renderer/assets/two.js', 'renderer/assets/three.js'],
|
||||
),
|
||||
/aggregate budget/u,
|
||||
)
|
||||
|
||||
const invalidUtf8Archive = await makeArchive('invalid-utf8', {
|
||||
'renderer/assets/invalid.json': Buffer.from([0xc3, 0x28]),
|
||||
})
|
||||
await expectRejected(
|
||||
async () => exportSelectedArtifactText(invalidUtf8Archive, await archiveSha256(invalidUtf8Archive), ['renderer/assets/invalid.json']),
|
||||
/strict UTF-8/u,
|
||||
)
|
||||
|
||||
console.log('Selected artifact text regression passed: root pinning, exact canonical selection, bounded strict UTF-8 reads, declared SHA verification, and ignored missing unselected unpacked members.')
|
||||
} finally {
|
||||
await fs.rm(temporaryRoot, { recursive: true, force: true })
|
||||
}
|
||||
Reference in new issue
Block a user