// Unit tests for SHA normalization in verify paths. // Run with: node --test test/sha-comparison.test.js import assert from 'node:assert/strict'; import { test } from 'node:test'; // The canonical normalization function used in verifyStatelessRecreated() // and runtime-status — must stay in sync with server.js. const stripSha = (s) => (s || '').replace(/^sha256:/, ''); // ------------------------------------------------------------------ // Bug #3 regression: docker compose images returns bare hex, // docker inspect .Image returns sha256:. They must compare equal. // ------------------------------------------------------------------ test('sha: bare hex == bare hex', () => { const a = 'a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2'; assert.equal(stripSha(a), stripSha(a)); assert.ok(stripSha(a) === stripSha(a)); }); test('sha: sha256-prefixed == bare hex (the failing case before the fix)', () => { const bare = 'a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2'; const prefixed = `sha256:${bare}`; // Before fix: prefixed === bare => false assert.notEqual(prefixed, bare, 'raw strings are indeed unequal — this is the bug'); // After fix: stripSha(prefixed) === stripSha(bare) => true assert.equal(stripSha(prefixed), stripSha(bare), 'normalized strings must be equal'); }); test('sha: both sha256-prefixed', () => { const a = 'sha256:a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2'; const b = 'sha256:a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2'; assert.equal(stripSha(a), stripSha(b)); }); test('sha: different digests stay different after normalization', () => { const a = 'sha256:aaaa0000000000000000000000000000000000000000000000000000000000001111'; const b = 'sha256:bbbb0000000000000000000000000000000000000000000000000000000000002222'; assert.notEqual(stripSha(a), stripSha(b)); }); test('sha: empty/null input returns empty string', () => { assert.equal(stripSha(''), ''); assert.equal(stripSha(null), ''); assert.equal(stripSha(undefined), ''); }); test('sha: imageMatch logic mirrors server.js verifyStatelessRecreated', () => { const expectedSha = 'a0845a6c5772e01234567890abcdef01234567890abcdef01234567890abcdef01'; const actualSha = `sha256:${expectedSha}`; const imageMatch = !!expectedSha && stripSha(actualSha) === stripSha(expectedSha); assert.ok(imageMatch, 'imageMatch must be true when digests are the same modulo sha256: prefix'); });