test(encryption): make tamper tests deterministic #262

Merged
barrettruth merged 1 commit from fix/encryption-test-deterministic-tampering into main 2026-05-01 17:45:31 +00:00
Owner

The two tampered-input tests in tests/core/encryption.test.ts (fails to decrypt tampered ciphertext and fails to decrypt tampered auth tag) built their tampered byte by replacing the last hex byte with the literal ff. When the original last byte was already 0xff — ~1/256 of encrypts, since the per-encrypt random IV cascades through AES-256-GCM into a random ciphertext + auth tag — the "tamper" was a no-op, decrypt succeeded, and the test failed with expected [Function] to throw an error. Combined per-vitest-run flake rate was 1 - (255/256)^2 ≈ 0.78%, which is what bit the migration commit 8eb1d7a8.

Fix is to pick the replacement byte based on the original: ff if the original last byte was anything else, 00 if it was already ff. Either way the byte is meaningfully altered so the decrypt rejects the bad input and the test asserts what it intends.

Verification: 500 consecutive vitest runs of tests/core/encryption.test.ts post-fix — 0 failures (pre-fix expectation was ~4 failures at the 0.78% rate). nix develop .#ci --command just ci green locally.

The two tampered-input tests in `tests/core/encryption.test.ts` (`fails to decrypt tampered ciphertext` and `fails to decrypt tampered auth tag`) built their tampered byte by replacing the last hex byte with the literal `ff`. When the original last byte was already `0xff` — ~1/256 of encrypts, since the per-encrypt random IV cascades through AES-256-GCM into a random ciphertext + auth tag — the "tamper" was a no-op, decrypt succeeded, and the test failed with `expected [Function] to throw an error`. Combined per-vitest-run flake rate was `1 - (255/256)^2 ≈ 0.78%`, which is what bit the migration commit `8eb1d7a8`. Fix is to pick the replacement byte based on the original: `ff` if the original last byte was anything else, `00` if it was already `ff`. Either way the byte is meaningfully altered so the decrypt rejects the bad input and the test asserts what it intends. Verification: 500 consecutive vitest runs of `tests/core/encryption.test.ts` post-fix — 0 failures (pre-fix expectation was ~4 failures at the 0.78% rate). `nix develop .#ci --command just ci` green locally.
test(encryption): make tamper tests deterministic
All checks were successful
quality / Test (pull_request) Successful in 19s
quality / Lint (pull_request) Successful in 24s
quality / Build (pull_request) Successful in 43s
948e84f7f1
Both 'fails to decrypt tampered ciphertext' and 'fails to decrypt
tampered auth tag' built their tampered byte by replacing the last
hex byte with the literal 'ff'. When the original last byte happened
to already be 0xff (~1/256 of encrypts, given the random per-encrypt
IV -> random ciphertext + auth tag), the 'tamper' was a no-op, the
decrypt succeeded, and the test failed with 'expected [Function] to
throw an error'. Combined per-vitest-run flake rate was
1 - (255/256)^2 ~= 0.78%.

Pick the replacement byte based on the original: 'ff' if the original
last byte is anything else, '00' if it was already 'ff'. Either way
the byte is meaningfully altered, the decrypt rejects the bad input,
and the test asserts what it intends to assert.

Stress-tested 500 consecutive vitest runs post-fix: 0 failures.
barrettruth deleted branch fix/encryption-test-deterministic-tampering 2026-05-01 17:45:43 +00:00
Sign in to join this conversation.
No description provided.