import { describe, expect, it } from 'vitest' import { overall, validateReport } from '@extant2000/evidence-record' import { checkPlan, formatPlan, peakRate, worstCaseBytes, type DeployStep, type SignatureBudget, } from '../src/index.js' const step = (p: Partial = {}): DeployStep => ({ name: 'pull-base-image', destination: 'registry.gitlab.com', bytes: 200_000_000, durationSeconds: 60, where: '.gitlab-ci.yml', ...p, }) describe('retries are cost, not a footnote', () => { it('counts every attempt in the worst case', () => { // A step budgeted at one attempt is budgeted at its best case. expect(worstCaseBytes(step({ bytes: 100, retries: 3 }))).toBe(300) expect(worstCaseBytes(step({ bytes: 100 }))).toBe(100) }) it('a plan that fits on first attempt and not with retries fails', () => { const budget: SignatureBudget = { maxTotalBytes: 250_000_000 } expect(overall(checkPlan([step({ retries: 1 })], budget))).toBe('pass') const r = checkPlan([step({ retries: 2 })], budget) expect(r.findings.find(f => f.id === 'total')!.determination).toBe('fail') expect(r.findings.find(f => f.id === 'total')!.detail).toContain('every retry counts') }) }) describe('an unexpected destination is a different kind of problem', () => { const budget: SignatureBudget = { allowedDestinations: ['registry.gitlab.com'] } it('fails a step reaching outside the declared set', () => { const r = checkPlan([step({ name: 'fetch-tool', destination: 'cdn.example.net', bytes: 1024 })], budget) expect(r.findings.find(f => f.id === 'fetch-tool')!.determination).toBe('fail') expect(r.findings.find(f => f.id === 'fetch-tool')!.severity).toBe('critical') }) it('stays critical however small the transfer', () => { // Volume is irrelevant: an unexpected host is supply chain or leak. const r = checkPlan([step({ name: 'ping', destination: 'evil.example', bytes: 1 })], budget) expect(r.findings.find(f => f.id === 'ping')!.severity).toBe('critical') expect(formatPlan([step({ name: 'ping', destination: 'evil.example', bytes: 1 })], budget)) .toContain('Volume is irrelevant here') }) it('says so when no allowlist was supplied', () => { expect(formatPlan([step()], {})).toContain('no step could be checked against one') }) it('passes a step inside the declared set', () => { expect(overall(checkPlan([step()], budget))).toBe('pass') }) }) describe('shape, not just total', () => { it('fails a burst that fits the total budget', () => { // 200 MB over 60s = 3.3 MB/s. The same bytes over an hour would pass. const r = checkPlan([step()], { maxTotalBytes: 1e9, maxBytesPerSecond: 1_000_000 }) const f = r.findings.find(x => x.id === 'pull-base-image')! expect(f.determination).toBe('fail') expect(f.detail).toContain('the total is not the problem, the shape is') }) it('multiplies the peak by concurrency', () => { const budget: SignatureBudget = { maxBytesPerSecond: 5_000_000, concurrency: 4 } // 3.3 MB/s alone passes; x4 concurrent does not. expect(overall(checkPlan([step()], { maxBytesPerSecond: 5_000_000 }))).toBe('pass') expect(overall(checkPlan([step()], budget))).toBe('fail') }) it('cannot check a rate without a duration, and says so', () => { const r = checkPlan([step({ durationSeconds: undefined })], { maxBytesPerSecond: 1_000_000 }) expect(r.findings.find(f => f.id === 'pull-base-image')!.determination).toBe('not-assessed') expect(peakRate(step({ durationSeconds: undefined }))).toBeNull() }) }) describe('an unmeasured transfer is not a small one', () => { it('reports an unknown volume as not-assessed, never zero', () => { const r = checkPlan([step({ bytes: null })], { maxTotalBytes: 1e9 }) const f = r.findings.find(x => x.id === 'pull-base-image')! expect(f.determination).toBe('not-assessed') expect(f.detail).toContain('An unmeasured transfer is not a small one') }) it('reports the total as a LOWER BOUND when any step is unmeasured', () => { // A partial sum presented as a total is how a budget check reassures // without checking. const r = checkPlan([step({ bytes: 1000 }), step({ name: 'unknown-pull', bytes: null })], { maxTotalBytes: 1e9 }) const total = r.findings.find(f => f.id === 'total')! expect(total.determination).toBe('not-assessed') expect(total.detail).toContain('lower bound, not a total') }) it('still fails when the KNOWN bytes alone exceed the budget', () => { // Unmeasured steps cannot rescue a plan that is already over. const r = checkPlan([step({ bytes: 2e9 }), step({ name: 'x', bytes: null })], { maxTotalBytes: 1e9 }) expect(r.findings.find(f => f.id === 'total')!.determination).toBe('fail') }) }) describe('conformance with the evidence-record standard', () => { it('an empty plan is not-assessed, and says what empty means', () => { expect(overall(checkPlan([]))).toBe('not-assessed') expect(formatPlan([])).toContain('An unenumerated step still moves bytes') }) it('every conclusion carries a citation', () => { expect(validateReport(checkPlan([step(), step({ name: 'b', destination: 'x', bytes: 5 })], { maxTotalBytes: 1e9, allowedDestinations: ['registry.gitlab.com'] }))).toEqual([]) }) it('cites the file each step is defined in', () => { expect(formatPlan([step()], {}, { evidence: 'full' })).toContain('.gitlab-ci.yml') }) })