Skip to content

Conversation

Flo4604
Copy link
Contributor

@Flo4604 Flo4604 commented Aug 27, 2025

What does this PR do?

Updates our regex and adds some test to make sure we redact any key and not just the ones that fit our schema.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Chore (refactoring code, technical debt, workflow improvements)
  • Enhancement (small improvements)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How should this be tested?

Manual testing using verifyKey and changing up the key json structure
Running the tests

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read Contributing Guide
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand areas
  • Ran pnpm build
  • Ran pnpm fmt
  • Checked for warnings, there are none
  • Removed all console.logs
  • Merged the latest changes from main onto my branch with git pull origin main
  • My changes don't cause any responsiveness issues

Appreciated

  • If a UI change was made: Added a screen recording or screenshots to this PR
  • Updated the Unkey Docs if changes were necessary

Summary by CodeRabbit

  • New Features

    • Improved redaction of sensitive fields in request/response logs for stronger privacy.
  • Bug Fixes

    • Handles more JSON formats, escaping, binary and edge-case payloads to reduce accidental exposure.
  • Refactor

    • Centralized reusable redaction logic for consistent sanitization without changing public APIs.
  • Tests

    • Added extensive tests covering nested/malformed inputs, long/binary payloads, idempotence, and many edge cases.

Copy link

changeset-bot bot commented Aug 27, 2025

⚠️ No Changeset found

Latest commit: a6c1b27

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link

vercel bot commented Aug 27, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
dashboard Ignored Ignored Preview Aug 27, 2025 2:32pm
engineering Ignored Ignored Preview Aug 27, 2025 2:32pm

Copy link
Contributor

coderabbitai bot commented Aug 27, 2025

📝 Walkthrough

Walkthrough

Moves JSON-string redaction out of WithMetrics into package-scoped utilities: introduces a redactionRule type, a redactionRules slice, and a redact([]byte) function; WithMetrics now calls redact() to sanitize request and response bodies. Comprehensive tests for redact() are added.

Changes

Cohort / File(s) Summary
Middleware metrics redaction refactor
go/pkg/zen/middleware_metrics.go
Removes inline redaction logic from WithMetrics; adds package-scoped redactionRule/redactionRules and redact([]byte); WithMetrics now calls redact() to sanitize request/response bodies; regexes broaden to match JSON string values for key and plaintext.
Redaction test suite
go/pkg/zen/middleware_metrics_test.go
Adds extensive tests exercising redact() across many cases: single/multiple fields, varied whitespace, nested JSON, arrays, escaping, malformed inputs, binary data, idempotence, long/unicode values, and other edge cases; asserts on both strings and []byte.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Middleware as MetricsMiddleware
    participant Redactor as redact()
    participant Handler as NextHandler
    participant Logger

    Client->>Middleware: HTTP request (body)
    Middleware->>Redactor: redact(request body)
    Redactor-->>Middleware: sanitized body
    Middleware->>Handler: call next handler with sanitized body
    Handler-->>Middleware: response (body)
    Middleware->>Redactor: redact(response body)
    Redactor-->>Middleware: sanitized response
    Middleware->>Logger: record metrics & log sanitized bodies
    Middleware-->>Client: HTTP response (sanitized)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • unkeyed/unkey#3277 — Refactors redaction logic for the same sensitive fields (key, plaintext) into a reusable function with JSON-string-aware regexes.

Suggested labels

Bug

Suggested reviewers

  • ogzhanolguncu
  • perkinsjr
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/key-regex

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

github-actions bot commented Aug 27, 2025

Thank you for following the naming conventions for pull request titles! 🙏

Copy link
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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
go/pkg/zen/middleware_metrics.go (2)

78-83: Trim whitespace on X-Forwarded-For.

Safer to trim the first hop IP; proxies often include spaces.

-				ips := strings.Split(s.r.Header.Get("X-Forwarded-For"), ",")
-				ipAddress := ""
-				if len(ips) > 0 {
-					ipAddress = ips[0]
-				}
+				ips := strings.Split(s.r.Header.Get("X-Forwarded-For"), ",")
+				ipAddress := ""
+				if len(ips) > 0 {
+					ipAddress = strings.TrimSpace(ips[0])
+				}

16-18: Add a doc comment for exported interface EventBuffer.

Public types must be documented per guidelines.

 type EventBuffer interface {
+	// BufferApiRequest enqueues a request event for asynchronous export
+	// (e.g., to ClickHouse). Implementations should be safe for concurrent use.
 	BufferApiRequest(schema.ApiRequestV1)
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2965d45 and 727f912.

📒 Files selected for processing (2)
  • go/pkg/zen/middleware_metrics.go (1 hunks)
  • go/pkg/zen/middleware_metrics_test.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Follow comprehensive documentation guidelines for Go code as described in go/GO_DOCUMENTATION_GUIDELINES.md
Every public function/type in Go code must be documented
Prefer interfaces for testability in Go code
Use AIDEV-* comments for complex/important code in Go services

Files:

  • go/pkg/zen/middleware_metrics_test.go
  • go/pkg/zen/middleware_metrics.go
**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*_test.go: Use table-driven tests in Go
Organize Go integration tests with real dependencies
Organize Go tests by HTTP status codes

Files:

  • go/pkg/zen/middleware_metrics_test.go
**/*.{env,js,ts,go}

📄 CodeRabbit inference engine (CLAUDE.md)

All environment variables must follow the format: UNKEY_<SERVICE_NAME>_VARNAME

Files:

  • go/pkg/zen/middleware_metrics_test.go
  • go/pkg/zen/middleware_metrics.go
🧠 Learnings (2)
📓 Common learnings
Learnt from: chronark
PR: unkeyed/unkey#3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via `\s`. Do not flag this as an error in future reviews.
📚 Learning: 2025-01-31T13:50:45.004Z
Learnt from: chronark
PR: unkeyed/unkey#2825
File: apps/dashboard/app/(app)/logs/components/table/logs-table.tsx:100-118
Timestamp: 2025-01-31T13:50:45.004Z
Learning: Sensitive data in logs is masked at the API layer (apps/api/src/pkg/middleware/metrics.ts) before being written to Clickhouse. This includes redacting API keys, plaintext values, and authorization headers using regex replacements.

Applied to files:

  • go/pkg/zen/middleware_metrics.go
🪛 Gitleaks (8.27.2)
go/pkg/zen/middleware_metrics_test.go

17-17: Found a Stripe Access Token, posing a risk to payment processing services and sensitive financial data.

(stripe-access-token)


298-298: Found a Stripe Access Token, posing a risk to payment processing services and sensitive financial data.

(stripe-access-token)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Build / Build
🔇 Additional comments (2)
go/pkg/zen/middleware_metrics.go (1)

93-97: LGTM: central redaction applied to request/response bodies before logging.

This ensures consistent masking in ClickHouse logs.

go/pkg/zen/middleware_metrics_test.go (1)

9-242: Solid coverage and edge cases.

Comprehensive table-driven tests for redact() including escapes, malformed input, and idempotence.

@Flo4604 Flo4604 enabled auto-merge August 27, 2025 10:05
@Flo4604 Flo4604 requested a review from ogzhanolguncu August 27, 2025 11:52
Copy link
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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 727f912 and be80944.

📒 Files selected for processing (2)
  • go/pkg/zen/middleware_metrics.go (1 hunks)
  • go/pkg/zen/middleware_metrics_test.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Follow comprehensive documentation guidelines for Go code as described in go/GO_DOCUMENTATION_GUIDELINES.md
Every public function/type in Go code must be documented
Prefer interfaces for testability in Go code
Use AIDEV-* comments for complex/important code in Go services

Files:

  • go/pkg/zen/middleware_metrics.go
  • go/pkg/zen/middleware_metrics_test.go
**/*.{env,js,ts,go}

📄 CodeRabbit inference engine (CLAUDE.md)

All environment variables must follow the format: UNKEY_<SERVICE_NAME>_VARNAME

Files:

  • go/pkg/zen/middleware_metrics.go
  • go/pkg/zen/middleware_metrics_test.go
**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*_test.go: Use table-driven tests in Go
Organize Go integration tests with real dependencies
Organize Go tests by HTTP status codes

Files:

  • go/pkg/zen/middleware_metrics_test.go
🧠 Learnings (3)
📓 Common learnings
Learnt from: chronark
PR: unkeyed/unkey#3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via `\s`. Do not flag this as an error in future reviews.
Learnt from: imeyer
PR: unkeyed/unkey#3755
File: .github/workflows/runbook-freshness-check.yaml:157-173
Timestamp: 2025-08-08T14:59:52.283Z
Learning: Repo unkeyed/unkey: When a CI/workflow fix is deferred, imeyer prefers a thorough GitHub issue be opened with sections (Summary, Impact, Where, Repro, Observed vs Expected, Acceptance Criteria, Validation Plan, Out of Scope, References) and assigned to imeyer, including backlinks to the originating PR and comment.
Learnt from: chronark
PR: unkeyed/unkey#3860
File: go/pkg/zen/middleware_metrics_test.go:297-313
Timestamp: 2025-08-27T11:02:17.134Z
Learning: The redact function in go/pkg/zen/middleware_metrics.go is not expected to be called concurrently, so concurrency tests are unnecessary for this function.
📚 Learning: 2025-08-27T11:02:17.134Z
Learnt from: chronark
PR: unkeyed/unkey#3860
File: go/pkg/zen/middleware_metrics_test.go:297-313
Timestamp: 2025-08-27T11:02:17.134Z
Learning: The redact function in go/pkg/zen/middleware_metrics.go is not expected to be called concurrently, so concurrency tests are unnecessary for this function.

Applied to files:

  • go/pkg/zen/middleware_metrics.go
  • go/pkg/zen/middleware_metrics_test.go
📚 Learning: 2025-07-16T17:51:57.297Z
Learnt from: chronark
PR: unkeyed/unkey#3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via `\s`. Do not flag this as an error in future reviews.

Applied to files:

  • go/pkg/zen/middleware_metrics_test.go
🪛 Gitleaks (8.27.2)
go/pkg/zen/middleware_metrics_test.go

17-17: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Build / Build
🔇 Additional comments (2)
go/pkg/zen/middleware_metrics.go (1)

25-36: Regexes correctly match generic JSON string values for "key" and "plaintext".

Covers escaped quotes and varied whitespace; tests reflect intent. LGTM.

go/pkg/zen/middleware_metrics_test.go (1)

9-249: Solid, table-driven coverage; good edge cases and idempotence.

Covers whitespace, escapes, malformed JSON, binary data, and idempotence. Nicely aligned with runtime behavior.

Also applies to: 252-276, 289-338

@Flo4604 Flo4604 requested a review from chronark August 27, 2025 14:40
Copy link
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

♻️ Duplicate comments (1)
go/pkg/zen/middleware_metrics.go (1)

20-23: Rename field to avoid package shadowing; add brief AIDEV note.

  • Rename regexp to re to avoid confusion with the imported package.
  • Add a short AIDEV note documenting intent and deterministic ordering (slice).
 type redactionRule struct {
-	regexp      *regexp.Regexp
-	replacement []byte
+	re          *regexp.Regexp
+	replacement []byte
 }
 
 var redactionRules = []redactionRule{
-	// Redact "key" field values - matches JSON-style key fields with various whitespace combinations
+	// AIDEV-NOTE: RE2 patterns applied in order; using a slice ensures deterministic redaction.
+	// We match JSON string values without parsing JSON to handle malformed inputs robustly.
+	// Redact "key" field values - matches JSON-style key fields with various whitespace combinations
 	{
-		regexp:      regexp.MustCompile(`"key"\s*:\s*"[^"\\]*(?:\\.[^"\\]*)*"`),
+		re:          regexp.MustCompile(`"key"\s*:\s*"[^"\\]*(?:\\.[^"\\]*)*"`),
 		replacement: []byte(`"key": "[REDACTED]"`),
 	},
 	// Redact "plaintext" field values - matches JSON-style plaintext fields with various whitespace combinations
 	{
-		regexp:      regexp.MustCompile(`"plaintext"\s*:\s*"[^"\\]*(?:\\.[^"\\]*)*"`),
+		re:          regexp.MustCompile(`"plaintext"\s*:\s*"[^"\\]*(?:\\.[^"\\]*)*"`),
 		replacement: []byte(`"plaintext": "[REDACTED]"`),
 	},
 }
 
 func redact(in []byte) []byte {
 	b := in
 
 	for _, rule := range redactionRules {
-		b = rule.regexp.ReplaceAll(b, rule.replacement)
+		b = rule.re.ReplaceAll(b, rule.replacement)
 	}
 
 	return b
 }

Also applies to: 28-29, 33-34, 41-43

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between be80944 and a6c1b27.

📒 Files selected for processing (1)
  • go/pkg/zen/middleware_metrics.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Follow comprehensive documentation guidelines for Go code as described in go/GO_DOCUMENTATION_GUIDELINES.md
Every public function/type in Go code must be documented
Prefer interfaces for testability in Go code
Use AIDEV-* comments for complex/important code in Go services

Files:

  • go/pkg/zen/middleware_metrics.go
**/*.{env,js,ts,go}

📄 CodeRabbit inference engine (CLAUDE.md)

All environment variables must follow the format: UNKEY_<SERVICE_NAME>_VARNAME

Files:

  • go/pkg/zen/middleware_metrics.go
🧠 Learnings (3)
📓 Common learnings
Learnt from: chronark
PR: unkeyed/unkey#3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via `\s`. Do not flag this as an error in future reviews.
Learnt from: imeyer
PR: unkeyed/unkey#3755
File: .github/workflows/runbook-freshness-check.yaml:157-173
Timestamp: 2025-08-08T14:59:52.283Z
Learning: Repo unkeyed/unkey: When a CI/workflow fix is deferred, imeyer prefers a thorough GitHub issue be opened with sections (Summary, Impact, Where, Repro, Observed vs Expected, Acceptance Criteria, Validation Plan, Out of Scope, References) and assigned to imeyer, including backlinks to the originating PR and comment.
Learnt from: chronark
PR: unkeyed/unkey#3860
File: go/pkg/zen/middleware_metrics_test.go:297-313
Timestamp: 2025-08-27T11:02:17.134Z
Learning: The redact function in go/pkg/zen/middleware_metrics.go is not expected to be called concurrently, so concurrency tests are unnecessary for this function.
📚 Learning: 2025-08-27T11:02:17.134Z
Learnt from: chronark
PR: unkeyed/unkey#3860
File: go/pkg/zen/middleware_metrics_test.go:297-313
Timestamp: 2025-08-27T11:02:17.134Z
Learning: The redact function in go/pkg/zen/middleware_metrics.go is not expected to be called concurrently, so concurrency tests are unnecessary for this function.

Applied to files:

  • go/pkg/zen/middleware_metrics.go
📚 Learning: 2025-01-31T13:50:45.004Z
Learnt from: chronark
PR: unkeyed/unkey#2825
File: apps/dashboard/app/(app)/logs/components/table/logs-table.tsx:100-118
Timestamp: 2025-01-31T13:50:45.004Z
Learning: Sensitive data in logs is masked at the API layer (apps/api/src/pkg/middleware/metrics.ts) before being written to Clickhouse. This includes redacting API keys, plaintext values, and authorization headers using regex replacements.

Applied to files:

  • go/pkg/zen/middleware_metrics.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build / Build
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
go/pkg/zen/middleware_metrics.go (1)

38-46: LGTM: deterministic, idempotent redaction loop.

Simple pass applying precompiled rules in order; matches the non-concurrent usage expectation.

Copy link
Contributor

👀

Copy link
Contributor Author

Flo4604 commented Aug 27, 2025

wanna give it a review? @ogzhanolguncu :bugeyes:

Copy link
Contributor

Will review it in 10 🫡 🫡

Copy link
Contributor

@ogzhanolguncu ogzhanolguncu left a comment

Choose a reason for hiding this comment

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

Tested locally, redaction is working correctly in CH logs as expected.

@Flo4604 Flo4604 added this pull request to the merge queue Aug 27, 2025
Copy link

graphite-app bot commented Aug 27, 2025

Movie gif. Joaquin Phoenix as Commodus from Gladiator doesn't look happy as he holds out his hand, but gradually looks calmer as he slowly gives us a thumbs up. (Added via Giphy)

Copy link

graphite-app bot commented Aug 27, 2025

Graphite Automations

"Post a GIF when PR approved" took an action on this PR • (08/27/25)

1 gif was posted to this PR based on Andreas Thomas's automation.

Merged via the queue into main with commit 490e164 Aug 27, 2025
18 checks passed
@Flo4604 Flo4604 deleted the fix/key-regex branch August 27, 2025 17:23
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.

3 participants