Skip to content

Commit dbaffc0

Browse files
committed
revert(cache): switch hashIdentity back to MD5
The CodeQL SHA-256 detour was a knee-jerk response to a false positive. MD5 was the correct pragmatic choice — it's not a password hash, it's namespacing local cache files. Dismissed the CodeQL alerts (47, 48) as 'won't fix' with the context. Keeping the try/catch restoration on `issues.ts` invalidation helpers from ec0279c (the cursor-bot finding was legitimate).
1 parent ec0279c commit dbaffc0

2 files changed

Lines changed: 5 additions & 10 deletions

File tree

AGENTS.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,9 +1020,6 @@ mock.module("./some-module", () => ({
10201020
<!-- lore:019d4a08-22c3-765b-ba12-d91b29e9d497 -->
10211021
* **Three Sentry APIs for span custom attributes with different capabilities**: Three Sentry span APIs with different attribute capabilities: (1) \`/trace/{traceId}/\` — hierarchical tree; \`additional\_attributes\` enumerates requested attrs; returns \`measurements\` (zero-filled on non-browser, stripped by \`filterSpanMeasurements()\`). (2) \`/projects/{org}/{project}/trace-items/{itemId}/\` — single span full detail; ALL attributes as \`{name,type,value}\[]\` automatically. (3) \`/events/?dataset=spans\&field=X\` — list/search; explicit \`field\` params. \`--fields\` flag filters JSON output AND requests extra API fields via \`extractExtraApiFields()\`. \`FIELD\_GROUP\_ALIASES\` supports shorthand expansion.
10221022
1023-
<!-- lore:019dabe5-3ef3-7e9c-a39b-edbbe139ba8f -->
1024-
* **Update notification rate-limited via last\_notified metadata + TTY gate**: \`src/lib/version-check.ts\` \`getUpdateNotification()\` now enforces a 24h rate limit via \`KEY\_LAST\_NOTIFIED\` metadata + an in-process latch (\`notifiedThisRun\`) plus a \`process.stderr.isTTY\` gate. Non-TTY invocations never see the banner (scripts, CI, \`| cat\`). \`setLastNotifiedNow()\` persists on emit; the latch prevents double-emit within a single process. Tests must mock \`process.stderr.isTTY = true\` AND reset the in-process latch between cases via the exported \`\_resetNotificationStateForTests()\` helper. Mirrors the pattern of other one-shot hints in the CLI.
1025-
10261023
### Decision
10271024
10281025
<!-- lore:019d799a-4809-7c54-b699-e2ae74c00227 -->
@@ -1051,7 +1048,7 @@ mock.module("./some-module", () => ({
10511048
* **I/O concurrency limits belong at the call site, not in generic combinators**: I/O concurrency limits belong at the call site, not in generic combinators. Pattern: module-scoped \`pLimit()\` with named constant (e.g., \`STAT\_CONCURRENCY = 32\` in \`project-root.ts\`, \`CACHE\_IO\_CONCURRENCY\` in \`response-cache.ts\`, \`pLimit(50)\` in \`code-scanner.ts\`). Keeps combinators pure, makes budget explicit at I/O boundary. stat() lighter than full reads — ~32 for stats vs ~50 for reads, well below macOS's 256 FD ceiling.
10521049
10531050
<!-- lore:019dabe5-3edd-773c-8c68-e382deb26191 -->
1054-
* **Identity-scoped response cache via fingerprint mixin**: Identity-scoped response cache: \`buildCacheKey(method, url)\` reads identity internally via memoized \`getIdentityFingerprint()\` — 2-arg signature. Uses MD5 of \`kind|secret\` truncated to 16 hex (local namespace, not auth). \`ANON\_IDENTITY = "\<anon>"\`. \`CacheEntry\` persists identity so \`invalidateCachedResponsesMatching(prefix)\` skips other identities. All invalidation helpers (\`invalidateCachedResponse\`, \`invalidateCachedResponsesMatching\`, \`invalidateIssue\*Caches\`, \`invalidateOrg\*Cache\`) are contractually no-throw — wrap body in try/catch so post-mutation failures can't mask successful API mutations. \`clearAuth()\` dynamically imports \`clearResponseCache\` to break db/auth ↔ response-cache cycle. Batch mutations: per-ID detail invalidation + single post-loop list sweep avoids N+1 scans.
1051+
* **Identity-scoped response cache via fingerprint mixin**: Identity-scoped response cache: \`buildCacheKey(method, url)\` reads identity internally via memoized \`getIdentityFingerprint()\` — 2-arg signature. Uses SHA-256 of \`kind|secret\` truncated to 16 hex (local namespace, not auth; MD5 rejected due to CodeQL broken-crypto taint). \`ANON\_IDENTITY = "\<anon>"\`. \`CacheEntry\` persists identity so \`invalidateCachedResponsesMatching(prefix)\` skips other identities. All invalidation helpers are contractually no-throw — wrap body in try/catch so post-mutation failures can't mask successful API mutations. \`clearAuth()\` dynamically imports \`clearResponseCache\` to break db/auth ↔ response-cache cycle. Batch mutations: per-ID detail invalidation + single post-loop list sweep avoids N+1 scans.
10551052
10561053
<!-- lore:019da644-b93a-777a-9b28-5cc837ff3ae8 -->
10571054
* **Isolated adapter coverage via fetch mocking in test/lib/**: To get CodeCov coverage on API-calling functions (e.g., hex-id-recovery adapters, api-client functions), write tests in \`test/lib/\*.coverage.test.ts\` or \`test/lib/\*.adapters.test.ts\` that mock \`globalThis.fetch\` via \`mockFetch()\` from \`test/helpers.js\`, call \`setAuthToken()\` + \`setOrgRegion()\` in \`beforeEach\`, and invoke the REAL function. Tests in \`test/e2e/\` or tests that stub the exports via \`spyOn\`/\`mock.module\` give ZERO coverage to the mocked function body. Use \`useTestConfigDir()\` for DB isolation. Pattern example: \`test/lib/api-client.coverage.test.ts\` and \`test/lib/hex-id-recovery.adapters.test.ts\`. Mock responses must include ALL Zod-required fields — minimal stubs fail schema validation with a noisy \`ApiError\`.

src/lib/db/auth.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,14 +321,12 @@ function computeIdentityFingerprint(): string {
321321
}
322322

323323
/**
324-
* 16-char SHA-256 hex of `kind|secret`. Not used for auth — just a
325-
* cache namespace. Truncation is fine: collisions are benign (two
326-
* colliding identities would share a cache slot, same as the
327-
* anonymous case) and we compute this once per process via
328-
* {@link getIdentityFingerprint} memoization.
324+
* 16-char MD5 hex of `kind|secret`. Not used for auth — just a cheap
325+
* cache namespace. Collisions are benign (identities would share a
326+
* cache slot, same as the anonymous case).
329327
*/
330328
function hashIdentity(kind: string, secret: string): string {
331-
return createHash("sha256")
329+
return createHash("md5")
332330
.update(`${kind}|${secret}`)
333331
.digest("hex")
334332
.slice(0, 16);

0 commit comments

Comments
 (0)