mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-15 17:16:16 -08:00
build(site): [SITE-07] checkpoint frozen vendor notices and open lifecycle evidence
This commit is contained in:
1 parent
72d2b9c36b
commit
838c3eb432
23 files changed
+3964
-17
No files matched your search
@@ -0,0 +1,29 @@
|
||||
import fs from 'node:fs'
|
||||
import { expect, test } from './fixtures.js'
|
||||
|
||||
test('mobile vConsole shows logs and upstream site notice texts are served unchanged', async ({ page, request }, testInfo) => {
|
||||
await page.route('https://**/*', route => route.fulfill({ status: 200, body: '' }))
|
||||
const code = 'window.art = new Artplayer({container:".artplayer-app",url:"/test/pattern.mp4",muted:true}); console.log("site-vendor-verified-message");'
|
||||
await page.goto(`/mobile.html?code=${encodeURIComponent(code)}`)
|
||||
await page.waitForFunction(() => window.art?.isReady && window.vConsole)
|
||||
await page.locator('.art-control-playAndPause').click()
|
||||
await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(0.2)
|
||||
await page.locator('#__vconsole .vc-switch').click()
|
||||
await expect(page.locator('#__vconsole').getByText('site-vendor-verified-message', { exact: true })).toBeVisible()
|
||||
const manifest = JSON.parse(fs.readFileSync('scripts/site-vendor/manifest.json', 'utf8'))
|
||||
const notices = []
|
||||
for (const group of manifest.groups) {
|
||||
for (const notice of group.notices) {
|
||||
const response = await request.get(`/${notice.target.slice('docs/'.length)}`)
|
||||
expect(response.status()).toBe(200)
|
||||
expect(await response.body()).toEqual(fs.readFileSync(notice.source))
|
||||
notices.push({ component: group.name, version: group.version, url: response.url(), sha256: notice.sha256 })
|
||||
}
|
||||
}
|
||||
await testInfo.attach('verified-vendor-notices', { contentType: 'application/json', body: JSON.stringify(notices) })
|
||||
await page.evaluate(() => {
|
||||
window.vConsole.destroy()
|
||||
window.art.destroy()
|
||||
})
|
||||
await expect(page.locator('#__vconsole')).toHaveCount(0)
|
||||
})
|
||||
@@ -0,0 +1,58 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { createHash } from 'node:crypto'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
// eslint-disable-next-line test/no-import-node-test -- Verify real notice bytes and failure-before-write behavior.
|
||||
import test from 'node:test'
|
||||
import { generateNotices, writeOrCheckNotices } from '../scripts/site-vendor/notices.ts'
|
||||
|
||||
const hash = bytes => createHash('sha256').update(bytes).digest('hex')
|
||||
function fixture(t) {
|
||||
const root = fs.mkdtempSync(path.resolve('refactor/.cache/site-notices-test-'))
|
||||
t.after(() => {
|
||||
assert.equal(path.dirname(root), path.resolve('refactor/.cache'))
|
||||
assert(path.basename(root).startsWith('site-notices-test-'))
|
||||
fs.rmSync(root, { recursive: true, force: true })
|
||||
})
|
||||
fs.mkdirSync(path.join(root, 'assets'))
|
||||
fs.writeFileSync(path.join(root, 'assets/code.js'), 'line\r\n')
|
||||
fs.writeFileSync(path.join(root, 'LICENSE'), 'Copyright\nPermission\n\n')
|
||||
const manifest = { schemaVersion: 1, scope: 'Fixture only', groups: [{ name: 'fixture', version: '1.0.0', tarball: 'https://example.org/fixed.tgz', roots: ['assets'], files: [{ path: 'assets/code.js', sha256: hash('line\n'), mode: 'lf-text' }], notices: [{ source: 'LICENSE', target: 'docs/licenses/fixture/LICENSE', sha256: hash('Copyright\nPermission\n\n') }] }] }
|
||||
return { root, manifest }
|
||||
}
|
||||
|
||||
test('Site notices retain the complete upstream bytes including trailing lines; check is read-only', (t) => {
|
||||
const { root, manifest } = fixture(t)
|
||||
assert.equal(writeOrCheckNotices(root, manifest, false), 2)
|
||||
assert.deepEqual(fs.readFileSync(path.join(root, 'docs/licenses/fixture/LICENSE')), fs.readFileSync(path.join(root, 'LICENSE')))
|
||||
assert.equal(writeOrCheckNotices(root, manifest, true), 2)
|
||||
fs.writeFileSync(path.join(root, 'docs/licenses/fixture/LICENSE'), 'edited')
|
||||
assert.throws(() => writeOrCheckNotices(root, manifest, true), /notice drift/)
|
||||
assert.equal(fs.readFileSync(path.join(root, 'docs/licenses/fixture/LICENSE'), 'utf8'), 'edited')
|
||||
})
|
||||
|
||||
test('Site notices reject missing/new/modified assets and altered license before writing', (t) => {
|
||||
const { root, manifest } = fixture(t)
|
||||
fs.writeFileSync(path.join(root, 'assets/new.js'), 'new')
|
||||
assert.throws(() => writeOrCheckNotices(root, manifest, false), /inventory drift/)
|
||||
assert(!fs.existsSync(path.join(root, 'docs')))
|
||||
fs.unlinkSync(path.join(root, 'assets/new.js'))
|
||||
fs.writeFileSync(path.join(root, 'assets/code.js'), 'different')
|
||||
assert.throws(() => generateNotices(root, manifest), /bytes changed/)
|
||||
fs.writeFileSync(path.join(root, 'assets/code.js'), 'line\n')
|
||||
fs.writeFileSync(path.join(root, 'LICENSE'), 'shortened')
|
||||
assert.throws(() => generateNotices(root, manifest), /notice changed/)
|
||||
fs.unlinkSync(path.join(root, 'assets/code.js'))
|
||||
assert.throws(() => generateNotices(root, manifest), /inventory drift/)
|
||||
})
|
||||
|
||||
test('Site notice paths cannot escape or silently omit the component license', (t) => {
|
||||
const { root, manifest } = fixture(t)
|
||||
for (const target of ['../escape', '/absolute', 'docs/licenses/other/LICENSE']) {
|
||||
const changed = structuredClone(manifest)
|
||||
changed.groups[0].notices[0].target = target
|
||||
assert.throws(() => generateNotices(root, changed))
|
||||
}
|
||||
manifest.groups[0].notices = []
|
||||
assert.throws(() => generateNotices(root, manifest), /Missing upstream/)
|
||||
})
|
||||
Reference in new issue
Block a user