import { describe, expect, it } from 'vitest' import { overall, validateReport } from '@extant2000/evidence-record' import { formatRollout, safeToProceed, verifyRollout, type Target } from '../src/index.js' const shipped = (name: string, sha = 'a1b2c3d'): Target => ({ name, expected: sha, observed: sha, via: 'artifact-probe', where: `https://${name}/__version` }) describe('a green pipeline is not a deployed artifact', () => { it('CATCHES THE SKIPPED DEPLOY: deploy skipped, pipeline still green', () => { // An unpinned linter failed, the deploy job's dependency was // unsatisfied, and it was SKIPPED. A skipped job does not fail a // pipeline, so nothing ships behind a green tick. const t: Target = { name: 'api', expected: 'a1b2c3d', observed: 'a1b2c3d', via: 'artifact-probe', where: 'gitlab pipelines/123', pipelineStatus: 'success', jobsRun: ['build', 'test', 'image-lint'], } const r = verifyRollout([t]) const f = r.findings.find(x => x.id === 'api/skipped-deploy')! expect(f.determination).toBe('fail') expect(f.severity).toBe('critical') expect(f.detail).toContain('build, test, image-lint') expect(overall(r)).toBe('fail') }) it('does not fire when the deploy job actually ran', () => { const t: Target = { ...shipped('api'), pipelineStatus: 'success', jobsRun: ['build', 'deploy'] } expect(verifyRollout([t]).findings.some(f => f.id.endsWith('/skipped-deploy'))).toBe(false) expect(overall(verifyRollout([t]))).toBe('pass') }) it('honours a custom deploy job name', () => { const t: Target = { ...shipped('api'), pipelineStatus: 'success', jobsRun: ['build', 'ship'] } expect(verifyRollout([t], { deployJob: 'ship' }).findings.some(f => f.id.endsWith('/skipped-deploy'))).toBe(false) expect(verifyRollout([t], { deployJob: 'deploy' }).findings.some(f => f.id.endsWith('/skipped-deploy'))).toBe(true) }) }) describe('a 200 is not your build', () => { it('refuses to accept an HTTP status as a deployment check', () => { const t: Target = { name: 'web', expected: 'a1b2c3d', observed: 'up', via: 'http-status', httpStatus: 200, where: 'https://web.example.com/healthz', } const r = verifyRollout([t]) expect(r.findings[0]!.determination).toBe('not-assessed') expect(r.findings[0]!.detail).toContain('passes on HTTP 500') expect(overall(r)).toBe('not-assessed') }) it('refuses to accept a pipeline status as a deployment check', () => { const t: Target = { name: 'worker', expected: 'a1b2c3d', observed: 'success', via: 'pipeline-status', pipelineStatus: 'success', where: 'gitlab pipelines/9', } expect(verifyRollout([t]).findings[0]!.determination).toBe('not-assessed') expect(formatRollout([t])).toContain('A green pipeline is not a deployed artifact') }) it('CATCHES THE HEALTHY OLD BUILD — up, 200, and the previous version', () => { const t: Target = { name: 'billing', expected: 'a1b2c3d', observed: '9f8e7d6', via: 'artifact-probe', where: 'https://billing.example.com/__version', } const f = verifyRollout([t]).findings[0]! expect(f.determination).toBe('fail') expect(f.summary).toContain('serving 9f8e7d6, expected a1b2c3d') expect(f.detail).toContain('up, healthy, and running the previous build') }) it('passes only on an artifact probe that matches', () => { expect(overall(verifyRollout([shipped('api')]))).toBe('pass') }) }) describe('an untouched target reports its previous success', () => { it('reports a not-yet-started target as unassessed, not green', () => { // Querying status for a repo not yet merged returns the PRE-rollout run. const t: Target = { name: 'search', expected: 'a1b2c3d', observed: 'success', via: 'pipeline-status', pipelineStatus: 'success', where: 'gitlab pipelines/1', started: false, } const f = verifyRollout([t]).findings[0]! expect(f.determination).toBe('not-assessed') expect(f.detail).toContain('green because nothing has happened yet') }) it('does not count an unstarted target as confirmed', () => { const t: Target = { ...shipped('search'), started: false } expect(formatRollout([t])).toContain('0 of 1 target(s) confirmed') }) }) describe('safeToProceed blocks on unverified, not only on failed', () => { it('proceeds when every target is confirmed by probe', () => { const r = safeToProceed([shipped('a'), shipped('b')]) expect(r.ok).toBe(true) expect(r.reason).toContain('All 2 target(s) confirmed') }) it('blocks on a failure', () => { expect(safeToProceed([shipped('a'), { name: 'b', expected: 'x', observed: 'y', via: 'artifact-probe', where: 'w' }]).ok).toBe(false) }) it('blocks on unverified — "not checked" is not evidence it worked', () => { const r = safeToProceed([ shipped('a'), { name: 'b', expected: 'x', observed: 'up', via: 'http-status', where: 'w' }, ]) expect(r.ok).toBe(false) expect(r.reason).toContain('is not evidence that it did') }) it('blocks on an empty target list', () => { expect(safeToProceed([]).ok).toBe(false) }) }) describe('conformance with the evidence-record standard', () => { it('an empty rollout is not-assessed, never clean', () => { expect(overall(verifyRollout([]))).toBe('not-assessed') expect(formatRollout([])).not.toContain('✓') }) it('every conclusion carries a citation', () => { expect(validateReport(verifyRollout([ shipped('a'), { name: 'b', expected: 'x', observed: 'y', via: 'artifact-probe', where: 'w', pipelineStatus: 'success', jobsRun: ['build'] }, ]))).toEqual([]) }) })