Skip to content

Backend sprint 1.8.3 hygiene: /v1/events 204, signing-seeds TTL, 404 audit, auth-poll diagnostics, jsdelivr mirror#14

Merged
rainxchzed merged 9 commits into
mainfrom
backend-sprint-1.8.3
May 15, 2026
Merged

Backend sprint 1.8.3 hygiene: /v1/events 204, signing-seeds TTL, 404 audit, auth-poll diagnostics, jsdelivr mirror#14
rainxchzed merged 9 commits into
mainfrom
backend-sprint-1.8.3

Conversation

@rainxchzed
Copy link
Copy Markdown
Member

@rainxchzed rainxchzed commented May 15, 2026

Summary

Tier A + B tasks from the backend sprint brief. 8 logically-atomic commits, each independently revertable.

Changes

Commit Task
Deprecate /v1/events with 410 Gone and edge cache Tier A Task 1
Switch /v1/events from 410 Gone to 204 No Content to silence old-client retry storm Tier A Task 1 (operator follow-up — pre-1.8.3 clients treat non-2xx as failure and retry)
Bump signing-seeds cache TTL to 7d at the edge and add ETag revalidation Tier A Task 2
Add GET / greeting JSON so bare-hostname hits don't 404 Tier A Task 3
Add 410 Gone tombstones for legacy /repo/login/{device,oauth} paths Tier A Task 3
Cache unmatched 404s and log method+path for audit Tier A Task 3
Add fastly.jsdelivr.net to /v1/mirrors/list with traffic_kinds dispatch field Tier B Task 4 (fastgit.cc DROPPED — lineage unverified per CodeRabbit)
Log privacy-safe diagnostics on /v1/auth/device/poll Tier B Task 5

Cloudflare analytics → expected impact (30d window)

  • /v1/events 180k 4xx → 204 (no body, ~0 origin cost per call)
  • /v1/signing-seeds 1.15M requests + low hit rate → 86400/604800 TTL with ETag, expect Hit ratio >90% within 7d
  • 43.74k 404s split: deprecated-path 410s for /v1/repo/login/{device,oauth} (~110/week), root greeting for / (~54/week), edge-cached not_found JSON for the rest
  • Auth-stuck triage (issues #433, #395): per-request structured log [auth-poll rid=… ] dch=<sha256-prefix> ghs=<upstream-status> gh_err=<github-code> lat_ms=<ms> ua=<UA> — no token, no raw device_code

Mirror task — operator note

feat/mirrors-add-fastgit was the original branch with both mirrors. After CodeRabbit's trust concern about fastgit.cc, verification turned up no public artifact tying the .cc TLD to the FastGitORG team (their domains are .org + .xyz; .org is officially shut down). Dropped from the list. Whatsnew bullet at OpenHub-Store/GitHub-Store#599 was amended accordingly.

New traffic_kinds field on every mirror entry (additive; pre-1.8.3 clients ignore it). 1.8.3+ clients MUST consult this list before routing — jsDelivr is ["raw_file"]-only (no release assets under /gh/), whole-URL proxies stay ["release_asset", "raw_file"].

Test plan

  • Full Gradle test suite green
  • Compile clean
  • After merge: verify Cloudflare 4xx panel shows /v1/events drop within 48h
  • After merge: verify /v1/signing-seeds hit ratio rises within 7d
  • After merge: hit https://api.github-store.org/ and confirm greeting JSON
  • After merge: hit https://api.github-store.org/v1/repo/login/device and confirm 410 with use_instead hint
  • After merge: delete per-task branches: chore/v1-events-deprecation, perf/signing-seeds-ttl, chore/404-audit, ops/auth-poll-diagnostics, feat/mirrors-add-fastgit

Coordination

  • Client telemetry endpoint (TelemetryRepositoryImpl.postEvents) still calls /v1/events. 204 stops the spam; 1.8.3 client follow-up should add a sticky-disable-on-non-2xx flag, after which this endpoint can flip back to 410 Gone for a real signal
  • Signing-seeds ETag is optional client-side win — backend serves 304 if client sends If-None-Match
  • Mirror picker / download router on client must consult traffic_kinds before 1.8.3 release or jsdelivr will 404 release-asset URLs

Summary by CodeRabbit

  • New Features

    • Added root endpoint (GET /) with greeting and docs link
    • Mirror list now exposes traffic kinds for client routing
    • Signing seeds endpoint emits strong ETag and supports conditional GET (304)
  • Deprecated

    • Legacy /repo/login/device and /repo/login/oauth return 410 Gone
    • Telemetry POST /events disabled; now returns 204 No Content
  • Improvements

    • Unmatched-route 404s are logged and cacheable at edge
    • Auth device-poll logging improved to avoid sensitive token exposure
  • Tests

    • Expanded tests covering new behaviors and caching/ETag semantics

Review Change Stack

Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rainxchzed has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 15, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d7daf5eb-67e2-4d99-a084-86ae96ba90e8

📥 Commits

Reviewing files that changed from the base of the PR and between 91ca9f5 and df2cf41.

📒 Files selected for processing (4)
  • src/main/kotlin/zed/rainxch/githubstore/Plugins.kt
  • src/main/kotlin/zed/rainxch/githubstore/routes/BadgeRoutes.kt
  • src/main/kotlin/zed/rainxch/githubstore/routes/InternalRoutes.kt
  • src/test/kotlin/zed/rainxch/githubstore/StatusPagesOverrideTest.kt

📝 Walkthrough

Walkthrough

The PR updates the GitHub Store API surface by adding a new root greeting endpoint, refactoring centralized 404 handling with request logging, deprecating legacy OAuth/device-flow paths with 410 Gone responses, disabling event telemetry collection, adding mirror traffic-kind metadata, implementing conditional caching for signing seeds via ETags, enhancing device-flow poll diagnostics with structured telemetry, and making the device client testable through constructor injection of OAuth credentials.

Changes

API Route Updates and Deprecations

Layer / File(s) Summary
Root route and centralized 404 handling
src/main/kotlin/zed/rainxch/githubstore/routes/RootRoutes.kt, src/main/kotlin/zed/rainxch/githubstore/Plugins.kt, src/test/kotlin/zed/rainxch/githubstore/routes/RootRoutesTest.kt
New GET / endpoint returns a serializable RootGreeting with name, docs, and api fields, set with long-lived Cache-Control headers. Plugins.kt widens REQUEST_ID_KEY visibility to internal and introduces a shared respondNotFound(call) helper that logs request id + method/path, sets edge-cache headers, and returns consistent ApiError("not_found") JSON for both NotFoundException and unmatched-route 404s.
Legacy endpoint deprecation with 410 Gone
src/main/kotlin/zed/rainxch/githubstore/routes/DeprecationRoutes.kt, src/main/kotlin/zed/rainxch/githubstore/routes/Routing.kt, src/test/kotlin/zed/rainxch/githubstore/routes/DeprecationRoutesTest.kt
New DeprecationRoutes module registers GET/POST handlers for /repo/login/device and /repo/login/oauth returning 410 Gone with a DeprecatedAuthNotice payload (error, message, timestamp, replacement paths) and Cache-Control: public, max-age=86400. Routing integration places these static routes before parameterized repoRoutes to ensure precedence.
Events endpoint telemetry disablement
src/main/kotlin/zed/rainxch/githubstore/routes/EventRoutes.kt, src/main/kotlin/zed/rainxch/githubstore/Plugins.kt, src/main/kotlin/zed/rainxch/githubstore/routes/Routing.kt, src/test/kotlin/zed/rainxch/githubstore/routes/EventRoutesTest.kt
/v1/events POST now silently discards batches and returns 204 No Content instead of storing them; EventRepository parameter removed from eventRoutes() signature, associated validation/insertion logic deleted, and dedicated events rate-limiter bucket removed from RateLimit configuration. Tests verify that both valid JSON arrays and invalid payloads return 204.
Mirror traffic-kind metadata
src/main/kotlin/zed/rainxch/githubstore/mirrors/Mirror.kt, src/main/kotlin/zed/rainxch/githubstore/routes/MirrorRoutes.kt, src/test/kotlin/zed/rainxch/githubstore/mirrors/MirrorRoutesTest.kt
MirrorPreset gains trafficKinds: List<String> to declare which URL shapes each mirror supports; MirrorPresets adds a shared FULL_PROXY_KINDS list and assigns traffic kinds to each preset. MirrorEntry adds serialized traffic_kinds field; GET /mirrors/list populates it from preset values. Tests validate that each mirror exposes non-empty traffic kinds and that whole-URL proxies cover both release_asset and raw_file kinds.
Signing seeds conditional GET with ETags
src/main/kotlin/zed/rainxch/githubstore/routes/SigningSeedsRoutes.kt, src/test/kotlin/zed/rainxch/githubstore/match/SigningSeedsRouteTest.kt
GET /signing-seeds now computes a strong ETag from deterministic JSON canonicalization + SHA-256 hash, sets improved Cache-Control headers (long-lived, stale-while-revalidate), and handles If-None-Match conditional requests to return 304 Not Modified when tags match. Includes etagsMatch() helper to tolerate weak-prefix (W/) and comma-separated ETag lists. Tests verify ETag computation, 304 responses, wildcard/weak-tag handling, and stability across identical requests.
Device client testability via constructor injection
src/main/kotlin/zed/rainxch/githubstore/ingest/GitHubDeviceClient.kt
GitHubDeviceClient is now open with clientId moved to primary constructor (default sourced from GITHUB_OAUTH_CLIENT_ID env var with same validation). Methods startDeviceFlow() and pollDeviceToken() marked open for test subclassing, enabling route tests to inject fake client IDs without relying solely on environment configuration.
Device poll structured logging and diagnostics
src/main/kotlin/zed/rainxch/githubstore/routes/AuthRoutes.kt, src/test/kotlin/zed/rainxch/githubstore/routes/AuthPollDiagnosticsTest.kt
/auth/device/poll handler enhanced with structured telemetry: computes truncated stable hash prefix of device code, captures sanitized/limited User-Agent, retrieves request-id attribute, and logs detailed auth-poll event including upstream HTTP status, parsed GitHub error code (extracted safely without deserializing tokens), and latency. New DeviceErrorProbe DTO and lenient JSON parser extract error field only from upstream response. Comprehensive test suite verifies log output, confirms no token/device-code leaks, validates error code parsing, and tests 502 mapping for non-2xx upstream responses.
Routing tree wiring and integration
src/main/kotlin/zed/rainxch/githubstore/routes/Routing.kt
configureRouting() updated to call rootRoutes() at the top level, remove EventRepository import and Koin injection, invoke eventRoutes() without repository or rate-limiting wrapper, and insert deprecationRoutes() before repoRoutes() under /v1 to establish correct static-path precedence.
API surface documentation
CLAUDE.md
Documentation updated: endpoint table now includes GET / with caching guidance; /v1 list revised to show POST /events as deprecated 204 No Content with client retry guidance; added GET /mirrors/list and deprecated {GET,POST} /repo/login/{device,oauth} entries; clarified 404 caching and request-id logging behavior.

🎯 3 (Moderate) | ⏱️ ~25 minutes

A rabbit bounces forth with routes so bright, 🐰
Deprecated paths now bid farewell at night,
ETags cache the seeds, and polls report with care,
While mirrors know their traffic, endpoints everywhere!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: telemetry disablement (/v1/events 204), cache improvements (signing-seeds TTL), error handling (404 audit), diagnostics (auth-poll), and feature additions (jsdelivr mirror).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch backend-sprint-1.8.3

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/main/kotlin/zed/rainxch/githubstore/mirrors/Mirror.kt (1)

55-105: ⚡ Quick win

Consider extracting traffic-kind string literals to constants.

The strings "release_asset" and "raw_file" appear as literals in multiple locations (here, line 127, and test assertions). Extracting them to const val declarations would prevent typos and clarify the contract.

♻️ Proposed refactor
 object MirrorPresets {
 
     private const val PROBE_ASSET =
         "https://github.com/cli/cli/releases/download/v2.40.0/gh_2.40.0_checksums.txt"
 
+    const val TRAFFIC_KIND_RELEASE_ASSET = "release_asset"
+    const val TRAFFIC_KIND_RAW_FILE = "raw_file"
+    
-    private val FULL_PROXY_KINDS = listOf("release_asset", "raw_file")
+    private val FULL_PROXY_KINDS = listOf(TRAFFIC_KIND_RELEASE_ASSET, TRAFFIC_KIND_RAW_FILE)

Then update line 127 and test assertions to reference these constants.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/kotlin/zed/rainxch/githubstore/mirrors/Mirror.kt` around lines 55 -
105, Extract the repeated traffic-kind string literals into constants (e.g. add
const val RELEASE_ASSET = "release_asset" and const val RAW_FILE = "raw_file")
and replace the literal usages in FULL_PROXY_KINDS with these constants; update
any MirrorPreset initializations that currently reference the string literals
and adjust test assertions to import/reference RELEASE_ASSET and RAW_FILE
instead of hard-coded strings so all places (including the FULL_PROXY_KINDS list
and tests) use the shared constants.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/kotlin/zed/rainxch/githubstore/Plugins.kt`:
- Around line 339-340: Remove or narrow the global StatusPages 404 handler in
Plugins.kt (the status(HttpStatusCode.NotFound) block) because it overrides
route-level 404 bodies; either delete that handler and rely on route code
calling the centralized respondNotFound(call) helper, or refactor all explicit
404 responses in InternalRoutes (the handlers returning mapOf("error" to "Not
found")), BadgeRoutes (handlers returning "unknown kind: ..."), and
RepoRefreshRoutes (already using ApiError) to call respondNotFound(call) instead
so formats stay consistent; alternatively, if you want a global handler, change
it to only catch unmatched routes (if Ktor supports it) and leave route-level
not-found responses untouched.

---

Nitpick comments:
In `@src/main/kotlin/zed/rainxch/githubstore/mirrors/Mirror.kt`:
- Around line 55-105: Extract the repeated traffic-kind string literals into
constants (e.g. add const val RELEASE_ASSET = "release_asset" and const val
RAW_FILE = "raw_file") and replace the literal usages in FULL_PROXY_KINDS with
these constants; update any MirrorPreset initializations that currently
reference the string literals and adjust test assertions to import/reference
RELEASE_ASSET and RAW_FILE instead of hard-coded strings so all places
(including the FULL_PROXY_KINDS list and tests) use the shared constants.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: aef8d1da-a66d-4ad7-ba02-810256b8af73

📥 Commits

Reviewing files that changed from the base of the PR and between a27580a and 91ca9f5.

📒 Files selected for processing (17)
  • CLAUDE.md
  • src/main/kotlin/zed/rainxch/githubstore/Plugins.kt
  • src/main/kotlin/zed/rainxch/githubstore/ingest/GitHubDeviceClient.kt
  • src/main/kotlin/zed/rainxch/githubstore/mirrors/Mirror.kt
  • src/main/kotlin/zed/rainxch/githubstore/routes/AuthRoutes.kt
  • src/main/kotlin/zed/rainxch/githubstore/routes/DeprecationRoutes.kt
  • src/main/kotlin/zed/rainxch/githubstore/routes/EventRoutes.kt
  • src/main/kotlin/zed/rainxch/githubstore/routes/MirrorRoutes.kt
  • src/main/kotlin/zed/rainxch/githubstore/routes/RootRoutes.kt
  • src/main/kotlin/zed/rainxch/githubstore/routes/Routing.kt
  • src/main/kotlin/zed/rainxch/githubstore/routes/SigningSeedsRoutes.kt
  • src/test/kotlin/zed/rainxch/githubstore/match/SigningSeedsRouteTest.kt
  • src/test/kotlin/zed/rainxch/githubstore/mirrors/MirrorRoutesTest.kt
  • src/test/kotlin/zed/rainxch/githubstore/routes/AuthPollDiagnosticsTest.kt
  • src/test/kotlin/zed/rainxch/githubstore/routes/DeprecationRoutesTest.kt
  • src/test/kotlin/zed/rainxch/githubstore/routes/EventRoutesTest.kt
  • src/test/kotlin/zed/rainxch/githubstore/routes/RootRoutesTest.kt

Comment thread src/main/kotlin/zed/rainxch/githubstore/Plugins.kt
Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rainxchzed has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@rainxchzed rainxchzed merged commit 71ebd12 into main May 15, 2026
1 of 2 checks passed
@rainxchzed rainxchzed deleted the backend-sprint-1.8.3 branch May 15, 2026 17:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant