| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- import assert from 'node:assert/strict'
- import fs from 'node:fs'
- import zlib from 'node:zlib'
- /** Read regular package files without extracting an untrusted archive. */
- export function packageFiles(filename) {
- const data = zlib.gunzipSync(fs.readFileSync(filename), { maxOutputLength: 64 * 1024 * 1024 })
- const files = new Map()
- const names = new Set()
- let offset = 0, pending
- while (offset + 512 <= data.length) {
- const header = data.subarray(offset, offset + 512)
- if (header.every(byte => byte === 0)) break
- const field = (start, size) => header.toString('utf8', start, start + size).replace(/\0[\s\S]*$/, '')
- const size = parseInt(field(124, 12), 8) || 0
- assert.ok(Number.isSafeInteger(size) && size >= 0 && offset + 512 + size <= data.length, 'Invalid tar entry size')
- const type = field(156, 1)
- const body = data.subarray(offset + 512, offset + 512 + size)
- if (type === 'x') {
- const pax = body.toString('utf8')
- assert.ok(!/\blinkpath=/.test(pax), 'Package links are forbidden')
- pending = /(?:^|\n)\d+ path=([^\n]*)\n/.exec(pax)?.[1]
- } else if (type === 'L') pending = body.toString('utf8').replace(/\0[\s\S]*$/, '')
- else {
- assert.ok(['', '0', '5'].includes(type), `Package entry type is not permitted: ${type}`)
- const prefix = field(345, 155)
- const name = pending ?? (prefix ? `${prefix}/${field(0, 100)}` : field(0, 100))
- pending = undefined
- assert.ok(name.startsWith('package/') && !name.includes('\\') && !name.includes(':') && !name.split('/').some(part => part === '..' || part === '.'), `Unsafe package entry: ${name}`)
- if (type !== '5') {
- const relative = name.slice(8)
- assert.ok(relative && !names.has(relative.toLowerCase()), `Duplicate package entry: ${name}`)
- names.add(relative.toLowerCase())
- files.set(relative, body)
- }
- }
- offset += 512 + Math.ceil(size / 512) * 512
- }
- assert.ok(files.size, 'Empty package')
- return files
- }
- export function checkPublishableManifest(manifest) {
- assert.notEqual(manifest.private, true, 'Release packages must not be private')
- assert.equal(manifest.publishConfig?.access, 'public')
- assert.equal(manifest.publishConfig?.tag, 'preview')
- assert.equal(manifest.publishConfig?.registry, 'https://registry.npmjs.org/')
- for (const hook of ['preinstall', 'install', 'postinstall', 'prepare', 'prepublishOnly', 'prepack', 'postpack', 'publish', 'postpublish']) {
- assert.equal(manifest.scripts?.[hook], undefined, `Release packages must not run ${hook}`)
- }
- for (const [name, version] of Object.entries({ ...manifest.dependencies, ...manifest.optionalDependencies, ...manifest.peerDependencies })) {
- assert.ok(!name.startsWith('@webnovel/') && !/^(workspace:|file:|link:)/.test(version), 'Unpublished runtime dependency')
- }
- }
- export function checkEmbeddingPackage(filename, expectedVersion) {
- const files = packageFiles(filename)
- const read = file => { assert.ok(files.has(file), `Missing ${file}`); return files.get(file).toString('utf8') }
- const manifest = JSON.parse(read('package.json'))
- assert.equal(manifest.name, 'webnovel-embedding-provider')
- assert.equal(manifest.version, expectedVersion)
- assert.equal(manifest.license, 'GPL-3.0-only')
- checkPublishableManifest(manifest)
- assert.ok(read('LICENSE').includes('GNU GENERAL PUBLIC LICENSE'))
- assert.ok(read('THIRD_PARTY_NOTICES.md').includes('Original notices'))
- for (const name of ['lib/index.js', 'lib/client.js', 'cordis.patch.yml', 'README.md', 'MODEL_DIMENSIONS.md']) read(name)
- assert.ok(read('lib/client.js').startsWith(`window.__ModuleLoader__.load({ id: ${JSON.stringify(manifest.name)},`), 'Embedding client identity must match its installed package name')
- for (const [file, data] of files) {
- assert.match(file, /^(package\.json|LICENSE|THIRD_PARTY_NOTICES\.md|README\.md|MODEL_DIMENSIONS\.md|cordis\.patch\.yml|lib\/(index|client)\.js|licenses\/[^/]+\.txt)$/)
- assert.ok(!/-----BEGIN [A-Z ]*PRIVATE KEY-----|sk-[A-Za-z0-9_-]{30,}/.test(data.toString('utf8')), `Possible credential in ${file}`)
- }
- for (const [name, version] of Object.entries({ ...manifest.dependencies, ...manifest.peerDependencies })) {
- assert.ok(!name.startsWith('@webnovel/') && !/^(workspace:|file:|link:)/.test(version), 'Unpublished runtime dependency')
- }
- return { ok: true, files: files.size, version: manifest.version }
- }
- export function checkMetaPackage(filename, expectedVersion, embeddingVersion) {
- const files = packageFiles(filename)
- const read = name => { assert.ok(files.has(name), `Missing ${name}`); return files.get(name).toString('utf8') }
- const manifest = JSON.parse(read('package.json'))
- assert.equal(manifest.name, '@linfengqaqtat/dsh-scriptor-full')
- assert.equal(manifest.version, expectedVersion)
- assert.equal(manifest.license, 'GPL-3.0-only')
- checkPublishableManifest(manifest)
- assert.deepEqual(manifest.dependencies, {
- '@linfengqaqtat/dsh-scriptor': expectedVersion,
- 'webnovel-embedding-provider': embeddingVersion,
- })
- assert.equal(manifest.dsh?.bundle?.patch, './cordis.patch.yml')
- assert.equal(read('cordis.patch.yml').replaceAll('\r\n', '\n').trim(),
- "- insert:\n - id: webnovel\n name: '@linfengqaqtat/dsh-scriptor'\n - id: webnovel-embeddings\n name: webnovel-embedding-provider")
- assert.ok(read('LICENSE').includes('GNU GENERAL PUBLIC LICENSE'))
- read('README.md')
- for (const file of files.keys()) assert.match(file, /^(package\.json|LICENSE|README\.md|RELEASE_NOTES\.md|cordis\.patch\.yml)$/)
- return { ok: true, files: files.size, version: manifest.version }
- }
|