import { describe, expect, it } from 'vitest' import { overall, validateReport } from '@extant2000/evidence-record' import { coverageGaps, formatTermination, verifyTermination, type Resource, type Termination, } from '../src/index.js' const gone = (id: string, cls: Resource['class']): Resource => ({ id, class: cls, where: `probe:${id}`, state: 'absent', verifiedBy: 'independent-probe' }) describe('billing outliving compute — the failure that costs money', () => { const t: Termination = { target: 'customer acme-corp', resources: [ gone('acme-web', 'compute'), gone('acme.example.com', 'dns'), { id: 'sub_1ABC', class: 'billing', where: 'stripe:sub_1ABC', state: 'present', verifiedBy: 'independent-probe' }, ], } it('catches the combination neither half can see', () => { // The teardown succeeded. The subscription is in a normal active state. // Only together are they wrong. const r = verifyTermination(t) const cross = r.findings.find(f => f.id === 'billing-outlives-compute')! expect(cross.determination).toBe('fail') expect(cross.severity).toBe('critical') expect(overall(r)).toBe('fail') }) it('leads with it, above the per-resource findings', () => { const text = formatTermination(t) expect(text.indexOf('Compute is gone and billing is still active')) .toBeLessThan(text.indexOf('sub_1ABC still present')) }) it('says who finds out', () => { expect(formatTermination(t)).toContain('the customer is the one who finds out') }) it('does not fire when compute is still up — that is just a running service', () => { const running: Termination = { target: 'x', resources: [ { id: 'web', class: 'compute', where: 'docker ps', state: 'present' }, { id: 'sub_1', class: 'billing', where: 'stripe', state: 'present' }, ], } expect(verifyTermination(running).findings.some(f => f.id === 'billing-outlives-compute')).toBe(false) }) it('does not fire when the subscription is deliberately retained', () => { const retained: Termination = { target: 'x', resources: [ gone('web', 'compute'), { id: 'sub_1', class: 'billing', where: 'stripe', state: 'present', retainedBy: 'final invoice pending' }, ], } expect(verifyTermination(retained).findings.some(f => f.id === 'billing-outlives-compute')).toBe(false) }) }) describe('a delete response is not a verification', () => { it('treats absence claimed by the delete call as UNVERIFIED, not gone', () => { // A 2xx from DELETE means the API accepted the request. This is the // entire difference between "terminated" and "verifiably terminated". const r = verifyTermination({ target: 'x', resources: [{ id: 'vol-1', class: 'storage', where: 'DELETE /volumes/vol-1', state: 'absent', verifiedBy: 'delete-response' }], }) expect(r.findings[0]!.determination).toBe('not-assessed') expect(overall(r)).toBe('not-assessed') expect(formatTermination({ target: 'x', resources: [{ id: 'vol-1', class: 'storage', where: 'DELETE /volumes/vol-1', state: 'absent', verifiedBy: 'delete-response' }], })).toContain('Re-check it from outside the teardown path') }) it('treats an unrecorded method as an assumption, never a pass', () => { const r = verifyTermination({ target: 'x', resources: [{ id: 'v', class: 'storage', where: 'runbook.md', state: 'absent' }], }) expect(r.findings[0]!.determination).toBe('not-assessed') expect(r.findings[0]!.detail).toContain('An assumption is not a verification') }) it('passes only on an independent probe', () => { expect(overall(verifyTermination({ target: 'x', resources: [gone('v', 'storage')] }))).toBe('pass') }) it('never counts unknown as gone', () => { const r = verifyTermination({ target: 'x', resources: [{ id: 'k', class: 'secret', where: 'vault', state: 'unknown' }], }) expect(r.findings[0]!.determination).toBe('not-assessed') expect(r.findings[0]!.severity).toBe('critical') }) }) describe('retention is an outcome, not a leak', () => { const t: Termination = { target: 'x', resources: [{ id: 'backup-2026-07', class: 'backup', where: 'b2://bucket/acme', state: 'present', retainedBy: '90-day retention, contractual', }], } it('reports a policy-retained resource as not-applicable, not a failure', () => { expect(verifyTermination(t).findings[0]!.determination).toBe('not-applicable') expect(overall(verifyTermination(t))).toBe('not-applicable') }) it('still prints it, because an invisible retention looks like a leak', () => { expect(formatTermination(t)).toContain('90-day retention, contractual') }) }) describe('residue', () => { it('rates a surviving secret critical, and says it can still authenticate', () => { const r = verifyTermination({ target: 'x', resources: [{ id: 'API_KEY', class: 'secret', where: '.env', state: 'present' }], }) expect(r.findings[0]!.severity).toBe('critical') expect(r.findings[0]!.detail).toContain('can still authenticate') }) it('rates a surviving DNS record high rather than critical', () => { const r = verifyTermination({ target: 'x', resources: [{ id: 'a.example.com', class: 'dns', where: 'cf', state: 'present' }], }) expect(r.findings[0]!.severity).toBe('high') }) }) describe('coverage — a class nobody enumerated cannot fail a check', () => { it('names the classes the teardown never mentioned', () => { const t: Termination = { target: 'x', resources: [gone('web', 'compute'), gone('v', 'storage')] } expect(coverageGaps(t)).toContain('billing') expect(coverageGaps(t)).toContain('secret') expect(formatTermination(t)).toContain('NOT COVERED') }) it('reports no gaps when every class is enumerated', () => { const t: Termination = { target: 'x', resources: (['compute', 'storage', 'dns', 'route', 'database', 'billing', 'mailbox', 'secret', 'backup'] as const) .map(c => gone(c, c)), } expect(coverageGaps(t)).toEqual([]) expect(formatTermination(t)).not.toContain('NOT COVERED') }) }) describe('conformance with the evidence-record standard', () => { it('an empty termination is not-assessed, never clean', () => { const r = verifyTermination({ target: 'x', resources: [] }) expect(overall(r)).toBe('not-assessed') expect(formatTermination({ target: 'x', resources: [] })) .toContain('An unenumerated resource is not a deleted one') }) it('every conclusion carries a citation', () => { const t: Termination = { target: 'x', resources: [ gone('web', 'compute'), { id: 'sub_1', class: 'billing', where: 'stripe', state: 'present' }, ], } expect(validateReport(verifyTermination(t))).toEqual([]) }) })