Skip to content

test: credential redaction verification and metadata filter fuzz hard… - #147

Merged
wpak-ai merged 5 commits into
cppalliance:mainfrom
jonathanMLDev:test/redaction-and-filter-fuzz
Jun 10, 2026
Merged

test: credential redaction verification and metadata filter fuzz hard…#147
wpak-ai merged 5 commits into
cppalliance:mainfrom
jonathanMLDev:test/redaction-and-filter-fuzz

Conversation

@jonathanMLDev

@jonathanMLDev jonathanMLDev commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

Item 5 (week_plan_v1) closes two pre-1.0 security gaps: MCP tool responses now sanitize known credential-bearing fields before JSON serialization, and the metadata filter validator rejects degenerate/oversized inputs with structured errors instead of passing them through to Pinecone. Property-based fuzz tests (fast-check) and targeted redaction tests lock in the behavior.

Issues addressed

Changes

5a — Credential redaction

  • redactApiKey() extended with pcsk_[A-Za-z0-9_-]{40,} pattern for modern Pinecone keys
  • New exported redactSensitiveFields() — key-targeted walk over message, suggestion, degradation_reason (preserves document UUIDs in metadata)
  • jsonResponse / jsonErrorResponse sanitize payloads before JSON.stringify (single choke point for all 9 tools)
  • Defense-in-depth: rerank.ts redacts SDK error text when building degradation_reason
  • docs/SECURITY.md documents MCP response redaction (not only stderr)

5b — Metadata filter hardening + fuzz

  • MAX_FILTER_DEPTH = 10 with explicit depth counter (depth 10 passes, 11 rejects)
  • Reject empty $and, $or, $in, $nin with clear validation messages
  • fast-check dev dependency + metadata-filter.fuzz.test.ts (4 properties × 100 runs)
  • metadata-filter.test.ts regression cases for depth boundary and empty-array guards

Acceptance criteria

#136 (5a — redaction)

  • Tool error message and suggestion redacted in MCP responses
  • HybridQueryResult.degradation_reason redacted (query handler + jsonResponse)
  • guided_query response path redacts result.degradation_reason (sensitive fields flow through jsonResponse)
  • classifyToolCatchError catch-all redacted in DEBUG mode via jsonErrorResponse
  • Tests use realistic pcsk_… fixtures
  • Bypass paths fixed: tool-response.ts, rerank.ts, logger.ts

#137 (5b — filter fuzz)

  • Fuzz coverage: depth 10+, empty combinators, $in 0/1000+, special field names, unknown operators, invalid $in elements
  • Malformed inputs return structured validator errors (no throw); end-to-end VALIDATION on query for empty $in
  • Valid complex filters (3+ nesting levels) pass unchanged
  • ≥ 100 generated cases via fast-check
  • Tests pass locally (211/211)
  • PR approved by at least 1 reviewer

Test plan

  • npm test — 211 tests pass
  • npm run test:coverage — passes
  • npm run typecheck / npm run lint / npm run build — pass
  • redaction.test.tspcsk_, UUID, Bearer, DEBUG-mode errors, degradation_reason, UUID preservation
  • metadata-filter.fuzz.test.ts — never-throws, malformed→error, valid grammar, special keys, large $in
  • metadata-filter.test.ts — depth 10/11 boundary, empty $and/$or/$in/$nin
  • CI green on PR

Notes for reviewers

  • redactSensitiveFields is not the same as private redactValue: logs redact every string; MCP responses redact only allowlisted keys so search-result metadata UUIDs are preserved.
  • decision_trace.explanation is intentionally excluded from the sensitive key list (routing text, not SDK error output).
  • Depth is measured by an explicit depth parameter on validateMetadataFilterRecord (not path.length), incremented at each $and/$or nested record.- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Summary by CodeRabbit

  • New Features

    • Enhanced redaction of sensitive data in logs and tool responses, including additional API key token formats.
  • Bug Fixes

    • Stricter validation for nested metadata filters with depth limits enforcement.
    • Improved error message sanitization to prevent API key exposure.
  • Documentation

    • Updated security guidance for log redaction and response sanitization practices.
  • Tests

    • Added comprehensive test coverage for redaction behavior and metadata filter validation.

@jonathanMLDev jonathanMLDev self-assigned this Jun 9, 2026
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jonathanMLDev, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 42 minutes and 18 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1acb7353-36a6-4526-9dcc-d26d9283283c

📥 Commits

Reviewing files that changed from the base of the PR and between 687a9a6 and 39e7f61.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • docs/SECURITY.md
  • package.json
  • src/core/pinecone/rerank.ts
  • src/core/server/metadata-filter.fuzz.test.ts
  • src/core/server/metadata-filter.test.ts
  • src/core/server/metadata-filter.ts
  • src/core/server/redaction.test.ts
  • src/core/server/tool-response.ts
  • src/logger.ts
📝 Walkthrough

Walkthrough

This PR hardens credential redaction across all tool output paths and introduces validated, depth-limited metadata filter validation. It adds redactSensitiveFields() to sanitize tool response JSON before serialization, extends the metadata filter validator with depth limits and stricter operator rules, and provides comprehensive test coverage including property-based fuzz testing.

Changes

Credential Redaction and Metadata Filter Validation Hardening

Layer / File(s) Summary
Core redaction utilities with pcsk_ pattern and deep-copy sanitization
src/logger.ts
redactApiKey() now masks modern pcsk_... Pinecone key format; new redactSensitiveFields() function recursively deep-copies values, redacting only string values at sensitive object keys using redactApiKey(), and handling circular references.
Metadata filter depth limits and operator validation rules
src/core/server/metadata-filter.ts
Exports MAX_FILTER_DEPTH = 10 constant; extends recursive validator to thread depth through nested $and/$or operators and reject filters exceeding max depth; requires non-empty arrays for $in/$nin/$and/$or with structured error reporting; tightens primitive-array validation.
Tool response redaction at serialization boundary
src/core/pinecone/rerank.ts, src/core/server/tool-response.ts
jsonResponse() and jsonErrorResponse() apply redactSensitiveFields() before JSON stringification; rerankResults() redacts API keys from degradation reason fallback strings to prevent leakage in error fallbacks.
Metadata filter unit tests for depth and operator boundaries
src/core/server/metadata-filter.test.ts
Tests validate filters at max depth pass; exceeding depth produces "maximum depth" error; empty $and/$or and empty $in/$nin arrays are rejected with field and message details; includes deepAnd() helper for test fixture construction.
Redaction test suite covering all output paths and MCP responses
src/core/server/redaction.test.ts
Vitest suite with mocked Pinecone client verifying redactApiKey() masks Pinecone key patterns, UUID tokens, api_key assignments, and Authorization: Bearer strings; redactSensitiveFields() redacts sensitive keys while preserving allowlisted metadata UUIDs; tool response constructors redact degradation_reason and error/suggestion content while preserving non-sensitive metadata.
Property-based fuzz testing of metadata filter validator
src/core/server/metadata-filter.fuzz.test.ts
Fast-check property tests covering arbitrary JSON-like inputs (never-throw), malformed filters (produce VALIDATION errors), deeply nested valid filters (within depth limit pass), special field names, and $in edge cases (reject empty, accept large arrays).
Documentation updates and dev dependency additions
package.json, docs/SECURITY.md
Adds fast-check ^4.8.0 to devDependencies; expands security guidance with concrete log redaction patterns for pcsk_... keys, UUID tokens, assignment patterns, and Bearer tokens; documents MCP response redaction behavior and metadata preservation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • wpak-ai
  • whisper67265
  • AuraMindNest

Poem

🐰 A rabbit hops through secrets deep,
Redacting keys in heaps and heaps—
Depth limits guard the nested ways,
While tests fuzz out suspicious strays.
No API keys shall leak today!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 69.23% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is vague and truncated, using "fuzz hard…" which does not convey meaningful information about the changeset. Complete the title and make it more descriptive, e.g., 'test: add credential redaction and metadata filter fuzz tests' to clearly summarize the main changes.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed All acceptance criteria from issues #136 and #137 are implemented: credential redaction across paths with pcsk_ key support, redactSensitiveFields export, payload sanitization in tool responses, metadata filter depth limits, empty array rejection, and 100+ fuzz test cases via fast-check.
Out of Scope Changes check ✅ Passed All changes directly support the linked issues: credential redaction, metadata filter fuzz testing, depth constraints, and related documentation updates are all in scope.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (2)
src/core/server/metadata-filter.test.ts (2)

90-94: ⚖️ Poor tradeoff

Consider extracting deepAnd to a shared test utility.

The deepAnd helper is duplicated between this file and metadata-filter.fuzz.test.ts (lines 28-31). Extracting it to a shared test utility module would eliminate duplication and provide a single source of truth.

🤖 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/core/server/metadata-filter.test.ts` around lines 90 - 94, The deepAnd
helper is duplicated; extract the function deepAnd(levels: number):
Record<string, unknown> into a shared test utility module (e.g.,
tests/util/filters or similar), export it, and replace the local implementations
in both metadata-filter.test.ts and metadata-filter.fuzz.test.ts with an import
of that shared deepAnd; ensure the exported helper has the same signature and
semantics so existing tests (which call deepAnd) require no other changes.

54-63: ⚡ Quick win

Use MAX_FILTER_DEPTH constant instead of hardcoding depth values.

The depth values 10 and 11 are hardcoded here, but the fuzz test file correctly imports and uses MAX_FILTER_DEPTH from the validator module. If the maximum depth ever changes, these hardcoded values will become incorrect.

♻️ Refactor to use the constant
 import { describe, expect, it } from 'vitest';
-import { validateMetadataFilter, validateMetadataFilterDetailed } from './metadata-filter.js';
+import {
+  MAX_FILTER_DEPTH,
+  validateMetadataFilter,
+  validateMetadataFilterDetailed,
+} from './metadata-filter.js';

Then update the test cases:

   it('accepts filter at maximum nesting depth', () => {
-    expect(validateMetadataFilterDetailed({ x: deepAnd(10) })).toBeNull();
+    expect(validateMetadataFilterDetailed({ x: deepAnd(MAX_FILTER_DEPTH) })).toBeNull();
   });

   it('rejects filter exceeding maximum nesting depth', () => {
-    const d = validateMetadataFilterDetailed({ x: deepAnd(11) });
+    const d = validateMetadataFilterDetailed({ x: deepAnd(MAX_FILTER_DEPTH + 1) });
     expect(d).not.toBeNull();
     expect(d!.message).toContain('maximum depth');
🤖 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/core/server/metadata-filter.test.ts` around lines 54 - 63, Replace the
hardcoded depth values in the two tests with the MAX_FILTER_DEPTH constant from
the validator module: call validateMetadataFilterDetailed({ x:
deepAnd(MAX_FILTER_DEPTH) }) for the acceptance case and
validateMetadataFilterDetailed({ x: deepAnd(MAX_FILTER_DEPTH + 1) }) for the
rejection case; ensure MAX_FILTER_DEPTH is imported from the same module that
exports the validator (the module where validateMetadataFilterDetailed is
defined) so the tests remain correct if the max depth changes.
🤖 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 `@package.json`:
- Line 89: The repo now lists a new dependency "fast-check" in package.json but
package-lock.json was not updated; run a lockfile regen (e.g., npm install) to
update package-lock.json, verify with npm ci or npm install --package-lock-only
that there is no drift, add the updated package-lock.json to the commit, and
push so CI will pass; target the change that added "fast-check" in package.json
when updating and committing the lockfile.

---

Nitpick comments:
In `@src/core/server/metadata-filter.test.ts`:
- Around line 90-94: The deepAnd helper is duplicated; extract the function
deepAnd(levels: number): Record<string, unknown> into a shared test utility
module (e.g., tests/util/filters or similar), export it, and replace the local
implementations in both metadata-filter.test.ts and metadata-filter.fuzz.test.ts
with an import of that shared deepAnd; ensure the exported helper has the same
signature and semantics so existing tests (which call deepAnd) require no other
changes.
- Around line 54-63: Replace the hardcoded depth values in the two tests with
the MAX_FILTER_DEPTH constant from the validator module: call
validateMetadataFilterDetailed({ x: deepAnd(MAX_FILTER_DEPTH) }) for the
acceptance case and validateMetadataFilterDetailed({ x: deepAnd(MAX_FILTER_DEPTH
+ 1) }) for the rejection case; ensure MAX_FILTER_DEPTH is imported from the
same module that exports the validator (the module where
validateMetadataFilterDetailed is defined) so the tests remain correct if the
max depth changes.
🪄 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: ba174d4f-82da-4897-967e-594db55f8c6e

📥 Commits

Reviewing files that changed from the base of the PR and between 687a9a6 and 5559919.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • docs/SECURITY.md
  • package.json
  • src/core/pinecone/rerank.ts
  • src/core/server/metadata-filter.fuzz.test.ts
  • src/core/server/metadata-filter.test.ts
  • src/core/server/metadata-filter.ts
  • src/core/server/redaction.test.ts
  • src/core/server/tool-response.ts
  • src/logger.ts

Comment thread package.json
Lockfile was produced with npm 11 locally; GitHub Actions uses npm 10, which failed npm ci due to missing @emnapi/core/runtime@1.11.0 entries.

Co-authored-by: Cursor <cursoragent@cursor.com>
@codecov

codecov Bot commented Jun 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.82609% with 1 line in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@687a9a6). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/core/server/metadata-filter.ts 96.15% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main     #147   +/-   ##
=======================================
  Coverage        ?   85.26%           
=======================================
  Files           ?       39           
  Lines           ?     1459           
  Branches        ?      502           
=======================================
  Hits            ?     1244           
  Misses          ?      213           
  Partials        ?        2           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jonathanMLDev

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review again

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

@jonathanMLDev Sure! I'll kick off a full review of this PR right away.

✅ Action performed

Full review finished.

@jonathanMLDev
jonathanMLDev requested review from leostar0412 and whisper67265 and removed request for whisper67265 June 9, 2026 19:53
@leostar0412
leostar0412 requested a review from wpak-ai June 9, 2026 21:01
@wpak-ai
wpak-ai merged commit 27d9a76 into cppalliance:main Jun 10, 2026
12 checks passed
@jonathanMLDev
jonathanMLDev deleted the test/redaction-and-filter-fuzz branch June 22, 2026 18: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.

Metadata filter recursive validator fuzz testing Credential redaction verification across all output paths

3 participants