ReviewOS

also looking at this

stacks/buddy

test: measure coverage, and call the three files nothing called

#1442
Merged glennmichael123 wants to merge test/zero-called-files into main
4 files +210 -0
test/analyzers.test.tsmodified+72-0
Changes to test/analyzers.test.ts
@@ -374,3 +374,75 @@ describe('analysis configuration', () => {
374374 expect(validateConfig({ analysis: { tools: { shellcheck: 'off' as never } } })).toHaveLength(1)
375375 })
376376})
377
378/**
379 * The workflow-audit analyzer had 0% function coverage: the six security
380 * rules it wraps are tested directly, but the wrapper — severity mapping,
381 * changed-file filtering, the empty-input short-circuit — was not, and the
382 * wrapper is what review actually calls.
383 */
384describe('workflow-audit analyzer', () => {
385 const cleanups: Array<() => void> = []
386
387 afterEach(() => {
388 while (cleanups.length > 0)
389 cleanups.pop()?.()
390 })
391
392 const RISKY = `name: CI
393on: push
394permissions: write-all
395jobs:
396 test:
397 runs-on: ubuntu-latest
398 steps:
399 - run: bun test
400`
401
402 async function repoRoot(): Promise<string> {
403 const { mkdtempSync, mkdirSync, writeFileSync, rmSync } = await import('node:fs')
404 const { tmpdir } = await import('node:os')
405 const { join } = await import('node:path')
406
407 const dir = mkdtempSync(join(tmpdir(), 'buddy-wf-audit-'))
408 cleanups.push(() => rmSync(dir, { recursive: true, force: true }))
409 mkdirSync(join(dir, '.github', 'workflows'), { recursive: true })
410 writeFileSync(join(dir, '.github', 'workflows', 'touched.yml'), RISKY)
411 writeFileSync(join(dir, '.github', 'workflows', 'untouched.yml'), RISKY)
412 return dir
413 }
414
415 it('success case - findings land as review findings with mapped severities', async () => {
416 const { githubActionsAnalyzer } = await import('../src/analysis/analyzers/github-actions')
417 const root = await repoRoot()
418
419 const findings = await githubActionsAnalyzer.run(['.github/workflows/touched.yml'], root)
420
421 expect(findings.length).toBeGreaterThan(0)
422 for (const finding of findings) {
423 expect(finding.tool).toBe('workflow-audit')
424 expect(finding.path).toBe('.github/workflows/touched.yml')
425 expect(['critical', 'major', 'minor', 'nit']).toContain(finding.severity)
426 }
427 // `permissions: write-all` is an error-level rule; errors map to major.
428 expect(findings.some(finding => finding.severity === 'major')).toBe(true)
429 })
430
431 it('success case - only the changed workflows are reported', async () => {
432 // The auditor scans the whole repository; a review must not comment on
433 // files the pull request never touched.
434 const { githubActionsAnalyzer } = await import('../src/analysis/analyzers/github-actions')
435 const root = await repoRoot()
436
437 const findings = await githubActionsAnalyzer.run(['.github/workflows/touched.yml'], root)
438
439 expect(findings.every(finding => finding.path !== '.github/workflows/untouched.yml')).toBe(true)
440 })
441
442 it('edge case - no changed workflows means no audit at all', async () => {
443 const { githubActionsAnalyzer } = await import('../src/analysis/analyzers/github-actions')
444
445 expect(await githubActionsAnalyzer.run([], '/nonexistent-root')).toEqual([])
446 })
447})
448