Skip to content

feat(fetch): add redactUrl option and sanitizeUrl helper - #12

Merged
Ryan Zhu (underthestars-zhy) merged 1 commit into
mainfrom
ryan/eng-1830-reduct-url-in-instrumented-fetch
Jun 30, 2026
Merged

feat(fetch): add redactUrl option and sanitizeUrl helper#12
Ryan Zhu (underthestars-zhy) merged 1 commit into
mainfrom
ryan/eng-1830-reduct-url-in-instrumented-fetch

Conversation

@underthestars-zhy

@underthestars-zhy Ryan Zhu (underthestars-zhy) commented Jun 30, 2026

Copy link
Copy Markdown
Member

Summary

  • New redactUrl fetch option. redactUrl: (url) => string rewrites the value stored as url.full, so you can strip tokens/secrets from the query string or path while keeping the span — unlike ignore, which drops the span entirely. server.address / server.port are still derived from the original URL, so an aggressive redactor can't break host resolution, and the real request still uses the original, unredacted URL — only telemetry is rewritten. Available on instrumentFetch, createInstrumentedFetch, and setupOtel({ instrumentFetch }).
  • New sanitizeUrl(url, options?) helper. Semantic-convention URL redaction: sensitive query-parameter values and user:pass@ credentials are replaced with the literal REDACTED, keeping the key (sig=REDACTED). Ships a built-in default list (X-Amz-Signature, X-Amz-Credential, X-Amz-Security-Token, sig, X-Goog-Signature); add your own via params, or disable the defaults with redactDefaults: false. Unparseable input — and input with nothing to redact — is returned unchanged (no query-string re-encoding). Exported alongside the new SanitizeUrlOptions type.
  • Node forces the globalThis.fetch wrap when redactUrl is set. The native undici instrumentation has no hook to rewrite url.full, so requesting redaction declines the native path and falls back to the wrap — the same tradeoff already made for static attributes.
  • Docs. README, configuration, fetch-instrumentation, PII-scrubbing, API reference, and testing docs all document redactUrl / sanitizeUrl and the keep-the-span-vs-ignore distinction.

Usage

import { sanitizeUrl, setupOtel } from "@photon-ai/otel";

setupOtel({
  serviceName: "orders-api",
  endpoint: "http://localhost:4318",
  instrumentFetch: {
    // keep the span, drop the secret from url.full
    redactUrl: (url) => sanitizeUrl(url, { params: ["token", "api_key"] }),
  },
});

// https://api.example.com/v1?token=secret&page=2
//   -> url.full = https://api.example.com/v1?token=REDACTED&page=2

Or per client, without touching global fetch:

import { createInstrumentedFetch, sanitizeUrl } from "@photon-ai/otel";

const fetch = createInstrumentedFetch(undefined, {
  redactUrl: (url) => sanitizeUrl(url),
});

Changes

File Change
src/sanitize.ts New sanitizeUrl() + SanitizeUrlOptions. Semconv query-param + user:pass@ redaction with a default sensitive-param list, a params extension, and a redactDefaults toggle; returns the input unchanged when nothing matches or the URL is unparseable.
src/instrument-fetch.ts Add redactUrl to FetchSpanOptions; fetchAttributes() applies it to ATTR_URL_FULL only, leaving server.* derived from the original URL.
src/instrument-fetch-native.ts Decline the native undici path when redactUrl (or static attributes) is requested, forcing the globalThis.fetch wrap that can rewrite url.full.
src/index.ts Export sanitizeUrl and the SanitizeUrlOptions type.
tests/sanitize.test.ts +6 sanitizeUrl tests: listed param, semconv defaults, user:pass@, no-match passthrough, unparseable passthrough, redactDefaults: false.
tests/instrument-fetch.test.ts +1: redactUrl rewrites url.full but keeps server.address / server.port and the real request URL.
tests/create-instrumented-fetch.test.ts +1: redaction through the per-client fetch.
tests/instrument-fetch-native.test.ts +1: native path declines (returns undefined, registers nothing) when redactUrl is set.
README.md, docs/* Document redactUrl / sanitizeUrl; reframe the "secrets in URLs" guidance around redact-vs-ignore.

Test plan

  • bun run test86 unit tests pass (9 new)
  • bun run build — tsdown ESM (26.40 kB) + DTS (11.90 kB) build succeeds
  • bun x ultracite check src tests — clean (20 files)
  • bun run test:integration — real OTLP/HTTP round-trip; requires Docker, runs in CI

🤖 Generated with Claude Code


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

Summary by CodeRabbit

  • New Features

    • Added URL redaction support for fetch instrumentation, letting spans keep url.full while removing sensitive values.
    • Introduced a URL sanitization helper for redacting query parameters and credentials.
    • Documented new configuration options and examples for using redaction in fetch setups.
  • Bug Fixes

    • Improved handling of sensitive URLs so telemetry can preserve span visibility without exposing secrets.
    • On Node, redacted fetches now fall back to the global fetch wrapper when needed.

Allows callers to rewrite `url.full` before it is recorded as a span
attribute, stripping secrets from query strings or paths while keeping
the span. Unlike `ignore`, the request still goes through.

`sanitizeUrl()` follows OTel URL semconv: sensitive query-parameter
values and `user:pass@` credentials are replaced with `REDACTED`, with
parameter keys preserved. A built-in default list covers common AWS/GCP
signing parameters.

On Node, requesting `redactUrl` forces the `globalThis.fetch` wrap
instead of the native undici instrumentation, which has no hook to
rewrite `url.full`.
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a074f1bb-c3ae-40a5-bc4c-6f86012f3ff1

📥 Commits

Reviewing files that changed from the base of the PR and between 34afd22 and 20d91d3.

📒 Files selected for processing (14)
  • README.md
  • docs/configuration.mdx
  • docs/guides/fetch-instrumentation.mdx
  • docs/guides/pii-scrubbing.mdx
  • docs/reference/api.mdx
  • docs/reference/testing.mdx
  • src/index.ts
  • src/instrument-fetch-native.ts
  • src/instrument-fetch.ts
  • src/sanitize.ts
  • tests/create-instrumented-fetch.test.ts
  • tests/instrument-fetch-native.test.ts
  • tests/instrument-fetch.test.ts
  • tests/sanitize.test.ts

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.


📝 Walkthrough

Walkthrough

Adds a sanitizeUrl helper to src/sanitize.ts that redacts sensitive query parameters and userinfo credentials in URLs, exposes it as a public export, and introduces a redactUrl option on fetch instrumentation that rewrites url.full while preserving the actual request URL. Native undici instrumentation falls back when redactUrl is set. Documentation and tests are updated accordingly.

Changes

redactUrl and sanitizeUrl feature

Layer / File(s) Summary
sanitizeUrl implementation and exports
src/sanitize.ts, src/index.ts
Adds sanitizeUrl(url, options?) with redactUserinfo and redactQueryParams helpers, a SanitizeUrlOptions interface (params, redactDefaults), and exports both from the package index.
redactUrl option wiring in fetch instrumentation
src/instrument-fetch.ts, src/instrument-fetch-native.ts
Adds FetchSpanOptions.redactUrl, applies it in fetchAttributes to set ATTR_URL_FULL while keeping server attributes from the original URL, and makes instrumentFetchNative decline the native path when redactUrl is provided.
Tests for redactUrl and sanitizeUrl
tests/sanitize.test.ts, tests/instrument-fetch.test.ts, tests/instrument-fetch-native.test.ts, tests/create-instrumented-fetch.test.ts
Adds unit tests for sanitizeUrl redaction cases and for redactUrl behavior across instrumentFetch, instrumentFetchNative, and createInstrumentedFetch.
Documentation updates for redactUrl and sanitizeUrl
README.md, docs/configuration.mdx, docs/guides/fetch-instrumentation.mdx, docs/guides/pii-scrubbing.mdx, docs/reference/api.mdx, docs/reference/testing.mdx
Documents the redactUrl option, sanitizeUrl API, usage examples, and revised best-practices/caveats guidance for handling secrets in URLs.

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant instrumentFetch
  participant fetchAttributes
  participant sanitizeUrl
  participant Span

  App->>instrumentFetch: fetch(url with token)
  instrumentFetch->>fetchAttributes: fetchAttributes(name, url, options.redactUrl)
  fetchAttributes->>sanitizeUrl: redactUrl(url)
  sanitizeUrl-->>fetchAttributes: redacted url string
  fetchAttributes->>Span: set url.full = redacted, server.address from original
  instrumentFetch->>App: perform real fetch using original URL
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • photon-hq/otel#8: Both PRs modify the Node native undici fetch decision logic (instrumentFetchNative) for falling back to the global fetch wrapper.

Poem

A token hopped through a URL one day,
"REDACTED!" the rabbit did softly say,
With sanitizeUrl tucked in its paw,
Secrets are hidden, but spans you still draw,
Hop, hop, hooray for privacy's way! 🐰🔒

✨ 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 ryan/eng-1830-reduct-url-in-instrumented-fetch

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

@underthestars-zhy
Ryan Zhu (underthestars-zhy) merged commit 38732a9 into main Jun 30, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release Fight on!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant