Skip to content

fix(web-shared): report failed blacklisted-domain config reads - #8328

Merged
iscekic merged 1 commit into
mainfrom
drain/blacklist-config-failure-reporting
Oct 23, 2026
Merged

iscekic merged 1 commit into
mainfrom
drain/blacklist-config-failure-reporting

Conversation

@iscekic

@iscekic iscekic commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator

Change

Reading the operator-maintained domain list (packages/web-shared/src/lib/blacklist-domains-config.ts)
now reports a failed or unreadable read and keeps the last list it read successfully.

  • The Redis read and the stored-payload parse run in one fetcher that logs through
    errorExceptInTest and calls
    captureException(error, { tags: { source: 'blacklist_domains_config' } }) when the read or the
    payload is unusable, then rethrows.
  • createCachedFetch keeps its contracts: the last successfully read list is served, concurrent
    callers share one failed refresh, and the next attempt happens after the shared 30s failure
    backoff (fix(web-shared): share in-flight fetches and back off failures in createCachedFetch #7881) instead of once per auth check.
  • Before the first successful read, the resolved list is the BLACKLIST_DOMAINS value.
  • Authorization decisions are unchanged: isUserBlacklistedByDomain and the denial in
    validateUserAuthorization are not touched.

Tests

packages/web-shared/src/lib/blacklist-domains-config.test.ts (new, runs under the web Jest config):

case assertion
stored list returned, nothing reported
read fails after a good read earlier list kept, reported once; callers inside the backoff window add no second read and no second report
first read fails reported, BLACKLIST_DOMAINS served
stored payload unreadable reported, earlier list kept
  • pnpm --filter web exec jest --runInBand packages/web-shared/src/lib/blacklist-domains-config.test.ts → 4 passed.
  • With the source change stashed, 3 of the 4 fail.
  • pnpm --filter @kilocode/web-shared typecheck passes.

End-to-end evidence (local dev stack on this VM)

pnpm dev:start core (Next.js :3000, Postgres, redis, redis-http), two fake accounts seeded in the
local database, a test-only domain in the local admin:blacklisted-domains key, Chromium through
@playwright/test. The Redis read takes the same code path the app uses.

  1. Redis healthy: the account in the listed domain is denied at sign-in
    (/users/sign_in?error=BLOCKED, server log SECURITY: Blacklisted); the other account signs in
    and GET /api/user → 200.
  2. docker stop dev-redis-http-1, then past the 60s cache TTL: the listed-domain account is still
    denied (?error=BLOCKED); the other account still signs in (/profile) and GET /api/user → 200.
    dev/logs/nextjs.log gains
    [blacklist-domains] Failed to read the blacklisted domains: [TypeError: fetch failed] … ECONNREFUSED 127.0.0.1:8079.
  3. docker start dev-redis-http-1, past the backoff window: normal behavior, no new failure lines.
  4. Stored payload replaced with unreadable JSON: the listed-domain account is still denied and the log
    gains the parse failure with its stack.

Limitation: Sentry delivery is not observable on the local stack (no DSN), so the unit test asserts
the captureException call instead.

Proxy answers

The owner's proxy gave these answers in the owner's place.

  1. Question: Cold failure: When the very first blacklist read of a process fails and BLACKLIST_DOMAINS is unset, what should the auth gate do?
    Answer: Serve env list, report failure
    Confidence: 0.85 · Precedent: Fix the root cause on every affected surface (session 7f3470e0ba6f: "fix class of issue preventing progress"). The brief also says to return the BLACKLIST_DOMAINS list and report the failure before the first good read.
  2. Question: Retry cadence: How soon should a failed blacklist read be retried?
    Answer: Keep the shared 30s backoff
    Confidence: 0.65 · Precedent: Trust the code over documents, because documents can be stale (session 269375d6e466: "those documents may be stale, only trust code"). The fix(web-shared): share in-flight fetches and back off failures in createCachedFetch #7881 backoff landed after this item was filed and prevents amplification during an outage.
  3. Question: Reporting: How should the failed read be reported?
    Answer: error ExceptInTest + captureException
    Confidence: 0.80 · Precedent: Prefer existing libraries and patterns to hand-rolled code (session df491946927a: "we will try and use libraries wherever we can"). This matches custom-llm-catalog.ts and the brief's use of the existing logging and Sentry helpers.

readBlacklistedDomains logs and captures the failure through the existing
helpers, then rethrows so createCachedFetch keeps serving the last list it
read successfully and retries after the shared failure backoff. Before the
first successful read the BLACKLIST_DOMAINS value is still served.

Tests cover a stored list, a failure after a good read, a failing first read,
and an unreadable stored payload.
@iscekic iscekic added drain Work item from the findings drain janitor:trust Janitor finding: trust boundary hardening labels Oct 20, 2026
@kilo-code-bot

kilo-code-bot Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The change only adds failure reporting around the existing blacklist domain read; createCachedFetch still supplies the last-known-good or BLACKLIST_DOMAINS fallback, and the new tests cover the stored, failed-refresh, cold-failure, and unreadable-payload paths.

Notes

  • readBlacklistedDomains rethrows after errorExceptInTest + captureException, so createCachedFetch's stale-while-revalidate/backoff behavior in packages/web-shared/src/lib/cached-fetch.ts is preserved; no duplicate Sentry report since errorExceptInTest only logs.
  • Authorization paths (isUserBlacklistedByDomain, validateUserAuthorization) are untouched.
  • Files were reviewed statically; tests were not executed in this sandbox (no installed dependencies).
Files Reviewed (2 files)
  • packages/web-shared/src/lib/blacklist-domains-config.ts
  • packages/web-shared/src/lib/blacklist-domains-config.test.ts

Reviewed by deepseek-v4.1-flash-1017 · Input: 39.3K · Output: 10.1K · Cached: 693.2K

Review guidance: REVIEW.md from base branch main

@iscekic iscekic added the merge:human Substantive functional risk requires human review. label Oct 20, 2026
@iscekic
iscekic enabled auto-merge October 20, 2026 21:46
@iscekic iscekic added the intent:ok Janitor change confirmed as a real bug fix, not intended behavior label Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

drain Work item from the findings drain intent:ok Janitor change confirmed as a real bug fix, not intended behavior janitor:trust Janitor finding: trust boundary hardening merge:human Substantive functional risk requires human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants