Files
at-container-registry/pkg/appview/db
Evan JarrettandClaude Opus 5 08121f3cd0 appview: fix O(n) bcrypt scan making /auth/token take 15s+
ValidateDeviceSecret ran bcrypt.CompareHashAndPassword against every row in
the devices table until one matched — no WHERE clause. At bcrypt cost 10
(~65ms on the single-core production host) and 244 registered devices, a
device near the end of the scan cost ~15.8s of pure CPU per /auth/token,
which is past Docker's client deadline. Measured on production: 15.7-16.0s
steady state with the appview pinned at 100% CPU for the duration, while
anonymous requests on the same box served in 20ms.

The cost grew linearly with every device registered, and the scan ran in
rowid order, so the newest devices — the ones most likely to be in active
use — paid the most. This is the timeout users were reporting.

Devices now carry secret_lookup = hex(sha256(secret)), indexed, and
authentication fetches the single matching row.

SHA-256 is the verifier here, not merely an index. Device secrets are 32
bytes from crypto/rand, so presenting a value that hashes to a stored digest
requires a preimage or a 2^256 search. bcrypt's work factor only helps when
the input space is small enough to enumerate, which does not apply to a
random 256-bit token, and a database leak exposes no more than before.

The plaintext is not recoverable from a bcrypt hash, so existing rows cannot
be backfilled directly. They are migrated lazily on their next successful
authentication, which any push, pull or login triggers, and the legacy scan
is filtered to un-migrated rows so its cost decays as devices migrate. The
backfill runs after the cursor is closed: issuing it inside the rows loop
deadlocks, because the open cursor holds the connection the write needs.

bcrypt now exists solely to carry legacy rows across and can be deleted once
the table is fully migrated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 23:01:07 -05:00
..
2026-02-09 23:19:01 -06:00
2026-02-10 20:58:24 -06:00
2026-02-10 20:58:24 -06:00
2026-04-09 10:31:19 -05:00
2026-05-03 10:48:36 -05:00
2026-05-03 10:48:36 -05:00
2025-10-28 17:40:11 -05:00
2026-01-05 20:26:41 -06:00
2026-02-09 23:19:01 -06:00
2025-10-25 13:30:07 -05:00