Skip to content

fix(interop)!: reject double-dot interop segments (LAB-5906) - #164

Merged
27Bslash6 merged 2 commits into
mainfrom
lab-5906-interop-forbid-double-dot
Sep 30, 2026
Merged

27Bslash6 merged 2 commits into
mainfrom
lab-5906-interop-forbid-double-dot

Conversation

@27Bslash6

@27Bslash6 27Bslash6 commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Interop segments (namespace and operation) containing .. are now rejected at wrap time on all backends. The interop/v1 grammar ^[a-z0-9][a-z0-9._-]{0,63} allows such segments, but the CachekitIO server rejects ..anywhere in a key. Before this change the SDK could produce a key that returned400` on every CachekitIO request while still working on other backends.

Public API changes

  • validateInteropSegment(kind, value) (serialization/interop.ts)
    • Now throws ConfigurationError when value contains ...
    • Check order: the type check, then the grammar check, then the new .. check, then the reserved-namespace (ns / nsapi) check.
    • Error message: Invalid interop <kind> "<value>": must not contain '..' — the CachekitIO server rejects '..' anywhere in a key.
    • The @throws JSDoc lists the new condition.
    • A lone . is still valid, including a trailing one (e.g. app.).
  • cache.wrap with interop
    • Inherits the new check through validateInteropSegment, so it throws for a .. namespace or operation.
    • generateInteropKey also goes through this validation path.
  • WrapOptions.interop JSDoc (types/cache.ts, shipped in .d.ts) now states that neither segment may contain .. and that a single . is allowed.

Because : delimits segments and the hash is hex, any .. in a full key must fall inside a segment. Validating the segments is therefore enough to prevent server-side traversal rejections.

Tests and fixtures

  • cache.interop.test.ts
    • wrap throws for namespace a..b and for operation x..y.
    • Namespace app. with operation users.fetch.by_id (arity 1) writes exactly the pinned key app.:users.fetch.by_id:405f09a3…e21a, matching the lone_dots_stay_valid vector.
  • interop-mode.protocol.test.ts
  • .secrets.baseline: only line-number shifts for existing fixture entries and a new generated_at timestamp. No new secrets.

Breaking change

Any existing interop namespace or operation containing .. now fails with ConfigurationError at wrap time. Such segments must be renamed, and keys under the new name start as a full cache miss.


Summary

Updates the JSDoc for the public generateInteropKey() function in packages/cachekit/src/serialization/interop.ts. The documentation now states that a ConfigurationError is thrown when namespace or operation contains .., in addition to the existing cases (segment-grammar violations and the reserved namespaces ns and nsapi).

Public API

  • generateInteropKey(): The @throws {ConfigurationError} contract now explicitly covers segments containing ... The function signature is unchanged.

Notes

  • The diff contains only this documentation change. It does not include any validation logic that rejects ... Such enforcement may already exist elsewhere, for example in the segment-grammar check, or it may be missing from this diff.
  • The PR title marks this as a breaking change (!). Callers who currently pass namespace or operation values containing .. should expect a ConfigurationError once the documented behavior is enforced.

Summary

The interop/v1 segment pattern admits .. inside a segment (a..b), but the CachekitIO server rejects .. anywhere in a key (cache-key-format.md → Server-Side Requirements, the Traversal row). So this SDK accepted such a segment and minted a key that fails with 400 on every CachekitIO request, while the same key works on other backends. cachekit-io/protocol#94 forbids .. in either segment; this PR implements it.

Changes

  • validateInteropSegment (packages/cachekit/src/serialization/interop.ts) throws ConfigurationError for a namespace or operation containing .., after the grammar check, on every backend. generateInteropKey and cache.wrap both go through it. A lone . stays valid, including at the end of a segment.
  • Re-vendors interop-mode.json 1.2.0 byte-for-byte from cachekit-io/protocol#94 (sha256 702613766d1b92bc3a337627a96b9aedc89abfeb4d9208c2bb00c9539a0a1f40; 35 key / 13 error vectors) and updates the sha and count pins. The new vectors are reject_double_dot_namespace (a..b), reject_double_dot_operation (x..) and lone_dots_stay_valid (app. / users.fetch.by_id).
  • The WrapOptions.interop JSDoc (types/cache.ts, shipped in .d.ts) states the rule.
  • Tests: src/cache.interop.test.ts (wrap throws for a .. namespace and operation; namespace app. with operation users.fetch.by_id writes the lone_dots_stay_valid key), and the vector suite's sha and count pins (test/protocol/interop-mode.protocol.test.ts).
  • .secrets.baseline: fixture line numbers shift; no new entries.

Merge order

Merge cachekit-io/protocol#94 first. The vendored fixture must stay byte-identical to test-vectors/interop-mode.json at its merge commit (sha256 above).

Breaking

An interop namespace or operation containing .. now throws ConfigurationError at wrap time, on every backend. Rename the segment; its keys become a full cache miss. Before this change, such a key already failed on CachekitIO.

Release notes read the breaking note from this block:

BEGIN_COMMIT_OVERRIDE
fix(interop)!: reject double-dot interop segments (LAB-5906) (#164)

BREAKING CHANGE: an interop namespace or operation containing .. now throws ConfigurationError at wrap time, on every backend; the exported generateInteropKey throws it at call time. Rename the segment; its keys become a full cache miss.
END_COMMIT_OVERRIDE

Test plan

  • pnpm lint, pnpm format:check, pnpm type-check, pnpm type-check:tests
  • pnpm vitest run in packages/cachekit: 1184 passed, 1 skipped
  • With the new check removed, both reject_double_dot_* vectors and the wrap-time test fail

The interop segment pattern admits `..` inside a segment (`a..b`), but the
CachekitIO server rejects `..` anywhere in a key (protocol
spec/cache-key-format.md#server-side-requirements, Traversal row), so such a
key failed with 400 on every request while working on other backends.

validateInteropSegment now throws ConfigurationError for a namespace or
operation containing `..`, after the grammar check, on every backend. A lone
`.` stays valid. The WrapOptions.interop JSDoc states the rule.

Re-vendors test-vectors/interop-mode.json 1.2.0 byte-for-byte from
cachekit-io/protocol#94 (sha256 702613766d1b92bc3a337627a96b9aedc89abfeb4d9208c2bb00c9539a0a1f40;
35 key / 13 error vectors) and updates the sha and count pins.

BREAKING CHANGE: an interop namespace or operation containing `..` now throws
ConfigurationError at wrap time, on every backend. Rename the segment; its
keys become a full cache miss.
@coderabbitai

coderabbitai Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 23 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: cachekit-io/cachekit-ts/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: ab7bea6a-dc28-404b-a648-a0518ecb0406

📥 Commits

Reviewing files that changed from the base of the PR and between c9318ad and f15d3b6.

📒 Files selected for processing (6)
  • .secrets.baseline
  • packages/cachekit/src/cache.interop.test.ts
  • packages/cachekit/src/serialization/interop.ts
  • packages/cachekit/src/types/cache.ts
  • packages/cachekit/test/protocol/fixtures/interop-mode.json
  • packages/cachekit/test/protocol/interop-mode.protocol.test.ts

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.

@kodus-27b

kodus-27b Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Code Review Completed! 🔥

The code review was successfully completed based on your current configurations.

Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the `@kody start-review` command at the root of your PR.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Providing Context (Files & MCPs)

Add these hints in your PR description (or a comment) to unlock deeper checks:

  • Ticket / Acceptance Criteria: `Refs: ABC-123` (Linear/Jira/Asana/ClickUp/Trello) or a direct ticket link.
  • Bugfix Validation: a Sentry/Datadog/Bugsnag event link (or paste the stack trace/error message).
  • Endpoint Risk: mention the route (e.g., `POST /api/payments`) or controller/action name.
  • Attach a repo file as context: use an explicit marker like `@file:docs/guide.mdx#L10-L50` (replace with your real path).
  • API Contract Docs: include `@file:openapi.yaml` or `@file:swagger.json` when changing routes/schemas.
  • Definition of Done / Standards: include `@file:DOD.md` or `@file:CONTRIBUTING.md` if your repo has them.
  • Design System Source of Truth: include `@file:ui/index.ts` (replace with your DS entrypoint path).
  • Feature Flags: include the flag key/name and `@file:flags.ts` / `@file:config.json` (and optionally the PostHog flag name).
  • Edge/CDN Rules: link the Cloudflare rule/zone or describe the intended redirect/header behavior.
  • Attach an MCP tool output: use `@mcp<provider|tool>` (replace with an installed MCP provider + tool, e.g., `@mcp<sentry|events.search>`).
Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug ✅
Performance ✅
Security ✅
Business Logic ✅

Access your configuration settings here.

kodus-27b[bot]
kodus-27b Bot previously approved these changes Sep 30, 2026
@codecov

codecov Bot commented Sep 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@kodus-27b

kodus-27b Bot commented Sep 30, 2026

Copy link
Copy Markdown

Code Review Completed! 🔥

The code review was successfully completed based on your current configurations.

Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the `@kody start-review` command at the root of your PR.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Providing Context (Files & MCPs)

Add these hints in your PR description (or a comment) to unlock deeper checks:

  • Ticket / Acceptance Criteria: `Refs: ABC-123` (Linear/Jira/Asana/ClickUp/Trello) or a direct ticket link.
  • Bugfix Validation: a Sentry/Datadog/Bugsnag event link (or paste the stack trace/error message).
  • Endpoint Risk: mention the route (e.g., `POST /api/payments`) or controller/action name.
  • Attach a repo file as context: use an explicit marker like `@file:docs/guide.mdx#L10-L50` (replace with your real path).
  • API Contract Docs: include `@file:openapi.yaml` or `@file:swagger.json` when changing routes/schemas.
  • Definition of Done / Standards: include `@file:DOD.md` or `@file:CONTRIBUTING.md` if your repo has them.
  • Design System Source of Truth: include `@file:ui/index.ts` (replace with your DS entrypoint path).
  • Feature Flags: include the flag key/name and `@file:flags.ts` / `@file:config.json` (and optionally the PostHog flag name).
  • Edge/CDN Rules: link the Cloudflare rule/zone or describe the intended redirect/header behavior.
  • Attach an MCP tool output: use `@mcp<provider|tool>` (replace with an installed MCP provider + tool, e.g., `@mcp<sentry|events.search>`).
Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug ✅
Performance ✅
Security ✅
Business Logic ✅

Access your configuration settings here.

@27Bslash6
27Bslash6 merged commit 4ae5c90 into main Sep 30, 2026
16 checks passed
@27Bslash6
27Bslash6 deleted the lab-5906-interop-forbid-double-dot branch September 30, 2026 06:06
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