46 lines
2.1 KiB
JavaScript
46 lines
2.1 KiB
JavaScript
import path from 'node:path';
|
|
import { REQUIRED_COVERAGE_UNITS } from './wp7-05-ui-gate.mjs';
|
|
|
|
const ABSOLUTE_PATH = /^(?:[A-Za-z]:[\\/]|[\\/]{2}|\\\\)/;
|
|
|
|
function assertSafeRelative(value, field) {
|
|
if (typeof value !== 'string' || !value || ABSOLUTE_PATH.test(value) || path.isAbsolute(value)) {
|
|
throw new Error(`WP7_05_UNSAFE_${field}`);
|
|
}
|
|
const normalized = value.replaceAll('\\', '/');
|
|
if (normalized.split('/').includes('..')) throw new Error(`WP7_05_UNSAFE_${field}`);
|
|
return normalized;
|
|
}
|
|
|
|
export function buildCoverageEvidence({ runId, candidateSha256, coverageUnits, viewports }) {
|
|
if (!runId || !/^[A-Za-z0-9._-]+$/.test(runId)) throw new Error('WP7_05_INVALID_RUN_ID');
|
|
if (!/^[A-Fa-f0-9]{64}$/.test(candidateSha256 ?? '')) throw new Error('WP7_05_INVALID_CANDIDATE_HASH');
|
|
if (!Array.isArray(coverageUnits)) throw new Error('WP7_05_COVERAGE_UNITS_REQUIRED');
|
|
|
|
const byPage = new Map();
|
|
for (const unit of coverageUnits) {
|
|
if (!REQUIRED_COVERAGE_UNITS.includes(unit.page_id)) throw new Error('WP7_05_UNKNOWN_PAGE');
|
|
if (byPage.has(unit.page_id)) throw new Error('WP7_05_DUPLICATE_PAGE');
|
|
if (!Array.isArray(unit.states) || unit.states.length === 0) throw new Error('WP7_05_STATES_REQUIRED');
|
|
const states = unit.states.map((state) => ({
|
|
state: assertSafeRelative(state.state, 'STATE'),
|
|
screenshot_100pct: assertSafeRelative(state.screenshot_100pct, 'SCREENSHOT'),
|
|
screenshot_200pct: assertSafeRelative(state.screenshot_200pct, 'SCREENSHOT'),
|
|
trace: assertSafeRelative(state.trace, 'TRACE'),
|
|
}));
|
|
byPage.set(unit.page_id, { page_id: unit.page_id, states });
|
|
}
|
|
const missing = REQUIRED_COVERAGE_UNITS.filter((page) => !byPage.has(page));
|
|
if (missing.length) throw new Error(`WP7_05_MISSING_PAGES:${missing.join(',')}`);
|
|
if (!Array.isArray(viewports) || viewports.length !== 2) throw new Error('WP7_05_VIEWPORTS_REQUIRED');
|
|
|
|
return {
|
|
schema_version: '1.0',
|
|
task: 'TASK-WP7-05',
|
|
run_id: runId,
|
|
candidate_sha256: candidateSha256.toUpperCase(),
|
|
viewports,
|
|
coverage_units: REQUIRED_COVERAGE_UNITS.map((page) => byPage.get(page)),
|
|
};
|
|
}
|