Skip to content

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

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

27Bslash6 merged 1 commit into
mainfrom
lab-5906-interop-forbid-double-dot

Conversation

@27Bslash6

@27Bslash6 27Bslash6 commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Interop/v1 key segments (namespace and operation) containing .. are now rejected, both at runtime and at compile time. The segment grammar ^[a-z0-9][a-z0-9._-]{0,63}$ allows .., but the CachekitIO server rejects .. anywhere in a key. Before this change, such keys were accepted locally and then failed on every CachekitIO request. A single . remains valid in any position, including trailing (for example app. or get.).

Modified public APIs

  • cachekit::interop::interop_key: returns CachekitError::InvalidKey when either namespace or operation contains ... The # Errors rustdoc now lists this case.
  • #[cachekit(...)] attribute macro: a namespace or interop literal containing .. is a compile error, spanned to the offending literal. The attribute docs describe the rule.

Implementation notes

  • In the private validate_segment (crates/cachekit/src/interop.rs), checks run in this order: grammar, then .., then reserved namespace (ns/nsapi). A segment that fails the grammar reports the grammar error, not the .. error.
  • Unlike the reservation check, the .. ban applies to both segment kinds.
  • Both runtime and macro errors contain the phrase must not contain "..": the CachekitIO server rejects ".." anywhere in a key. The tests assert on this text.
  • The rustdoc explains why checking each segment is enough. The : delimiters separate segments, and the args hash is hex, so any .. in a full key must lie inside a single segment.
  • The macro crate's mirror (parse_segment) is kept in sync, and the cross-reference comments in both crates now mention the .. ban.

Tests and fixtures

  • interop::tests::segment_rejects_double_dot: rejects a..b, ab.., a...b (namespace) and x..y, x.. (operation), and accepts app./users.fetch.by_id and app.v1/get..
  • cachekit-macros double_dot_segment_is_a_compile_error: equivalent coverage at the macro level.
  • tests/interop_vector_tests.rs: the header now references protocol interop-mode.json 1.2.0 (protocol PR chore(deps): update rust-dev-deps #94, sha256 7026137…a1f40). The count pins change from 34 to 35 key vectors and from 11 to 13 error vectors.
  • README.md (interop section) documents the rule.

Breaking change

Any existing interop namespace or operation containing .. now fails: interop_key returns InvalidKey, and #[cachekit] does not compile. Affected segments must be renamed, and their keys become a full cache miss. These keys already failed against CachekitIO, but other backends previously accepted them.


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

  • validate_segment (crates/cachekit/src/interop.rs) returns CachekitError::InvalidKey for a namespace or operation containing .., after the grammar check. The macro's compile-time mirror (parse_segment in crates/cachekit-macros/src/lib.rs) makes it a compile error for either namespace or interop. 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).
  • README.md (interop section), the interop module docs and the #[cachekit] attribute docs state the rule.
  • Tests: interop::tests::segment_rejects_double_dot (rejects a..b, x..y, x.., ab.., a...b; accepts app. and get.), cachekit-macros double_dot_segment_is_a_compile_error, and the vector suite's count pins (tests/interop_vector_tests.rs; the sha is pinned in its header).

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 fails: interop_key returns InvalidKey, and #[cachekit] does not compile. 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) (#98)

BREAKING CHANGE: an interop namespace or operation containing .. now fails: interop_key returns InvalidKey, and #[cachekit] does not compile. Rename the segment; its keys become a full cache miss.
END_COMMIT_OVERRIDE

Test plan

  • cargo fmt --all -- --check
  • cargo clippy --all-targets --features cachekitio,redis,encryption,l1,macros,memcached,file,tracing -- -D warnings
  • cargo test --features cachekitio,redis,encryption,l1,macros,memcached,file,tracing: all suites pass, including doc-tests
  • With the runtime check removed, segment_rejects_double_dot fails; with the macro check removed, double_dot_segment_is_a_compile_error fails

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.

validate_segment now returns CachekitError::InvalidKey for a namespace or
operation containing `..`, after the grammar check, and the macro's
compile-time mirror (parse_segment) makes it a compile error for either
`namespace` or `interop`. A lone `.` stays valid. The README 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 fails:
interop_key returns InvalidKey, and #[cachekit] does not compile. Rename the
segment; its keys become a full cache miss.
@coderabbitai

coderabbitai Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

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

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 20678b1b-7754-4fe6-b462-361ea8f18aba

📥 Commits

Reviewing files that changed from the base of the PR and between 86c1874 and 38f33a7.

📒 Files selected for processing (5)
  • README.md
  • crates/cachekit-macros/src/lib.rs
  • crates/cachekit/src/interop.rs
  • crates/cachekit/tests/interop_vector_tests.rs
  • crates/cachekit/tests/vectors/interop-mode.json

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

The runtime and macro validators now reject .. in either interop key segment. Documentation and interop vectors describe this rule and confirm that lone dots remain valid.

Changes

Interop key validation

Layer / File(s) Summary
Runtime and macro segment validation
crates/cachekit/src/interop.rs, crates/cachekit-macros/src/lib.rs, README.md
The runtime and macro validators reject .. in either segment. Documentation and tests cover the rule and retain acceptance of lone dots.
Interop vector updates
crates/cachekit/tests/vectors/interop-mode.json, crates/cachekit/tests/interop_vector_tests.rs
The fixture advances to version 1.2.0, adds vectors for valid lone dots and rejected double dots, and updates the checksum and expected vector counts.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 38f33

Interop keys containing .. will now fail validation, so affected callers must rename those segments; the updated runtime, macro, and vector coverage aligns with that intended change, leaving no actionable merge-blocking risk.

Security Architecture Review

Security architecture risk: ⚪ Minimal · up to 38f33

The change consistently narrows accepted inputs without adding a route around validation or increasing access to cached data. Callers using double-dot segments will now receive an error or fail compilation; lone dots remain valid.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The changed control applies to SDK callers constructing interop keys, including callers supplying dynamic segment strings. Within this boundary, it reduces accepted input rather than adding caller authority or downstream reachability.

Trust Boundaries and Controls

  • observed — Caller-supplied segment strings encounter full ASCII grammar, length, double-dot, and namespace-reservation checks before key generation. Direct runtime use cannot bypass these checks merely by avoiding the macro.

Resilience and Maintainability Implications

  • observed — Within interop_key, validation failure returns before argument encoding, hashing, or key return. This changed validation path does not perform a shared-state transition or leave a partially constructed persistent key.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 3 files. (2 skipped: 2…
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: rejecting double-dot interop segments. The breaking-change marker and issue reference are appropriate.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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.

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