Skip to content

refactor: add control-plane cache store abstraction#564

Open
ColeMurray wants to merge 1 commit intomainfrom
refactor/cache-store-abstraction
Open

refactor: add control-plane cache store abstraction#564
ColeMurray wants to merge 1 commit intomainfrom
refactor/cache-store-abstraction

Conversation

@ColeMurray
Copy link
Copy Markdown
Owner

@ColeMurray ColeMurray commented Apr 26, 2026

Summary

  • Add a control-plane CacheStore interface with a KV-backed implementation.
  • Convert GitHub installation token caching and source-control provider injection to depend on CacheStore instead of KVNamespace.
  • Leave direct repo list cache and bot KV usages for later follow-up; reviewed remaining usages for compatibility.

Verification

  • npm test -w @open-inspect/control-plane -- src/auth/github-app.test.ts
  • npm run typecheck -w @open-inspect/control-plane

Created with Open-Inspect

Summary by CodeRabbit

  • Refactor
    • Refactored internal caching layer to use a standardized cache abstraction interface for improved consistency across token persistence operations.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 26, 2026

📝 Walkthrough

Walkthrough

This PR introduces a CacheStore abstraction interface to decouple cache operations from Cloudflare's KV storage. A createKvCacheStore adapter wraps KVNamespace into the new interface. All references to kvCache and direct KV usage are refactored to use the abstracted CacheStore across the GitHub provider and related modules.

Changes

Cohort / File(s) Summary
Cache Abstraction
packages/control-plane/src/cache/cache-store.ts
Introduces new exported CacheStore interface with get<T>(), put(), and delete() methods. Adds createKvCacheStore() function to wrap KVNamespace into a CacheStore adapter.
GitHub App Refactoring
packages/control-plane/src/auth/github-app.ts, packages/control-plane/src/auth/github-app.test.ts
Replaces kvCache with cacheStore in token caching logic. Updates cache bindings interface from REPOS_CACHE: KVNamespace to cacheStore: CacheStore. Modifies test to use FakeCacheStore instead of FakeKvNamespace.
Provider Configuration
packages/control-plane/src/source-control/providers/types.ts, packages/control-plane/src/source-control/providers/github-provider.ts
Updates GitHubProviderConfig interface to use cacheStore?: CacheStore instead of kvCache?: KVNamespace. Adapts provider constructor to consume and pass the new cache abstraction to helper functions.
Integration Points
packages/control-plane/src/routes/shared.ts, packages/control-plane/src/session/durable-object.ts
Wraps env.REPOS_CACHE using createKvCacheStore() before passing to source control provider and token retrieval helpers, replacing direct KV namespace injection.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A cache runs swift, now dressed in new attire,
From KV's grasp to Store's lighter desire,
Abstraction blooms where concrete once did stay,
The token hops through layers, light as day! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% 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 accurately describes the main change: introducing a CacheStore abstraction for control-plane cache management, replacing KVNamespace dependencies across multiple modules.
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 refactor/cache-store-abstraction

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.

@github-actions
Copy link
Copy Markdown

Terraform Validation Results

Step Status
Format
Init
Validate

Note: Terraform plan was skipped because secrets are not configured. This is expected for external contributors. See docs/GETTING_STARTED.md for setup instructions.

Pushed by: @ColeMurray, Action: pull_request

Copy link
Copy Markdown
Contributor

@open-inspect open-inspect Bot left a comment

Choose a reason for hiding this comment

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

Summary

This PR introduces a small CacheStore abstraction in the control-plane and rewires GitHub installation-token caching and provider construction to depend on it instead of KVNamespace directly. The refactor is behavior-preserving in the reviewed paths, and the cache semantics, error handling, and token TTL logic remain intact.

  • PR Title and number: refactor: add control-plane cache store abstraction (#564)
  • Author: @ColeMurray
  • Files changed count, additions/deletions: 7 files, +51 / -33
  • Verification: npm test -w @open-inspect/control-plane -- src/auth/github-app.test.ts passed (9 tests), and npm run typecheck -w @open-inspect/control-plane passed.

Critical Issues

None.

Suggestions

  • [Testing] packages/control-plane/src/cache/cache-store.ts:1 - This abstraction is now part of the control-plane wiring, but the added test coverage only exercises getCachedInstallationToken with a fake store. A small focused test around provider wiring or createKvCacheStore() would help catch future drift if the abstraction expands beyond installation-token caching.

Nitpicks

None.

Positive Feedback

  • The refactor keeps the cache failure behavior unchanged, which is important on auth-critical paths.
  • The call-site updates are minimal and consistent, which keeps the new abstraction easy to reason about.
  • The renamed local variables in getCachedInstallationToken() improve clarity by separating persistent cache reads from the in-memory cache.

Questions

None.

Verdict

Approve: Ready to merge, no blocking issues.

Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
packages/control-plane/src/session/durable-object.ts (1)

583-589: Optional: hoist the cacheStore wrapper out of the per-call closure.

A fresh createKvCacheStore(this.env.REPOS_CACHE) is allocated every time getCloneToken() is invoked. The wrapper is stateless (the in-memory token cache and in-flight map live in github-app.ts), so the duplication is harmless, but constructing it once and capturing it in the closure is cleaner and matches createSourceControlProvider above.

♻️ Hoist wrapper
+            const cacheStore = createKvCacheStore(this.env.REPOS_CACHE);
             const getCloneToken: () => Promise<string | null> =
               scmProvider === "gitlab"
                 ? () => Promise.resolve(this.env.GITLAB_ACCESS_TOKEN ?? null)
                 : appConfig
-                  ? () =>
-                      getCachedInstallationToken(appConfig, {
-                        cacheStore: createKvCacheStore(this.env.REPOS_CACHE),
-                      })
+                  ? () => getCachedInstallationToken(appConfig, { cacheStore })
                   : () => Promise.resolve(null);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/control-plane/src/session/durable-object.ts` around lines 583 - 589,
The per-call closure currently constructs a new cache wrapper each time
(createKvCacheStore(this.env.REPOS_CACHE)) when returning the
getCachedInstallationToken path; hoist that wrapper into a single const (e.g.
const reposCacheStore = createKvCacheStore(this.env.REPOS_CACHE)) captured by
the outer scope of getCloneToken so the closure reuses reposCacheStore instead
of allocating a fresh one on every invocation; update the branch that calls
getCachedInstallationToken(appConfig, { cacheStore: ... }) to pass
reposCacheStore.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/control-plane/src/session/durable-object.ts`:
- Around line 583-589: The per-call closure currently constructs a new cache
wrapper each time (createKvCacheStore(this.env.REPOS_CACHE)) when returning the
getCachedInstallationToken path; hoist that wrapper into a single const (e.g.
const reposCacheStore = createKvCacheStore(this.env.REPOS_CACHE)) captured by
the outer scope of getCloneToken so the closure reuses reposCacheStore instead
of allocating a fresh one on every invocation; update the branch that calls
getCachedInstallationToken(appConfig, { cacheStore: ... }) to pass
reposCacheStore.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 97097ea7-7f73-48d2-af72-74c8bb18d3a1

📥 Commits

Reviewing files that changed from the base of the PR and between a2db39a and fb50205.

📒 Files selected for processing (7)
  • packages/control-plane/src/auth/github-app.test.ts
  • packages/control-plane/src/auth/github-app.ts
  • packages/control-plane/src/cache/cache-store.ts
  • packages/control-plane/src/routes/shared.ts
  • packages/control-plane/src/session/durable-object.ts
  • packages/control-plane/src/source-control/providers/github-provider.ts
  • packages/control-plane/src/source-control/providers/types.ts

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