const fs = require('fs'); const os = require('os'); const path = require('path'); const test = require('node:test'); const assert = require('node:assert/strict'); const handler = require('./query-regression-comment.cjs'); const { collectReportRows, renderSummaryTable, admissionMac, verifyAdmissionMac, formatAdmissionMarker, parseAdmissionMarker, } = handler._test; const HMAC_SECRET = 'test-admission-hmac'; function report(name, measurements, thresholds = []) { return { case: { name }, status: 'ok', targets: [ { measurements: measurements.base }, { measurements: measurements.candidate }, ], thresholds, }; } function markerComment(identity, { id = 1, secret = HMAC_SECRET } = {}) { const payload = { ...identity, mac: admissionMac(secret, identity) }; return { id, body: formatAdmissionMarker(payload) }; } function githubApi({ identity, pull, comments }) { return { rest: { issues: { listComments: async () => ({ data: comments ?? [markerComment(identity)] }), }, pulls: { get: async () => ({ data: pull ?? { state: 'open', base: { repo: { full_name: identity.base_repo } }, head: { repo: { full_name: identity.head_repo }, sha: identity.head_sha }, }, }), }, }, }; } test('keeps the default export callable and exposes only the test seam', () => { assert.equal(typeof handler, 'function'); assert.equal(handler.constructor.name, 'AsyncFunction'); assert.deepEqual(Object.keys(handler._test).sort(), [ 'admissionMac', 'collectReportRows', 'formatAdmissionMarker', 'parseAdmissionMarker', 'renderSummaryTable', 'verifyAdmissionMac', ]); }); test('renders every case in one summary table without per-case separators', () => { const rows = [ ...collectReportRows(report('first', { base: [{ name: 'q1', latency_ms_median: 10 }], candidate: [{ name: 'q1', latency_ms_median: 11 }], }), '/reports/first/query-regression-report.json'), ...collectReportRows(report('second', { base: [{ name: 'q2', latency_ms_median: 20 }], candidate: [{ name: 'q2', latency_ms_median: 18 }], }), '/reports/second/query-regression-report.json'), ]; const table = renderSummaryTable(rows); assert.equal((table.match(/^\| Case \| Query \| Case status \|/gm) || []).length, 1); assert.match(table, /\| first \| q1 \|/); assert.match(table, /\| second \| q2 \|/); assert.doesNotMatch(table, /^### /m); assert.doesNotMatch(table, /^---$/m); }); test('renders failed reports as N/A rows with their error', () => { const rows = collectReportRows({ case: { name: 'broken' }, status: 'failed', error: 'connection refused', }, '/reports/broken/query-regression-report.json'); assert.deepEqual(rows, [{ caseName: 'broken', query: 'N/A', status: 'failed', baseMedian: 'N/A', candidateMedian: 'N/A', regression: 'N/A', threshold: 'error: connection refused', }]); }); test('reports missing targets and empty measurements', () => { const missingTargets = collectReportRows({ case: { name: 'missing' }, status: 'failed' }, '/reports/missing/report.json'); const emptyMeasurements = collectReportRows(report('empty', { base: [], candidate: [] }), '/reports/empty/report.json'); assert.equal(missingTargets[0].threshold, 'base/candidate measurements missing'); assert.equal(emptyMeasurements[0].threshold, 'no query measurements found'); }); test('renders null, array, and primitive reports as invalid report rows', () => { for (const invalidReport of [null, [], 'not an object']) { assert.deepEqual( collectReportRows(invalidReport, '/reports/fallback/query-regression-report.json'), [{ caseName: 'fallback', query: 'N/A', status: 'missing', baseMedian: 'N/A', candidateMedian: 'N/A', regression: 'N/A', threshold: 'invalid report object', }] ); } }); test('rejects null medians and diagnoses missing asymmetric measurements', () => { const rows = collectReportRows(report('missing-values', { base: [ { name: 'null-median', latency_ms_median: null }, { name: 'base-only', latency_ms_median: 10 }, { name: 'candidate-null', latency_ms_median: 20 }, ], candidate: [ { name: 'null-median', latency_ms_median: 20 }, { name: 'candidate-null', latency_ms_median: null }, { name: 'candidate-only', latency_ms_median: 30 }, ], }), '/reports/missing-values/query-regression-report.json'); const byQuery = new Map(rows.map(row => [row.query, row])); assert.equal(byQuery.get('null-median').baseMedian, 'N/A'); assert.equal(byQuery.get('null-median').candidateMedian, '20.00'); assert.equal(byQuery.get('null-median').regression, 'N/A'); assert.equal(byQuery.get('null-median').threshold, 'base measurement missing'); assert.equal(byQuery.get('base-only').threshold, 'candidate measurement missing'); assert.equal(byQuery.get('candidate-null').candidateMedian, 'N/A'); assert.equal(byQuery.get('candidate-null').regression, 'N/A'); assert.equal(byQuery.get('candidate-null').threshold, 'candidate measurement missing'); assert.equal(byQuery.get('candidate-only').threshold, 'base measurement missing'); }); test('rejects empty, blank, NaN, and infinite medians', () => { const rows = collectReportRows(report('invalid-values', { base: [ { name: 'empty-base', latency_ms_median: '' }, { name: 'blank-base', latency_ms_median: ' ' }, { name: 'nan-candidate', latency_ms_median: 10 }, { name: 'infinite-candidate', latency_ms_median: 10 }, ], candidate: [ { name: 'empty-base', latency_ms_median: 10 }, { name: 'blank-base', latency_ms_median: 10 }, { name: 'nan-candidate', latency_ms_median: Number.NaN }, { name: 'infinite-candidate', latency_ms_median: Number.POSITIVE_INFINITY }, ], }), '/reports/invalid-values/query-regression-report.json'); const byQuery = new Map(rows.map(row => [row.query, row])); for (const query of ['empty-base', 'blank-base', 'nan-candidate', 'infinite-candidate']) { assert.equal(byQuery.get(query).regression, 'N/A'); } assert.equal(byQuery.get('empty-base').baseMedian, 'N/A'); assert.equal(byQuery.get('blank-base').baseMedian, 'N/A'); assert.equal(byQuery.get('nan-candidate').candidateMedian, 'N/A'); assert.equal(byQuery.get('infinite-candidate').candidateMedian, 'N/A'); }); test('rejects boolean, array, and object median coercions', () => { const rows = collectReportRows(report('invalid-types', { base: [ { name: 'boolean-base', latency_ms_median: true }, { name: 'array-base', latency_ms_median: [] }, { name: 'object-base', latency_ms_median: {} }, { name: 'boolean-candidate', latency_ms_median: 10 }, { name: 'array-candidate', latency_ms_median: 10 }, { name: 'object-candidate', latency_ms_median: 10 }, ], candidate: [ { name: 'boolean-base', latency_ms_median: 10 }, { name: 'array-base', latency_ms_median: 10 }, { name: 'object-base', latency_ms_median: 10 }, { name: 'boolean-candidate', latency_ms_median: false }, { name: 'array-candidate', latency_ms_median: [] }, { name: 'object-candidate', latency_ms_median: {} }, ], }), '/reports/invalid-types/query-regression-report.json'); for (const row of rows) { assert.equal(row.regression, 'N/A'); } assert.equal(rows.find(row => row.query === 'boolean-base').baseMedian, 'N/A'); assert.equal(rows.find(row => row.query === 'array-base').baseMedian, 'N/A'); assert.equal(rows.find(row => row.query === 'object-base').baseMedian, 'N/A'); assert.equal(rows.find(row => row.query === 'boolean-candidate').candidateMedian, 'N/A'); assert.equal(rows.find(row => row.query === 'array-candidate').candidateMedian, 'N/A'); assert.equal(rows.find(row => row.query === 'object-candidate').candidateMedian, 'N/A'); }); test('sorts the base and candidate query union and aggregates scoped thresholds', () => { const rows = collectReportRows(report('union', { base: [{ name: 'z', latency_ms_median: 10 }], candidate: [{ name: 'a', latency_ms_median: 20 }], }, [ { query: 'z', threshold: 'p95', target: 'base', status: 'warn' }, { query: 'z', threshold: 'absolute', target: 'candidate', encoding: 'plain', status: 'pass' }, ]), '/reports/union/query-regression-report.json'); assert.deepEqual(rows.map(row => row.query), ['a', 'z']); assert.equal(rows[0].baseMedian, 'N/A'); assert.equal(rows[0].candidateMedian, '20.00'); assert.equal(rows[0].threshold, 'base measurement missing'); assert.equal( rows[1].threshold, 'candidate measurement missing; p95 [target=base]: warn; absolute [target=candidate, encoding=plain]: pass' ); }); test('keeps unscoped and unmatched thresholds in a case-thresholds detail row', () => { const rows = collectReportRows(report('thresholds', { base: [{ name: 'measured', latency_ms_median: 10 }], candidate: [{ name: 'measured', latency_ms_median: 11 }], }, [ { query: 'measured', threshold: 'query limit', target: 'base', status: 'passed' }, { threshold: 'min_files', target: 'base', status: 'passed' }, { threshold: 'min_files', target: 'candidate', status: 'failed' }, { threshold: 'encoding limit', target: 'candidate', encoding: 'plain', status: 'failed' }, { query: 'not-measured', threshold: 'orphaned limit', target: 'base', encoding: 'json', status: 'failed', reason: 'measurement unavailable', }, ]), '/reports/thresholds/query-regression-report.json'); assert.equal(rows.length, 2); assert.equal(rows[0].query, 'measured'); assert.equal(rows[0].threshold, 'query limit [target=base]: passed'); assert.equal(rows[1].query, 'N/A'); assert.equal(rows[1].kind, 'case-thresholds'); assert.equal( rows[1].threshold, 'min_files [target=base]: passed; min_files [target=candidate]: failed; encoding limit [target=candidate, encoding=plain]: failed; unmatched query not-measured: orphaned limit [target=base, encoding=json]: failed (reason: measurement unavailable)' ); }); test('keeps unscoped thresholds out of undefined and null query rows', () => { const rows = collectReportRows(report('collisions', { base: [ { name: 'undefined', latency_ms_median: 10 }, { name: 'null', latency_ms_median: 10 }, ], candidate: [ { name: 'undefined', latency_ms_median: 11 }, { name: 'null', latency_ms_median: 11 }, ], }, [ { threshold: 'min_files', target: 'base', status: 'passed' }, { query: null, threshold: 'min_files', target: 'candidate', status: 'failed' }, ]), '/reports/collisions/query-regression-report.json'); const byQuery = new Map(rows.map(row => [row.query, row])); assert.equal(byQuery.get('undefined').threshold, 'N/A'); assert.equal(byQuery.get('null').threshold, 'N/A'); assert.equal(rows.filter(row => row.query === 'N/A').length, 1); assert.equal(byQuery.get('N/A').kind, 'case-thresholds'); assert.equal( byQuery.get('N/A').threshold, 'min_files [target=base]: passed; min_files [target=candidate]: failed' ); }); test('renders case/storage thresholds in a collapsible details block below the table', () => { const rows = [ ...collectReportRows(report('first', { base: [{ name: 'q1', latency_ms_median: 10 }], candidate: [{ name: 'q1', latency_ms_median: 11 }], }, [ { query: 'q1', threshold: 'query limit', target: 'base', status: 'passed' }, { threshold: 'min_files', target: 'base', status: 'passed' }, { threshold: 'min_files', target: 'candidate', status: 'failed' }, ]), '/reports/first/query-regression-report.json'), ...collectReportRows({ case: { name: 'broken' }, status: 'failed', error: 'connection refused', }, '/reports/broken/query-regression-report.json'), ]; const rendered = renderSummaryTable(rows); const detailsIndex = rendered.indexOf('
'); const table = rendered.slice(0, detailsIndex); const details = rendered.slice(detailsIndex); // Query rows and abnormal N/A rows stay in the main table. assert.match(table, /\| first \| q1 \| ✅ ok \|/); assert.match(table, /\| broken \| N\/A \| ❌ failed \|/); // Storage thresholds are not main-table rows. assert.doesNotMatch(table, /^\| first \| N\/A \|/m); assert.doesNotMatch(table, /min_files/); // Status column is plain text without code-span backticks. assert.doesNotMatch(table, /`/); // Details block keeps its tags unescaped and its items '; '-separated. assert.ok(details.startsWith('
Case / storage thresholds')); assert.ok(details.includes('- first: min_files \\[target=base\\]: passed; min_files \\[target=candidate\\]: failed')); assert.ok(details.endsWith('
')); assert.ok(!rendered.includes('<details>')); }); test('escapes Markdown table content, including bare carriage returns', () => { const table = renderSummaryTable([{ caseName: 'safe\r| injected |\n@user ', query: 'query`|\n@team', status: 'failed', baseMedian: '1|2', candidateMedian: '3\n4', regression: '`@all', threshold: 'x|y\r\n`@here ', }]); assert.equal(table.split('\n').length, 3); assert.match(table, /safe \\\| injected \\\| @\u200buser <tag>/); assert.match(table, /query`\\\| @\u200bteam/); assert.match(table, /1\\\|2/); assert.match(table, /3 4/); assert.match(table, /`@\u200ball/); assert.match(table, /x\\\|y `@\u200bhere <html>/); assert.doesNotMatch(table, /hidden|comment|drop|\r/); }); test('posts a comment-command report without treating workflow_run as the PR head', async () => { const originalCwd = process.cwd(); const originalRunId = process.env.WORKFLOW_RUN_ID; const originalRunAttempt = process.env.WORKFLOW_RUN_ATTEMPT; const originalHmac = process.env.QUERY_REGRESSION_ADMISSION_HMAC; const temporaryDir = fs.mkdtempSync(path.join(os.tmpdir(), 'query-regression-comment-')); const artifactDir = path.join(temporaryDir, 'query-regression-comment'); const outputs = new Map(); try { fs.mkdirSync(artifactDir); const metadata = { run_id: 202, run_attempt: 1, base_repo: 'owner/repo', pr_number: 42, head_sha: 'pr-head-sha', head_repo: 'fork/repo', built_base_sha: 'base-sha', event_base_sha: 'event-base-sha', candidate_sha: 'merge-sha', base_sha: 'event-base-sha', }; fs.mkdirSync(path.join(temporaryDir, 'query-regression-admission')); fs.writeFileSync( path.join(temporaryDir, 'query-regression-admission', 'query-regression-admission.json'), JSON.stringify(metadata), ); fs.writeFileSync(path.join(artifactDir, 'query-regression-pr.json'), JSON.stringify(metadata)); process.chdir(temporaryDir); process.env.WORKFLOW_RUN_ID = '202'; process.env.WORKFLOW_RUN_ATTEMPT = '1'; process.env.QUERY_REGRESSION_ADMISSION_HMAC = HMAC_SECRET; await handler({ core: { info() {}, warning() {}, setOutput(name, value) { outputs.set(name, value); }, }, context: { repo: { owner: 'owner', repo: 'repo' }, payload: { workflow_run: { event: 'repository_dispatch', head_sha: 'default-branch-sha', head_repository: { full_name: 'owner/repo' }, pull_requests: [], }, }, }, github: githubApi({ identity: metadata }), }); assert.equal(outputs.get('should_post'), 'true'); assert.equal(outputs.get('pr_number'), '42'); } finally { process.chdir(originalCwd); if (originalRunId === undefined) delete process.env.WORKFLOW_RUN_ID; else process.env.WORKFLOW_RUN_ID = originalRunId; if (originalRunAttempt === undefined) delete process.env.WORKFLOW_RUN_ATTEMPT; else process.env.WORKFLOW_RUN_ATTEMPT = originalRunAttempt; if (originalHmac === undefined) delete process.env.QUERY_REGRESSION_ADMISSION_HMAC; else process.env.QUERY_REGRESSION_ADMISSION_HMAC = originalHmac; fs.rmSync(temporaryDir, { recursive: true, force: true }); } }); test('skips reports produced by a pull_request workflow_run', async () => { const originalCwd = process.cwd(); const originalRunId = process.env.WORKFLOW_RUN_ID; const originalRunAttempt = process.env.WORKFLOW_RUN_ATTEMPT; const temporaryDir = fs.mkdtempSync(path.join(os.tmpdir(), 'query-regression-comment-')); const artifactDir = path.join(temporaryDir, 'query-regression-comment'); const outputs = new Map(); const infos = []; try { fs.mkdirSync(artifactDir); const metadata = { run_id: 303, run_attempt: 1, base_repo: 'owner/repo', pr_number: 42, head_sha: 'head-sha', head_repo: 'fork/repo', built_base_sha: 'base-sha', event_base_sha: 'event-base-sha', candidate_sha: 'candidate-sha', base_sha: 'event-base-sha', }; fs.mkdirSync(path.join(temporaryDir, 'query-regression-admission')); fs.writeFileSync( path.join(temporaryDir, 'query-regression-admission', 'query-regression-admission.json'), JSON.stringify(metadata), ); fs.writeFileSync(path.join(artifactDir, 'query-regression-pr.json'), JSON.stringify(metadata)); process.chdir(temporaryDir); process.env.WORKFLOW_RUN_ID = '303'; process.env.WORKFLOW_RUN_ATTEMPT = '1'; await handler({ core: { info(message) { infos.push(message); }, warning() {}, setOutput(name, value) { outputs.set(name, value); }, }, context: { repo: { owner: 'owner', repo: 'repo' }, payload: { workflow_run: { event: 'pull_request', head_sha: 'head-sha', head_repository: { full_name: 'fork/repo' }, pull_requests: [{ number: 42 }], }, }, }, github: { rest: { pulls: { get: async () => { throw new Error('should not fetch PR'); } } } }, }); assert.equal(outputs.get('should_post'), 'false'); assert.match(infos.join('\n'), /not repository_dispatch/); } finally { process.chdir(originalCwd); if (originalRunId === undefined) delete process.env.WORKFLOW_RUN_ID; else process.env.WORKFLOW_RUN_ID = originalRunId; if (originalRunAttempt === undefined) delete process.env.WORKFLOW_RUN_ATTEMPT; else process.env.WORKFLOW_RUN_ATTEMPT = originalRunAttempt; fs.rmSync(temporaryDir, { recursive: true, force: true }); } }); test('writes the explicit no-report summary without an empty table', async () => { const originalCwd = process.cwd(); const originalRunId = process.env.WORKFLOW_RUN_ID; const originalRunAttempt = process.env.WORKFLOW_RUN_ATTEMPT; const originalHmac = process.env.QUERY_REGRESSION_ADMISSION_HMAC; const temporaryDir = fs.mkdtempSync(path.join(os.tmpdir(), 'query-regression-comment-')); const artifactDir = path.join(temporaryDir, 'query-regression-comment'); const outputs = new Map(); try { fs.mkdirSync(artifactDir); const metadata = { run_id: 101, run_attempt: 1, base_repo: 'owner/repo', pr_number: 42, head_sha: 'head-sha', head_repo: 'fork/repo', built_base_sha: 'base-sha', event_base_sha: 'event-base-sha', candidate_sha: 'candidate-sha', base_sha: 'event-base-sha', }; fs.mkdirSync(path.join(temporaryDir, 'query-regression-admission')); fs.writeFileSync( path.join(temporaryDir, 'query-regression-admission', 'query-regression-admission.json'), JSON.stringify(metadata), ); fs.writeFileSync(path.join(artifactDir, 'query-regression-pr.json'), JSON.stringify(metadata)); process.chdir(temporaryDir); process.env.WORKFLOW_RUN_ID = '101'; process.env.WORKFLOW_RUN_ATTEMPT = '1'; process.env.QUERY_REGRESSION_ADMISSION_HMAC = HMAC_SECRET; await handler({ core: { info() {}, warning() {}, setOutput(name, value) { outputs.set(name, value); }, }, context: { repo: { owner: 'owner', repo: 'repo' }, payload: { workflow_run: { event: 'repository_dispatch', head_sha: 'default-branch-sha', head_repository: { full_name: 'owner/repo' }, pull_requests: [], }, }, }, github: githubApi({ identity: metadata }), }); const summary = fs.readFileSync(path.join(artifactDir, 'query-regression-summary.md'), 'utf8'); assert.equal(outputs.get('should_post'), 'true'); assert.match(summary, /No query-regression JSON reports were found in the artifact\./); assert.doesNotMatch(summary, /\| Case \| Query \|/); } finally { process.chdir(originalCwd); if (originalRunId === undefined) delete process.env.WORKFLOW_RUN_ID; else process.env.WORKFLOW_RUN_ID = originalRunId; if (originalRunAttempt === undefined) delete process.env.WORKFLOW_RUN_ATTEMPT; else process.env.WORKFLOW_RUN_ATTEMPT = originalRunAttempt; if (originalHmac === undefined) delete process.env.QUERY_REGRESSION_ADMISSION_HMAC; else process.env.QUERY_REGRESSION_ADMISSION_HMAC = originalHmac; fs.rmSync(temporaryDir, { recursive: true, force: true }); } }); test('skips when the runner artifact forges a different PR number', async () => { const originalCwd = process.cwd(); const originalRunId = process.env.WORKFLOW_RUN_ID; const originalRunAttempt = process.env.WORKFLOW_RUN_ATTEMPT; const temporaryDir = fs.mkdtempSync(path.join(os.tmpdir(), 'query-regression-comment-')); const artifactDir = path.join(temporaryDir, 'query-regression-comment'); const outputs = new Map(); const infos = []; try { fs.mkdirSync(artifactDir); const admission = { run_id: 404, run_attempt: 1, base_repo: 'owner/repo', pr_number: 42, head_sha: 'head-sha', head_repo: 'fork/repo', candidate_sha: 'merge-sha', base_sha: 'base-sha', }; fs.mkdirSync(path.join(temporaryDir, 'query-regression-admission')); fs.writeFileSync( path.join(temporaryDir, 'query-regression-admission', 'query-regression-admission.json'), JSON.stringify(admission), ); fs.writeFileSync(path.join(artifactDir, 'query-regression-pr.json'), JSON.stringify({ ...admission, pr_number: 99, })); process.chdir(temporaryDir); process.env.WORKFLOW_RUN_ID = '404'; process.env.WORKFLOW_RUN_ATTEMPT = '1'; await handler({ core: { info(message) { infos.push(message); }, warning() {}, setOutput(name, value) { outputs.set(name, value); }, }, context: { repo: { owner: 'owner', repo: 'repo' }, payload: { workflow_run: { event: 'repository_dispatch', head_sha: 'default-branch-sha', head_repository: { full_name: 'owner/repo' }, pull_requests: [], }, }, }, github: { rest: { pulls: { get: async () => { throw new Error('should not fetch PR'); } } } }, }); assert.equal(outputs.get('should_post'), 'false'); assert.match(infos.join('\n'), /does not match admission artifact/); } finally { process.chdir(originalCwd); if (originalRunId === undefined) delete process.env.WORKFLOW_RUN_ID; else process.env.WORKFLOW_RUN_ID = originalRunId; if (originalRunAttempt === undefined) delete process.env.WORKFLOW_RUN_ATTEMPT; else process.env.WORKFLOW_RUN_ATTEMPT = originalRunAttempt; fs.rmSync(temporaryDir, { recursive: true, force: true }); } }); test('posts after Re-run failed jobs when admission stays on attempt 1', async () => { const originalCwd = process.cwd(); const originalRunId = process.env.WORKFLOW_RUN_ID; const originalRunAttempt = process.env.WORKFLOW_RUN_ATTEMPT; const originalHmac = process.env.QUERY_REGRESSION_ADMISSION_HMAC; const temporaryDir = fs.mkdtempSync(path.join(os.tmpdir(), 'query-regression-comment-')); const artifactDir = path.join(temporaryDir, 'query-regression-comment'); const outputs = new Map(); try { fs.mkdirSync(artifactDir); const admission = { run_id: 505, run_attempt: 1, base_repo: 'owner/repo', pr_number: 42, head_sha: 'pr-head-sha', head_repo: 'fork/repo', candidate_sha: 'merge-sha', base_sha: 'base-sha', }; const metadata = { ...admission, run_attempt: 2, built_base_sha: 'base-sha', event_base_sha: 'base-sha', }; fs.mkdirSync(path.join(temporaryDir, 'query-regression-admission')); fs.writeFileSync( path.join(temporaryDir, 'query-regression-admission', 'query-regression-admission.json'), JSON.stringify(admission), ); fs.writeFileSync(path.join(artifactDir, 'query-regression-pr.json'), JSON.stringify(metadata)); process.chdir(temporaryDir); process.env.WORKFLOW_RUN_ID = '505'; process.env.WORKFLOW_RUN_ATTEMPT = '2'; process.env.QUERY_REGRESSION_ADMISSION_HMAC = HMAC_SECRET; await handler({ core: { info() {}, warning() {}, setOutput(name, value) { outputs.set(name, value); }, }, context: { repo: { owner: 'owner', repo: 'repo' }, payload: { workflow_run: { event: 'repository_dispatch', head_sha: 'default-branch-sha', head_repository: { full_name: 'owner/repo' }, pull_requests: [], }, }, }, github: githubApi({ identity: admission }), }); assert.equal(outputs.get('should_post'), 'true'); assert.equal(outputs.get('pr_number'), '42'); } finally { process.chdir(originalCwd); if (originalRunId === undefined) delete process.env.WORKFLOW_RUN_ID; else process.env.WORKFLOW_RUN_ID = originalRunId; if (originalRunAttempt === undefined) delete process.env.WORKFLOW_RUN_ATTEMPT; else process.env.WORKFLOW_RUN_ATTEMPT = originalRunAttempt; if (originalHmac === undefined) delete process.env.QUERY_REGRESSION_ADMISSION_HMAC; else process.env.QUERY_REGRESSION_ADMISSION_HMAC = originalHmac; fs.rmSync(temporaryDir, { recursive: true, force: true }); } }); test('skips a stale runner artifact from a previous attempt', async () => { const originalCwd = process.cwd(); const originalRunId = process.env.WORKFLOW_RUN_ID; const originalRunAttempt = process.env.WORKFLOW_RUN_ATTEMPT; const temporaryDir = fs.mkdtempSync(path.join(os.tmpdir(), 'query-regression-comment-')); const artifactDir = path.join(temporaryDir, 'query-regression-comment'); const outputs = new Map(); const infos = []; try { fs.mkdirSync(artifactDir); const admission = { run_id: 606, run_attempt: 1, base_repo: 'owner/repo', pr_number: 42, head_sha: 'pr-head-sha', head_repo: 'fork/repo', candidate_sha: 'merge-sha', base_sha: 'base-sha', }; fs.mkdirSync(path.join(temporaryDir, 'query-regression-admission')); fs.writeFileSync( path.join(temporaryDir, 'query-regression-admission', 'query-regression-admission.json'), JSON.stringify(admission), ); fs.writeFileSync(path.join(artifactDir, 'query-regression-pr.json'), JSON.stringify({ ...admission, built_base_sha: 'base-sha', event_base_sha: 'base-sha', })); process.chdir(temporaryDir); process.env.WORKFLOW_RUN_ID = '606'; process.env.WORKFLOW_RUN_ATTEMPT = '2'; await handler({ core: { info(message) { infos.push(message); }, warning() {}, setOutput(name, value) { outputs.set(name, value); }, }, context: { repo: { owner: 'owner', repo: 'repo' }, payload: { workflow_run: { event: 'repository_dispatch', head_sha: 'default-branch-sha', head_repository: { full_name: 'owner/repo' }, pull_requests: [], }, }, }, github: { rest: { pulls: { get: async () => { throw new Error('should not fetch PR'); } } } }, }); assert.equal(outputs.get('should_post'), 'false'); assert.match(infos.join('\n'), /does not match this workflow_run attempt/); } finally { process.chdir(originalCwd); if (originalRunId === undefined) delete process.env.WORKFLOW_RUN_ID; else process.env.WORKFLOW_RUN_ID = originalRunId; if (originalRunAttempt === undefined) delete process.env.WORKFLOW_RUN_ATTEMPT; else process.env.WORKFLOW_RUN_ATTEMPT = originalRunAttempt; fs.rmSync(temporaryDir, { recursive: true, force: true }); } }); test('skips when the current PR head repository is missing', async () => { const originalCwd = process.cwd(); const originalRunId = process.env.WORKFLOW_RUN_ID; const originalRunAttempt = process.env.WORKFLOW_RUN_ATTEMPT; const originalHmac = process.env.QUERY_REGRESSION_ADMISSION_HMAC; const temporaryDir = fs.mkdtempSync(path.join(os.tmpdir(), 'query-regression-comment-')); const artifactDir = path.join(temporaryDir, 'query-regression-comment'); const outputs = new Map(); const infos = []; try { fs.mkdirSync(artifactDir); const metadata = { run_id: 707, run_attempt: 1, base_repo: 'owner/repo', pr_number: 42, head_sha: 'pr-head-sha', head_repo: 'fork/repo', built_base_sha: 'base-sha', event_base_sha: 'base-sha', candidate_sha: 'merge-sha', base_sha: 'base-sha', }; fs.mkdirSync(path.join(temporaryDir, 'query-regression-admission')); fs.writeFileSync( path.join(temporaryDir, 'query-regression-admission', 'query-regression-admission.json'), JSON.stringify(metadata), ); fs.writeFileSync(path.join(artifactDir, 'query-regression-pr.json'), JSON.stringify(metadata)); process.chdir(temporaryDir); process.env.WORKFLOW_RUN_ID = '707'; process.env.WORKFLOW_RUN_ATTEMPT = '1'; process.env.QUERY_REGRESSION_ADMISSION_HMAC = HMAC_SECRET; await handler({ core: { info(message) { infos.push(message); }, warning() {}, setOutput(name, value) { outputs.set(name, value); }, }, context: { repo: { owner: 'owner', repo: 'repo' }, payload: { workflow_run: { event: 'repository_dispatch', head_sha: 'default-branch-sha', head_repository: { full_name: 'owner/repo' }, pull_requests: [], }, }, }, github: githubApi({ identity: metadata, pull: { state: 'open', base: { repo: { full_name: 'owner/repo' } }, head: { repo: null, sha: 'pr-head-sha' }, }, }), }); assert.equal(outputs.get('should_post'), 'false'); assert.match(infos.join('\n'), /does not match trusted admission/); } finally { process.chdir(originalCwd); if (originalRunId === undefined) delete process.env.WORKFLOW_RUN_ID; else process.env.WORKFLOW_RUN_ID = originalRunId; if (originalRunAttempt === undefined) delete process.env.WORKFLOW_RUN_ATTEMPT; else process.env.WORKFLOW_RUN_ATTEMPT = originalRunAttempt; if (originalHmac === undefined) delete process.env.QUERY_REGRESSION_ADMISSION_HMAC; else process.env.QUERY_REGRESSION_ADMISSION_HMAC = originalHmac; fs.rmSync(temporaryDir, { recursive: true, force: true }); } }); test('signs and verifies admission markers', () => { const identity = { run_id: 808, pr_number: 42, head_sha: 'HEADSHA', head_repo: 'fork/repo', base_repo: 'owner/repo', candidate_sha: 'MERGESHA', base_sha: 'BASESHA', }; const mac = admissionMac(HMAC_SECRET, identity); assert.equal(verifyAdmissionMac(HMAC_SECRET, identity, mac), true); assert.equal(verifyAdmissionMac('other', identity, mac), false); assert.equal(verifyAdmissionMac(HMAC_SECRET, { ...identity, pr_number: 99 }, mac), false); const parsed = parseAdmissionMarker(`noise\n${formatAdmissionMarker({ ...identity, mac })}\n`); assert.equal(parsed.pr_number, 42); assert.equal(verifyAdmissionMac(HMAC_SECRET, parsed, parsed.mac), true); }); test('skips when the HMAC secret is unset', async () => { const originalCwd = process.cwd(); const originalRunId = process.env.WORKFLOW_RUN_ID; const originalRunAttempt = process.env.WORKFLOW_RUN_ATTEMPT; const originalHmac = process.env.QUERY_REGRESSION_ADMISSION_HMAC; const temporaryDir = fs.mkdtempSync(path.join(os.tmpdir(), 'query-regression-comment-')); const artifactDir = path.join(temporaryDir, 'query-regression-comment'); const outputs = new Map(); const infos = []; try { fs.mkdirSync(artifactDir); const metadata = { run_id: 808, run_attempt: 1, base_repo: 'owner/repo', pr_number: 42, head_sha: 'pr-head-sha', head_repo: 'fork/repo', candidate_sha: 'merge-sha', base_sha: 'base-sha', }; fs.mkdirSync(path.join(temporaryDir, 'query-regression-admission')); fs.writeFileSync( path.join(temporaryDir, 'query-regression-admission', 'query-regression-admission.json'), JSON.stringify(metadata), ); fs.writeFileSync(path.join(artifactDir, 'query-regression-pr.json'), JSON.stringify(metadata)); process.chdir(temporaryDir); process.env.WORKFLOW_RUN_ID = '808'; process.env.WORKFLOW_RUN_ATTEMPT = '1'; delete process.env.QUERY_REGRESSION_ADMISSION_HMAC; await handler({ core: { info(message) { infos.push(message); }, warning() {}, setOutput(name, value) { outputs.set(name, value); }, }, context: { repo: { owner: 'owner', repo: 'repo' }, payload: { workflow_run: { event: 'repository_dispatch', head_sha: 'default-branch-sha', head_repository: { full_name: 'owner/repo' }, pull_requests: [], }, }, }, github: githubApi({ identity: metadata }), }); assert.equal(outputs.get('should_post'), 'false'); assert.match(infos.join('\n'), /QUERY_REGRESSION_ADMISSION_HMAC is unset/); } finally { process.chdir(originalCwd); if (originalRunId === undefined) delete process.env.WORKFLOW_RUN_ID; else process.env.WORKFLOW_RUN_ID = originalRunId; if (originalRunAttempt === undefined) delete process.env.WORKFLOW_RUN_ATTEMPT; else process.env.WORKFLOW_RUN_ATTEMPT = originalRunAttempt; if (originalHmac === undefined) delete process.env.QUERY_REGRESSION_ADMISSION_HMAC; else process.env.QUERY_REGRESSION_ADMISSION_HMAC = originalHmac; fs.rmSync(temporaryDir, { recursive: true, force: true }); } }); test('skips when the hinted PR has no signed marker for this run', async () => { const originalCwd = process.cwd(); const originalRunId = process.env.WORKFLOW_RUN_ID; const originalRunAttempt = process.env.WORKFLOW_RUN_ATTEMPT; const originalHmac = process.env.QUERY_REGRESSION_ADMISSION_HMAC; const temporaryDir = fs.mkdtempSync(path.join(os.tmpdir(), 'query-regression-comment-')); const artifactDir = path.join(temporaryDir, 'query-regression-comment'); const outputs = new Map(); const infos = []; try { fs.mkdirSync(artifactDir); const metadata = { run_id: 909, run_attempt: 1, base_repo: 'owner/repo', pr_number: 99, head_sha: 'pr-head-sha', head_repo: 'fork/repo', candidate_sha: 'merge-sha', base_sha: 'base-sha', }; fs.mkdirSync(path.join(temporaryDir, 'query-regression-admission')); fs.writeFileSync( path.join(temporaryDir, 'query-regression-admission', 'query-regression-admission.json'), JSON.stringify(metadata), ); fs.writeFileSync(path.join(artifactDir, 'query-regression-pr.json'), JSON.stringify(metadata)); process.chdir(temporaryDir); process.env.WORKFLOW_RUN_ID = '909'; process.env.WORKFLOW_RUN_ATTEMPT = '1'; process.env.QUERY_REGRESSION_ADMISSION_HMAC = HMAC_SECRET; await handler({ core: { info(message) { infos.push(message); }, warning() {}, setOutput(name, value) { outputs.set(name, value); }, }, context: { repo: { owner: 'owner', repo: 'repo' }, payload: { workflow_run: { event: 'repository_dispatch', head_sha: 'default-branch-sha', head_repository: { full_name: 'owner/repo' }, pull_requests: [], }, }, }, github: githubApi({ identity: metadata, comments: [{ id: 1, body: 'unrelated' }] }), }); assert.equal(outputs.get('should_post'), 'false'); assert.match(infos.join('\n'), /No signed admission marker/); } finally { process.chdir(originalCwd); if (originalRunId === undefined) delete process.env.WORKFLOW_RUN_ID; else process.env.WORKFLOW_RUN_ID = originalRunId; if (originalRunAttempt === undefined) delete process.env.WORKFLOW_RUN_ATTEMPT; else process.env.WORKFLOW_RUN_ATTEMPT = originalRunAttempt; if (originalHmac === undefined) delete process.env.QUERY_REGRESSION_ADMISSION_HMAC; else process.env.QUERY_REGRESSION_ADMISSION_HMAC = originalHmac; fs.rmSync(temporaryDir, { recursive: true, force: true }); } }); test('skips a marker whose HMAC does not match', async () => { const originalCwd = process.cwd(); const originalRunId = process.env.WORKFLOW_RUN_ID; const originalRunAttempt = process.env.WORKFLOW_RUN_ATTEMPT; const originalHmac = process.env.QUERY_REGRESSION_ADMISSION_HMAC; const temporaryDir = fs.mkdtempSync(path.join(os.tmpdir(), 'query-regression-comment-')); const artifactDir = path.join(temporaryDir, 'query-regression-comment'); const outputs = new Map(); const infos = []; try { fs.mkdirSync(artifactDir); const metadata = { run_id: 910, run_attempt: 1, base_repo: 'owner/repo', pr_number: 42, head_sha: 'pr-head-sha', head_repo: 'fork/repo', candidate_sha: 'merge-sha', base_sha: 'base-sha', }; fs.mkdirSync(path.join(temporaryDir, 'query-regression-admission')); fs.writeFileSync( path.join(temporaryDir, 'query-regression-admission', 'query-regression-admission.json'), JSON.stringify(metadata), ); fs.writeFileSync(path.join(artifactDir, 'query-regression-pr.json'), JSON.stringify(metadata)); process.chdir(temporaryDir); process.env.WORKFLOW_RUN_ID = '910'; process.env.WORKFLOW_RUN_ATTEMPT = '1'; process.env.QUERY_REGRESSION_ADMISSION_HMAC = HMAC_SECRET; await handler({ core: { info(message) { infos.push(message); }, warning() {}, setOutput(name, value) { outputs.set(name, value); }, }, context: { repo: { owner: 'owner', repo: 'repo' }, payload: { workflow_run: { event: 'repository_dispatch', head_sha: 'default-branch-sha', head_repository: { full_name: 'owner/repo' }, pull_requests: [], }, }, }, github: githubApi({ identity: metadata, comments: [markerComment(metadata, { secret: 'forged-secret' })], }), }); assert.equal(outputs.get('should_post'), 'false'); assert.match(infos.join('\n'), /No signed admission marker/); } finally { process.chdir(originalCwd); if (originalRunId === undefined) delete process.env.WORKFLOW_RUN_ID; else process.env.WORKFLOW_RUN_ID = originalRunId; if (originalRunAttempt === undefined) delete process.env.WORKFLOW_RUN_ATTEMPT; else process.env.WORKFLOW_RUN_ATTEMPT = originalRunAttempt; if (originalHmac === undefined) delete process.env.QUERY_REGRESSION_ADMISSION_HMAC; else process.env.QUERY_REGRESSION_ADMISSION_HMAC = originalHmac; fs.rmSync(temporaryDir, { recursive: true, force: true }); } }); test('finds a newly posted marker after a full page of newer comments', async () => { const originalCwd = process.cwd(); const originalRunId = process.env.WORKFLOW_RUN_ID; const originalRunAttempt = process.env.WORKFLOW_RUN_ATTEMPT; const originalHmac = process.env.QUERY_REGRESSION_ADMISSION_HMAC; const temporaryDir = fs.mkdtempSync(path.join(os.tmpdir(), 'query-regression-comment-')); const artifactDir = path.join(temporaryDir, 'query-regression-comment'); const outputs = new Map(); const pages = []; try { fs.mkdirSync(artifactDir); const metadata = { run_id: 911, run_attempt: 1, base_repo: 'owner/repo', pr_number: 42, head_sha: 'pr-head-sha', head_repo: 'fork/repo', candidate_sha: 'merge-sha', base_sha: 'base-sha', }; fs.mkdirSync(path.join(temporaryDir, 'query-regression-admission')); fs.writeFileSync( path.join(temporaryDir, 'query-regression-admission', 'query-regression-admission.json'), JSON.stringify(metadata), ); fs.writeFileSync(path.join(artifactDir, 'query-regression-pr.json'), JSON.stringify(metadata)); process.chdir(temporaryDir); process.env.WORKFLOW_RUN_ID = '911'; process.env.WORKFLOW_RUN_ATTEMPT = '1'; process.env.QUERY_REGRESSION_ADMISSION_HMAC = HMAC_SECRET; await handler({ core: { info() {}, warning() {}, setOutput(name, value) { outputs.set(name, value); }, }, context: { repo: { owner: 'owner', repo: 'repo' }, payload: { workflow_run: { event: 'repository_dispatch', head_sha: 'default-branch-sha', head_repository: { full_name: 'owner/repo' }, pull_requests: [], }, }, }, github: { rest: { issues: { listComments: async ({ page, direction }) => { pages.push({ page, direction }); if (page === 1) { return { data: Array.from({ length: 100 }, (_, index) => ({ id: 10_000 - index, body: 'unrelated', })), }; } return { data: [markerComment(metadata, { id: 50 })] }; }, }, pulls: { get: async () => ({ data: { state: 'open', base: { repo: { full_name: 'owner/repo' } }, head: { repo: { full_name: 'fork/repo' }, sha: 'pr-head-sha' }, }, }), }, }, }, }); assert.equal(outputs.get('should_post'), 'true'); assert.deepEqual(pages, [ { page: 1, direction: 'desc' }, { page: 2, direction: 'desc' }, ]); } finally { process.chdir(originalCwd); if (originalRunId === undefined) delete process.env.WORKFLOW_RUN_ID; else process.env.WORKFLOW_RUN_ID = originalRunId; if (originalRunAttempt === undefined) delete process.env.WORKFLOW_RUN_ATTEMPT; else process.env.WORKFLOW_RUN_ATTEMPT = originalRunAttempt; if (originalHmac === undefined) delete process.env.QUERY_REGRESSION_ADMISSION_HMAC; else process.env.QUERY_REGRESSION_ADMISSION_HMAC = originalHmac; fs.rmSync(temporaryDir, { recursive: true, force: true }); } });