build(site): [SITE-07] reproduce 41 more console vendor modules

This commit is contained in:
Harvey Zhao committed 2026-09-15 06:40:29 +08:00
1 parent b47ede011a
commit ba1dbd430f
26 files changed
+1163 -24

No files matched your search

+19 -5
View File
@@ -72,8 +72,11 @@ remain SITE-07 / VENDOR-08; this build does not close them. See
`refactor/baselines/console-feed-provenance.json` maps all 32 modules reachable
through relative imports from m6b6 to the official console-feed 3.2.2 archive.
Their rebuilt bodies exactly match the frozen bundle. The 68 remaining vendor
modules and Parcel wrapper need further provenance; this does not establish a
Their rebuilt bodies exactly match the frozen bundle. The separate
`console-commonjs-provenance.json` adds 41 exact modules from 13 official archives:
React/ReactDOM, scheduler, object-assign, react-is, prop-types, shallowequal,
process, hoist-non-react-statics, is-dom/is-object/is-window and linkifyjs.
The 27 remaining vendor modules and Parcel wrapper need further provenance; this does not establish a
unique original installed version or recover its missing lockfile.
```sh
@@ -82,19 +85,30 @@ node scripts/site-vendor/console/reproduce.ts
yarn test:site-console
```
The first command downloads two pinned npm archives into the dedicated ignored
The first command downloads 15 pinned npm archives into the dedicated ignored
`refactor/.cache/console-feed-reproduction/` directory. The second uses that cache
offline. Both verify SHA-512 SRI, archive SHA-256, source member fingerprints,
compiler bytes and exact output. They load Terser 3.17.0 as a historical build
compiler bytes, original notice bytes and exact output of all 73 identified
modules. They load Terser 3.17.0 as a historical build
tool with the already installed source-map 0.6.1; they do not install dependencies,
change Yarn or execute the archived console-feed runtime. Canonical Node is required.
The minification recipe is recovered from Parcel 1.12.5's archive; this proves a
reproducing transform, not that the original author used precisely that Parcel
version. `provenance.ts` separately verifies complete traversal, relative source
mapping and external dependency boundaries. Missing, unreachable, duplicate or
changed evidence fails instead of silently shrinking the comparison.
changed evidence fails instead of silently shrinking the comparison. Multiple
package roots are explicit, relative edges must stay in the same archive, and
the remaining module IDs are checked as a complete list. Production entrypoints
use the pinned-source process.env.NODE_ENV substitution. The process shim's
single process.browser assignment is removed following Parcel's original visitor;
this is checked against exact source/output bytes, not a general JS rewrite.
The archived LICENSE is preserved verbatim with its Facebook attribution under
`refactor/baselines/site-vendor/console-feed-3.2.2-LICENSE.txt`. Do not rewrite it
or infer it covers every embedded/external component. Complete notices remain
open, including the bundled replicator and remaining dependencies.
The other 13 archives' LICENSE texts are also frozen under
`refactor/baselines/site-vendor/console-commonjs/`, with exact bytes preserved by
Git attributes. They are source evidence; complete site notice delivery still
requires the remaining component review. React-inspector 5.1.1's CJS file did
not match; its ESM conversion remains an investigation, not an accepted source.
+8 -6
View File
@@ -4,7 +4,7 @@ import path from 'node:path'
import ts from 'typescript'
export interface Module { id: string, body: string, dependencies: Record<string, string> }
export interface Source { id: string, member: string, sourceSha256: string, generatedSha256: string, bodySha256: string }
export interface Source { id: string, member: string, sourceSha256: string, generatedSha256: string, bodySha256: string, archive?: string }
export interface External { from: string, dependency: string, id: string }
export interface Archive { name: string, version: string, tarball: string, integrity: string, sha256: string }
export const hash = (bytes: string | Uint8Array) => createHash('sha256').update(bytes).digest('hex')
@@ -46,7 +46,7 @@ export function parcelModules(text: string): Map<string, Module> {
return result
}
export function verifyModules(modules: Map<string, Module>, sources: Source[], external: External[], read: (member: string) => string, compile: (source: string) => string) {
export function verifyModules<S extends Source>(modules: Map<string, Module>, sources: S[], external: External[], read: (member: string, item: S) => string, compile: (source: string, item: S) => string, options = { roots: ['m6b6'], sourcePrefix: 'package/lib/' }) {
const mapped = new Map(sources.map(source => [source.id, source]))
assert.equal(mapped.size, sources.length, 'Duplicate source mapping')
const visited = new Set<string>()
@@ -57,11 +57,11 @@ export function verifyModules(modules: Map<string, Module>, sources: Source[], e
const item = mapped.get(id)
const module = modules.get(id)
assert(item && module, `Missing console-feed module mapping: ${id}`)
assert(item.member.startsWith('package/lib/') && item.member.endsWith('.js') && path.posix.normalize(item.member) === item.member, 'Invalid source member')
assert(item.member.startsWith(options.sourcePrefix) && item.member.endsWith('.js') && path.posix.normalize(item.member) === item.member, 'Invalid source member')
visited.add(id)
const source = read(item.member)
const source = read(item.member, item)
assert.equal(hash(source), item.sourceSha256, `Source changed: ${item.member}`)
const compiled = compile(source)
const compiled = compile(source, item)
assert.equal(hash(compiled), item.generatedSha256, `Compiler output changed: ${id}`)
assert.equal(hash(module.body), item.bodySha256, `Frozen module changed: ${id}`)
assert.equal(compiled, module.body, `Rebuilt module differs: ${id}`)
@@ -74,10 +74,12 @@ export function verifyModules(modules: Map<string, Module>, sources: Source[], e
const base = path.posix.join(path.posix.dirname(item.member), dependency)
const target = mapped.get(child)?.member
assert(target && [base, `${base}.js`, `${base}/index.js`].includes(target), `Source dependency mapping changed: ${id} ${dependency}`)
assert.equal(item.archive, mapped.get(child)?.archive, `Relative dependency changed archives: ${id} ${dependency}`)
visit(child)
}
}
visit('m6b6')
assert(options.roots.length && new Set(options.roots).size === options.roots.length, 'Invalid source roots')
options.roots.forEach(visit)
assert.equal(visited.size, sources.length, 'Unreachable source mapping')
assert.deepEqual(dependencies, external, 'External dependency boundary changed')
return visited.size
+49 -6
View File
@@ -8,7 +8,7 @@ import process from 'node:process'
import { fileURLToPath } from 'node:url'
import { hash, parcelModules, verifyArchive, verifyModules } from './provenance.ts'
interface CompilerOptions { warnings: boolean, safari10: boolean, mangle: { toplevel: boolean } }
interface CompilerOptions { warnings: boolean, safari10: boolean, mangle: { toplevel: boolean }, output?: { comments: boolean } }
interface Provenance {
archive: Archive
frozen: { path: string, sha256: string }
@@ -17,16 +17,26 @@ interface Provenance {
external: External[]
}
interface Minifier { minify: (source: string, options: CompilerOptions) => { code?: string, error?: unknown } }
interface CommonSource extends Source { archive: string, transform: 'plain' | 'production' | 'process-browser' }
interface CommonProvenance {
archives: (Archive & { id: string, notices: { source: string, member: string, sha256: string }[] })[]
sources: CommonSource[]
external: External[]
roots: string[]
compilerOptions: CompilerOptions
unresolvedModules: string[]
}
const root = fileURLToPath(new URL('../../../', import.meta.url))
const record: Provenance = JSON.parse(fs.readFileSync(path.join(root, 'refactor/baselines/console-feed-provenance.json'), 'utf8'))
const common: CommonProvenance = JSON.parse(fs.readFileSync(path.join(root, 'refactor/baselines/console-commonjs-provenance.json'), 'utf8'))
assert(process.argv.slice(2).every(arg => arg === '--fetch'), 'Use reproduce.ts [--fetch]')
assert.equal(process.version, `v${fs.readFileSync(path.join(root, '.node-version'), 'utf8').trim()}`, 'Use canonical Node')
const cacheRoot = fs.realpathSync(path.join(root, 'refactor/.cache'))
const cache = path.join(cacheRoot, 'console-feed-reproduction')
fs.mkdirSync(cache, { recursive: true })
assert.equal(fs.realpathSync(cache), cache, 'Reproduction cache must not redirect')
for (const archive of [record.archive, record.compiler.archive]) {
for (const archive of [record.archive, record.compiler.archive, ...common.archives]) {
const target = path.join(cache, `${archive.name}-${archive.version}.tgz`)
if (process.argv.includes('--fetch')) {
const response = await fetch(archive.tarball)
@@ -50,11 +60,44 @@ const { minify } = require(compilerPath) as Minifier
const frozen = fs.readFileSync(path.join(root, record.frozen.path), 'utf8')
assert.equal(hash(frozen), record.frozen.sha256, 'Frozen console changed')
assert.equal(record.sources.length, 32, 'Incomplete console-feed scope')
const count = verifyModules(parcelModules(frozen), record.sources, record.external, member => readMember('console-feed-3.2.2.tgz', member).toString('utf8'), (source) => {
const result = minify(source, record.compiler.options)
function compile(source: string, options: CompilerOptions) {
const result = minify(source, options)
if (result.error)
throw result.error
assert(typeof result.code === 'string')
return result.code
})
console.log(JSON.stringify({ exactModules: count, totalVendorModules: 100, archive: record.archive.sha256, licenseClosure: false }))
}
const modules = parcelModules(frozen)
const count = verifyModules(modules, record.sources, record.external, member => readMember('console-feed-3.2.2.tgz', member).toString('utf8'), source => compile(source, record.compiler.options))
assert.equal(common.sources.length, 41, 'Incomplete commonjs scope')
const archiveIds = new Set(common.archives.map(archive => archive.id))
assert.equal(archiveIds.size, common.archives.length, 'Duplicate archives')
for (const archive of common.archives) {
assert.equal(archive.id, `${archive.name}-${archive.version}`, 'Archive ID differs')
for (const notice of archive.notices) {
const bytes = readMember(`${archive.id}.tgz`, notice.member)
assert.equal(hash(bytes), notice.sha256, 'Upstream notice differs')
assert.equal(hash(fs.readFileSync(path.join(root, notice.source))), notice.sha256, 'Frozen notice differs')
}
}
const commonCount = verifyModules(modules, common.sources, common.external, (member, item) => {
assert(archiveIds.has(item.archive), 'Unknown source archive')
return readMember(`${item.archive}.tgz`, member).toString('utf8')
}, (source, item) => {
if (item.transform === 'production') {
assert(source.includes('process.env.NODE_ENV'), 'Missing production substitution')
source = source.replaceAll('process.env.NODE_ENV', '"production"')
}
else if (item.transform === 'process-browser') {
assert.equal(source.split('process.browser = true;').length, 2, 'Unexpected process browser assignment')
source = source.replace('process.browser = true;', '')
}
else {
assert.equal(item.transform, 'plain', 'Unknown transform')
}
return compile(source, common.compilerOptions)
}, { roots: common.roots, sourcePrefix: 'package/' })
const identified = new Set([...record.sources, ...common.sources].map(source => source.id))
assert.equal(identified.size, count + commonCount, 'Duplicate identified module')
assert.deepEqual([...modules.keys()].filter(id => !identified.has(id) && !['Focm', 'W5CS'].includes(id)), common.unresolvedModules, 'Unresolved module scope changed')
console.log(JSON.stringify({ exactModules: identified.size, consoleFeed: count, commonjs: commonCount, totalVendorModules: 100, unresolved: common.unresolvedModules.length, licenseClosure: false }))