build(site): [SITE-07] bind console licenses to verified component sources

This commit is contained in:
Harvey Zhao committed 2026-09-15 08:27:40 +08:00
1 parent 4bef084328
commit fb1faffbe9
20 files changed
+343 -28

No files matched your search

+18 -8
View File
@@ -120,12 +120,12 @@ site builds continue using the frozen verified vendor boundary.
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.
or infer it covers every embedded/external component. Embedded and external
components have their own source records and notices described below.
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. The final ESM and Parcel texts live in
Git attributes. They are source evidence tied to the generated notice inventory.
The final ESM and Parcel texts live in
`refactor/baselines/site-vendor/console-esm/`. React-inspector 5.1.1's ESM member
is an exact match after historical conversion; its CJS member was a failed
candidate. Styled-components 5.3.3 omits LICENSE in npm; the supplemental original
@@ -133,7 +133,7 @@ comes from fixed upstream commit 9b3457036cfedf1d5336f654f3171657630a9fd8.
The fetch command verifies that immutable upstream text through GitHub's Contents
API too (the raw URL had connection resets); both URLs and the blob ID are
recorded, and decoded content must match the same hash. Offline mode checks
the frozen bytes. Full embedded-component attribution remains open.
the frozen bytes. The consolidated review is in `refactor/console-notice-review.md`.
## Public notice delivery and embedded sources
@@ -205,6 +205,16 @@ member. Callback/context support and other changes prevent an exact-source claim
the public attribution explains that boundary and retains both authors' notices.
There are now 47 console notice outputs for 44 components. This includes a
CC BY-SA snippet; never describe the bundle as MIT-only. Final embedded-source
and mixed-license distribution review remains open. Exact Parcel module
reproduction alone is insufficient to close VENDOR-08.
CC BY-SA snippet; never describe the bundle as MIT-only. The identified source
and notice inventory is reviewed with the scope in `refactor/console-notice-review.md`.
The original complete lockfile and online Closure service have not been recovered.
The reproduction command's `licenseClosure: false` means that technical byte
comparison alone makes no license-clearance claim; the documented review also
considers component identity, embedded attribution and actual delivery.
`notices.ts` binds the 44 delivered components to 46 upstream notice/source files
from the independent provenance records. The 47th output is the local modification
explanation for react-pure-render. Both normal notice commands verify this relation
before writing: retaining all files while redirecting a BSD component to another
component's MIT notice is rejected. Re-review changed source or integration boundaries,
then revalidate the release candidate; this scope does not replace release reviews.
+63
View File
@@ -0,0 +1,63 @@
import type { VendorManifest } from '../notices.ts'
import assert from 'node:assert/strict'
import fs from 'node:fs'
import path from 'node:path'
interface Notice { source: string, sha256: string }
interface Archive { name: string, version: string, tarball: string, notices: Notice[] }
interface Remote extends Notice { id: string, url: string }
// Bind delivered component notices to independently verified source records.
// The normal site build does not download or execute the historical compilers.
export function verifyConsoleNoticeSources(root: string, manifest: VendorManifest): { components: number, upstreamNotices: number } {
const read = <T>(name: string): T => JSON.parse(fs.readFileSync(path.join(root, `refactor/baselines/${name}.json`), 'utf8')) as T
const feed = read<{ archive: Archive, notice: Notice }>('console-feed-provenance')
const common = read<{ archives: Archive[] }>('console-commonjs-provenance')
const esm = read<{ archives: Archive[], parcel: { archive: Archive, notices: Notice[] }, supplementalNotices: Notice[] }>('console-esm-provenance')
const embedded = read<{ archives: Archive[] }>('console-embedded-sources')
const headers = read<{ notices: Notice[] }>('console-embedded-notices')
const derived = read<{ archives: Archive[], remotes: Remote[], hash: { notice: Notice }, shallow: { license: string } }>('console-derived-attribution')
const stack = read<{ apiUrl: string, notices: Notice[] }>('console-stackoverflow-provenance')
const group = manifest.groups.find(group => group.name === 'console')
assert(group?.components, 'Missing console component inventory')
const visited = new Set<string>()
const matchedNotices = new Set<string>()
const verify = (identity: { name: string, tarball?: string }, expected: Notice[]): void => {
const matches = group.components!.filter(component => component.name === identity.name && (!identity.tarball || component.tarball === identity.tarball))
assert.equal(matches.length, 1, 'Expected one component for verified console source')
const component = matches[0]!
assert(!visited.has(component.name), 'Duplicate console source coverage')
assert(expected.length, `Missing source license: ${component.name}`)
for (const notice of expected) {
const delivered: (Notice & { target: string })[] = group.notices.filter(item => item.source === notice.source && item.sha256 === notice.sha256)
assert.equal(delivered.length, 1, `Console source notice not delivered: ${component.name}`)
assert(component.notices.includes(delivered[0]!.target), `Console component points to the wrong notice: ${component.name}`)
matchedNotices.add(delivered[0]!.target)
}
visited.add(component.name)
}
verify(feed.archive, [feed.notice])
for (const archive of [...common.archives, ...esm.archives, ...embedded.archives, ...derived.archives]) {
const name = archive.name === '@babel/runtime' && archive.version === '7.13.10'
? '@babel/runtime (react-inspector embedded)'
: archive.name === 'replicator'
? 'replicator (console-feed fork)'
: archive.name === 'stylis' ? 'stylis (Emotion fork)' : archive.name
verify({ name, tarball: archive.tarball }, archive.name === 'styled-components' ? esm.supplementalNotices : archive.notices)
}
verify(esm.parcel.archive, esm.parcel.notices)
assert.equal(headers.notices.length, 2, 'Unexpected embedded header scope')
verify({ name: 'chromium-string-utils' }, [headers.notices[0]!])
verify({ name: 'stylis-rule-sheet' }, [headers.notices[1]!])
const hashLicense = derived.remotes.find(source => source.id === 'gary-readme')
assert(hashLicense, 'Missing MurmurHash license source')
verify({ name: 'murmurhash-js (Gary Court)' }, [hashLicense])
verify({ name: 'murmurhash2 (Austin Appleby)' }, [derived.hash.notice])
verify({ name: 'stackoverflow-custom-stringify', tarball: stack.apiUrl }, stack.notices)
const pureLicense = derived.remotes.find(source => source.id === derived.shallow.license)
assert(pureLicense, 'Missing react-pure-render license source')
verify({ name: 'react-pure-render (shallowequal origin)' }, [pureLicense])
assert.equal(visited.size, 44, 'Incomplete reviewed console source scope')
assert.deepEqual([...visited].sort(), group.components.map(component => component.name).sort(), 'Unreviewed console component')
return { components: visited.size, upstreamNotices: matchedNotices.size }
}