68 lines
3.0 KiB
TypeScript
68 lines
3.0 KiB
TypeScript
import { generateKeyPairSync } from 'node:crypto';
|
|
import { describe, expect, it } from 'vitest';
|
|
import { aggregateFiveDriveTraces } from '../../scripts/lib/performance-aggregation.mjs';
|
|
import { signReferenceCandidate } from '../../scripts/lib/reference-evidence.mjs';
|
|
|
|
const trusted = generateKeyPairSync('ed25519');
|
|
const attacker = generateKeyPairSync('ed25519');
|
|
const policy = {
|
|
schema: 'portfolio-reference-trust-policy/v1',
|
|
keyId: 'lab-release-2026',
|
|
publicKeyPem: trusted.publicKey.export({ type: 'spki', format: 'pem' }).toString(),
|
|
};
|
|
|
|
const candidate = (lcp: number, tbt: number, runIndex: number) => ({
|
|
schema: 'drive-trace.v1',
|
|
evidenceKind: 'validated-reference-candidate-unsigned',
|
|
gatingReferenceResult: false,
|
|
referenceCandidateValidated: true,
|
|
profile: 'desktop-high',
|
|
tier: 'high',
|
|
referenceRun: { runId: `run-${runIndex}`, runIndex, attestationDigest: `${runIndex}`.repeat(64) },
|
|
validReferenceCadence: true,
|
|
referenceBudgetsPass: true,
|
|
metrics: { lcp, tbt },
|
|
budgetResults: { cls: true, scene: true, runtimeResources: true, requestConcurrency: true },
|
|
});
|
|
|
|
const signed = (lcp: number, tbt: number, runIndex: number) => signReferenceCandidate(
|
|
candidate(lcp, tbt, runIndex),
|
|
{ keyId: policy.keyId, privateKey: trusted.privateKey },
|
|
);
|
|
|
|
describe('five-run drive trace aggregation', () => {
|
|
it('uses worst and median gates across exactly five trusted signed runs', () => {
|
|
expect(aggregateFiveDriveTraces([
|
|
signed(2_000, 100, 1), signed(2_100, 110, 2), signed(2_500, 200, 3), signed(2_900, 250, 4), signed(3_000, 300, 5),
|
|
], policy)).toMatchObject({
|
|
runCount: 5,
|
|
passes: true,
|
|
summary: { lcpWorst: 3_000, lcpMedian: 2_500, tbtWorst: 300, tbtMedian: 200 },
|
|
});
|
|
});
|
|
|
|
it('rejects unsigned developer reports and wrong run counts', () => {
|
|
expect(() => aggregateFiveDriveTraces([
|
|
candidate(2_000, 100, 1), signed(2_000, 100, 2), signed(2_000, 100, 3), signed(2_000, 100, 4), signed(2_000, 100, 5),
|
|
], policy)).toThrow(/signature/u);
|
|
expect(() => aggregateFiveDriveTraces([signed(2_000, 100, 1)], policy)).toThrow(/five/u);
|
|
});
|
|
|
|
it('rejects self-selected keys, tampered measurements, and duplicate replay', () => {
|
|
const selfSigned = signReferenceCandidate(candidate(2_000, 100, 1), { keyId: policy.keyId, privateKey: attacker.privateKey });
|
|
expect(() => aggregateFiveDriveTraces([
|
|
selfSigned, signed(2_000, 100, 2), signed(2_000, 100, 3), signed(2_000, 100, 4), signed(2_000, 100, 5),
|
|
], policy)).toThrow(/signature/u);
|
|
|
|
const tampered = { ...signed(2_000, 100, 1), metrics: { lcp: 1, tbt: 1 } };
|
|
expect(() => aggregateFiveDriveTraces([
|
|
tampered, signed(2_000, 100, 2), signed(2_000, 100, 3), signed(2_000, 100, 4), signed(2_000, 100, 5),
|
|
], policy)).toThrow(/digest|signature/u);
|
|
|
|
const replay = signed(2_000, 100, 4);
|
|
expect(() => aggregateFiveDriveTraces([
|
|
signed(2_000, 100, 1), signed(2_000, 100, 2), signed(2_000, 100, 3), replay, replay,
|
|
], policy)).toThrow(/run indexes 1 through 5|duplicate/u);
|
|
});
|
|
});
|