feat: publish av-tools 0.1.0

This commit is contained in:
2026-07-24 14:58:03 +02:00
commit fcc537b024
254 changed files with 63270 additions and 0 deletions

View File

@@ -0,0 +1,251 @@
import {
mkdtemp,
mkdir,
readFile,
rm,
symlink,
writeFile,
} from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { afterEach, describe, expect, it } from 'vitest';
import {
assertLicenseReady,
collectDirectoryEntries,
createDeterministicZip,
parseReleaseArguments,
safeArchivePath,
} from '../../scripts/package-release.mjs';
import {
checksumLine,
parseChecksumLine,
sha256,
verifyChecksum,
writeChecksum,
} from '../../scripts/checksum-release.mjs';
import {
inspectPortalHeaders,
parsePortalArguments,
} from '../../scripts/portal-assembly-smoke.mjs';
const temporaryDirectories = [];
async function temporaryDirectory() {
const directory = await mkdtemp(
path.join(tmpdir(), 'av-tools-release-test-')
);
temporaryDirectories.push(directory);
return directory;
}
afterEach(async () => {
await Promise.all(
temporaryDirectories
.splice(0)
.map((directory) => rm(directory, { force: true, recursive: true }))
);
});
describe('release path safety', () => {
it.each([
'',
'/index.html',
'../index.html',
'assets/../index.html',
'assets//main.js',
'C:/index.html',
'assets\\main.js',
'assets/\0main.js',
])('rejects unsafe archive path %j', (unsafePath) => {
expect(() => safeArchivePath(unsafePath)).toThrow();
});
it('accepts a canonical nested path', () => {
expect(safeArchivePath('vendor/ffmpeg/core.wasm')).toBe(
'vendor/ffmpeg/core.wasm'
);
});
it('rejects symlinks while collecting a directory', async () => {
const directory = await temporaryDirectory();
await writeFile(path.join(directory, 'target.txt'), 'target');
await symlink('target.txt', path.join(directory, 'alias.txt'));
await expect(collectDirectoryEntries(directory)).rejects.toThrow(
/symlink/i
);
});
});
describe('deterministic release ZIP', () => {
const entries = [
{ name: 'z.txt', data: Buffer.from('last') },
{ name: 'a.txt', data: Buffer.from('first') },
];
it('is byte-identical regardless of input order', () => {
const first = createDeterministicZip(entries);
const second = createDeterministicZip([...entries].reverse());
expect(first.equals(second)).toBe(true);
expect(sha256(first)).toMatch(/^[a-f0-9]{64}$/);
});
it('stores sorted UTF-8 entries with the normalized epoch and file mode', () => {
const archive = createDeterministicZip(entries);
expect(archive.readUInt32LE(0)).toBe(0x04034b50);
expect(archive.readUInt16LE(10)).toBe(0);
expect(archive.readUInt16LE(12)).toBe(33);
expect(archive.subarray(30, 35).toString('utf8')).toBe('a.txt');
const centralOffset = archive.indexOf(
Buffer.from([0x50, 0x4b, 0x01, 0x02])
);
expect(centralOffset).toBeGreaterThan(0);
expect(archive.readUInt16LE(centralOffset + 4)).toBe(0x0314);
expect(archive.readUInt32LE(centralOffset + 38) >>> 16).toBe(0o100644);
});
it('rejects duplicate paths and local absolute paths in text', () => {
expect(() =>
createDeterministicZip([
{ name: 'same.txt', data: Buffer.from('one') },
{ name: 'same.txt', data: Buffer.from('two') },
])
).toThrow(/duplicate/i);
expect(() =>
createDeterministicZip([
{ name: 'bundle.js', data: Buffer.from('source: "/home/user/file"') },
])
).toThrow(/local absolute path/i);
});
});
describe('licence release gate', () => {
it('blocks a normal release without an application licence', async () => {
const directory = await temporaryDirectory();
await expect(assertLicenseReady(directory)).rejects.toThrow(
/RELEASE BLOCKED/
);
});
it('allows only the explicit development-smoke escape hatch', async () => {
const directory = await temporaryDirectory();
await expect(assertLicenseReady(directory, true)).resolves.toBeNull();
expect(
parseReleaseArguments(['--allow-unlicensed-development-smoke'])
).toEqual({
allowUnlicensedDevelopmentSmoke: true,
force: false,
});
expect(() => parseReleaseArguments(['--publish'])).toThrow(/unknown/i);
});
it('recognizes a complete GPL version 3 root application licence', async () => {
const directory = await temporaryDirectory();
const licence = path.join(directory, 'LICENSE');
await writeFile(
licence,
[
'GNU GENERAL PUBLIC LICENSE',
'Version 3, 29 June 2007',
'END OF TERMS AND CONDITIONS',
].join('\n')
);
await expect(assertLicenseReady(directory)).resolves.toBe(licence);
});
it('rejects an arbitrary file named LICENSE', async () => {
const directory = await temporaryDirectory();
await writeFile(path.join(directory, 'LICENSE'), 'example only');
await expect(assertLicenseReady(directory)).rejects.toThrow(
/complete GNU GPL version 3/i
);
});
});
describe('release checksum', () => {
it('formats and parses the portable sidecar form', () => {
const digest = 'a'.repeat(64);
const line = checksumLine(digest, 'av-tools-0.1.0.zip');
expect(line).toBe(`${digest} av-tools-0.1.0.zip\n`);
expect(parseChecksumLine(line)).toEqual({
archiveName: 'av-tools-0.1.0.zip',
digest,
});
});
it('writes and verifies a checksum sidecar', async () => {
const directory = await temporaryDirectory();
const archive = path.join(directory, 'av-tools-0.1.0.zip');
await writeFile(archive, 'deterministic bytes');
const result = await writeChecksum(archive);
expect(await verifyChecksum(archive, result.sidecarPath)).toBe(
result.digest
);
expect(await readFile(result.sidecarPath, 'utf8')).toContain(
' av-tools-0.1.0.zip'
);
});
it('rejects checksum mismatches', async () => {
const directory = await temporaryDirectory();
const archive = path.join(directory, 'av-tools-0.1.0.zip');
const sidecar = `${archive}.sha256`;
await writeFile(archive, 'changed');
await mkdir(path.dirname(sidecar), { recursive: true });
await writeFile(
sidecar,
checksumLine('0'.repeat(64), path.basename(archive))
);
await expect(verifyChecksum(archive, sidecar)).rejects.toThrow(/mismatch/i);
});
});
describe('portal assembly smoke validation', () => {
const isolatedHeaders = `
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Embedder-Policy "require-corp" always;
add_header Cross-Origin-Resource-Policy "same-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self' blob:; media-src 'self' blob:;" always;
types { application/wasm wasm; }
# vendor/ffmpeg/0.12.10
`;
it('accepts the required isolation, CSP and MIME profile', () => {
expect(inspectPortalHeaders(isolatedHeaders)).toEqual({
errors: [],
warnings: [],
});
});
it('detects the current media-preview CSP gap', () => {
const inspection = inspectPortalHeaders(
isolatedHeaders.replace("media-src 'self' blob:;", '')
);
expect(inspection.errors).toContain(
"CSP media-src must contain 'self' and blob:"
);
});
it('parses only explicit smoke overrides and paths', () => {
const parsed = parsePortalArguments(
[
'--artifact',
'release/example.zip',
'--allow-unlicensed-development-smoke',
'--allow-known-header-gap',
'--keep-temp',
],
'/work/av-tools'
);
expect(parsed).toEqual({
allowKnownHeaderGap: true,
allowUnlicensedDevelopmentSmoke: true,
artifact: '/work/av-tools/release/example.zip',
keepTemp: true,
portalRoot: '/work/references/toolbox-portal',
});
expect(() => parsePortalArguments(['--publish'], '/work/av-tools')).toThrow(
/unknown/i
);
});
});