Releases: redact-secret/redact-secret-adapters
Release list
Release train 2026.09.30.2
Release train 2026.09.30.2. Every package is versioned independently; this train shipped:
@redact-secret/adapter-otel-trace 0.1.0
Added
- The package, under a name that says what it covers: OpenTelemetry JS
traces (#49). It is the code
@redact-secret/adapter-otel0.1.2shipped, unchanged: the same
createRedactingSpanProcessor,RedactingSpanProcessorWith,
redactAttributesWith, options (policy,maxStringLength,onOutcome,
andpiion the live factory) and outcome shape, and the same
REDACT_SECRET_SPAN_DROPPEDwarning, whose message still begins
@redact-secret/adapter-otel:so a filter written against it keeps
matching. It protects spans only — the span name, attributes, events, status
message and link attributes. OpenTelemetry Logs (LogRecords) pass through
no code in this package. - Declares
@opentelemetry/sdk-trace-base^2.0.0and@redact-secret/core
^0.1.0-beta.6, the rangesadapter-otel0.1.2declared, backed by the
same real-host tests (test/otel-host.test.ts,test/otel-lifecycle.test.ts,
test/outcome.test.ts,test/vault-token.test.ts), which CI runs at both
ends of each range.test/exporter-bytes.test.tsadds the final OTLP JSON
bytes an exporter would send, for the injected and the live factory, through
bothSimpleSpanProcessorandBatchSpanProcessor.
@redact-secret/adapter-otel 0.1.3
Deprecated
- This package is now a compatibility re-export of
@redact-secret/adapter-otel-trace, the same
processor under a name that says what it covers: OpenTelemetry traces
(aSpanProcessor), not OpenTelemetry Logs
(#49). Every export keeps its name,
signature and behavior —createRedactingSpanProcessor,
RedactingSpanProcessorWith(the same class object, soinstanceofstill
holds),redactAttributesWithand the option and outcome types — and each
is marked@deprecatedin the type declarations. Nothing is printed at
import or call time. Migrate by changing the import specifier to
@redact-secret/adapter-otel-trace; see the
migration guide.
test/compat-shim.test.tschecks that every export is identical to the new
package's and that a realBasicTracerProviderspan exports the same OTLP
JSON bytes through either name.
Changed
- Depends on
@redact-secret/adapter-otel-trace^0.1.0instead of
@redact-secret/adapterdirectly (the trace package brings it). The
@opentelemetry/sdk-trace-base^2.0.0and@redact-secret/core
^0.1.0-beta.6peer ranges are unchanged, backed by the same tests, now in
packages/adapter-otel-trace/test.
Release train 2026.09.30
Release train 2026.09.30. Every package is versioned independently; this train shipped:
@redact-secret/adapter-mcp 0.1.2
Changed
- The optional peer
@modelcontextprotocol/sdkrange is raised from
>=1.13.0 <=1.30.1to>=1.26.0 <=1.30.1. Every 1.x release before 1.26.0
carries at least one of three high-severity SDK advisories:
GHSA-w48q-cv73-mx4w (DNS rebinding protection off by default, fixed in
1.24.0), GHSA-8r9q-7v3j-jr4g (ReDoS inUriTemplate, fixed in 1.25.2) and
GHSA-345p-7cg4-v4c7 (cross-client data leak on server or transport reuse,
fixed in 1.26.0). None is reachable from this adapter's own code. With the
SDK installed, npm now refuses an older one with ERESOLVE. The new range is
backed bytest/transport.test.ts,test/resources-transport.test.tsand
test/e2e.test.ts, run at both endpoints (1.26.0 and 1.30.1) by CI
range-endpoints. 1.26.0 negotiates protocol 2025-11-25, so 2025-06-18 is
no longer negotiated at a tested endpoint (#83).
Fixed
- With
binaryContent: "pass", a binary field (an image or audio block's
data, a resource'sblob) is read once. Before, the boundary checked that
the value was a string and then read it again while rebuilding the result.
A getter could return a non-string, unscanned value on the second read, and
it went out asok. A getter that threw on the second read escaped
sanitizeToolResult,sanitizeResourceResultand the wrapped handlers as an
exception. The boundary now passes on the string it checked. Backed by
test/boundary-edges.test.ts(#91). - A streamed-result step whose
doneorvaluegetter throws is now
tool_error, and the boundary aborts the session and closes the producer.
Before, the getter's error escaped
sanitizeStreamedToolResultandwrapStreamedToolHandleras a rejection
carrying the producer's own error, and the session stayed open. Backed by
test/boundary-edges.test.ts(#92).
@redact-secret/adapter 0.1.5
Added
maxNodeswalk budget (default 20000) inLimitsandDEFAULT_LIMITS
(#87).walkValue, behind
maskSecretsWithandmaskLogValueWith, budgeted only string leaves, and it
walks a shared reference once per path. An in-process graph of 8 levels, each
holding 1000 references to the next, therefore cost about 1000^7 container
visits before any string budget tripped (a probe: 10^8 paths took 8 s).
Every visited value now counts, containers included, using the same rule as
walkStrict'smaxNodes. Past the budget, every value becomes
[REDACTED:LIMIT_EXCEEDED](countedlimited). The default is four times
maxTotalLeaves, so a string-heavy value still meets the leaf budget first.
Invalid overrides fall back to the default throughresolveLimit. Tested by
"maxNodes counts every visit…" and "a shared-reference DAG is bounded by
maxNodes…" intest/mask-secrets.test.ts, and the shared
shared_reference_dag_is_bounded_by_max_nodesand
tightened_max_nodes_bounds_a_shared_reference_dagcases in
fixtures/bounded-traversal-cases.json.
redact-secret-adapters (PyPI) 0.1.2
Added
max_nodeswalk budget (default 20000) inDEFAULT_LIMITS
(#87). The walker behind
mask_secrets_with,mask_log_value_withandextra_fieldsbudgeted only
string leaves, and it walks a shared reference once per path. An in-process
graph of shared lists therefore cost exponential time before any string
budget tripped (a probe: 10^8 paths took 85 s). Every visited value now
counts, containers included, with the same rule and default as the
TypeScriptmaxNodes. Past the budget, every value becomes
[REDACTED:LIMIT_EXCEEDED](countedlimited). Invalid overrides fall back
to the default throughresolve_limit. Tested by
test_max_nodes_counts_every_visit_once_per_path,
test_a_shared_reference_dag_is_bounded_by_max_nodes_not_its_path_count, and
the sharedshared_reference_dag_is_bounded_by_max_nodesand
tightened_max_nodes_bounds_a_shared_reference_dagcases.
Changed
- An object the walker does not walk now fails closed to
[REDACTED:ERROR]instead of passing through unchanged
(#85). This covers aset,bytes, a
dataclass, adatetime, or any other instance reached by
mask_secrets_with,mask_log_value_with, or aRedactSecretFilter
extra_fieldsentry. Before, a%(ctx)sformat or a JSON formatter with
default=strprinted such a value unscanned.str,int,float,
boolandNoneare unchanged, anddict,list,tupleand
exceptions are still walked. To keep such a value, convert it to a
dictorstrbefore logging it. Tested by
test_any_other_object_fails_closed_to_the_error_marker,
test_a_non_container_object_extra_fails_closed_for_str_and_json_formatters,
and the sharedopaque_object_never_passes_its_secret_throughcase in
fixtures/bounded-traversal-cases.json.
Fixed
- A container whose read raises (a
dictsubclass whose__getitem__or
keys()raises, alistsubclass whose slicing raises) no longer raises
out of the walk, or out oflogger.info()throughRedactSecretFilter
(#85). It becomes[REDACTED:ERROR]for that key alone, or for the whole
container when it cannot be listed, as in the TypeScript walker. Tested by
test_a_container_whose_read_raises_degrades_per_entry_and_never_raises,
test_an_extra_whose_read_raises_never_raises_into_the_logging_call, and
the sharedthrowing_entry_degrades_for_that_entry_alonecase. limitsare validated like the TypeScriptresolveLimit(#85):None,
NaN, a negative number, abool, or a non-number falls back to that
key's default. Before,max_depth=NoneraisedTypeErrorout of
filter(),max_total_leaves=float("nan")never tripped, and
max_array_length=-1kept all but the last element. Tested by
test_an_invalid_limit_falls_back_to_the_default_instead_of_disabling_it,
test_invalid_limits_fall_back_to_the_defaults_instead_of_raising, and the
sharedinvalid_*_limits_fall_back_to_the_defaultscases.
Release train 2026.09.29.4
Release train 2026.09.29.4. Every package is versioned independently; this train shipped:
@redact-secret/adapter 0.1.4
Changed
- The
PII_ACTIVATION_CONFLICTdocumentation inactivation.tsnow shows the
pii-context/v2vocabulary that core0.1.0-beta.11reports. Documentation
only; no behaviour change.
Release train 2026.09.29.3
Release train 2026.09.29.3. Every package is versioned independently; this train shipped:
@redact-secret/adapter-ai-context 0.1.1
Fixed
- The package README no longer calls the package a prerelease or tells the
reader to install@alpha;0.1.0is stable and published aslatest.
@redact-secret/adapter-mcp 0.1.1
Fixed
- The package README no longer calls the package a prerelease or tells the
reader to install@alpha;0.1.0is stable and published aslatest.
Release train 2026.09.29.2
Release train 2026.09.29.2. Every package is versioned independently; this train shipped:
@redact-secret/adapter-ai-context 0.1.0
Changed
- First stable release: published under the npm dist-tag
latest. The code is
that of0.1.0-alpha.2plus the scan reuse below. sanitizeValueandbuildContextscan each distinct text once per call
(texts up to 1,024 code units), reusing the result for repeats such as a
content envelope'stype/textkeys. Output, findings,onFinding
(still once per occurrence),maxNodescounting and outcomes are
unchanged. Theai-context-jsworkload drops from 28 to about 20 core
calls per event (#107).
@redact-secret/adapter-mcp 0.1.0
Changed
- First stable release: published under the npm dist-tag
latest. The code is
that of0.1.0-alpha.2plus the scan reuse below. - A tool result's repeated envelope strings reach the core once per crossing:
the value scan reuses identical texts, and the key-context check skips a
serialized part that already scanned with no findings. Outputs, findings and
onFinding(once per occurrence) are unchanged (#107).
Release train 2026.09.29
Release train 2026.09.29. Every package is versioned independently; this train shipped:
- @redact-secret/adapter-ai-context 0.1.0-alpha.2
- @redact-secret/adapter-mcp 0.1.0-alpha.2
- @redact-secret/adapter-otel 0.1.2
- @redact-secret/adapter-pino 0.1.2
- @redact-secret/adapter 0.1.3
- redact-secret-adapters (PyPI) 0.1.1
@redact-secret/adapter-ai-context 0.1.0-alpha.2
Added
-
piioncreateAiContextBoundary, carried by
AiContextBoundaryOptionsWithDefaults
(#51). It activates core PII
selectors for the whole process through@redact-secret/adapter's
activateCore. The factory's contract of never rejecting is unchanged:
a selection that cannot be shown to be active is an initialization
failure like any other, so every operation fails closed asblocked/
core_errorwith nocode, rather than quietly building context with
PII off.piiis read by property, so an activation inherited through a
prototype survives, the same rulewithDefaultLimitsfollows. -
AI_CONTEXT_DEFAULT_LIMITSandwithDefaultLimits(options?), and
createAiContextBoundary(options?)now fills in any of the three limit sets
a caller leaves out (#46). A new
integration no longer has to invent four security numbers before its first
sanitizeText. The values are the ones this repository has been exercising
all along — the README example, the clean-install smoke test, and the core's
conformance replay. -
The
AiContextLimitsandAiContextBoundaryOptionsWithDefaultstypes.
Fixed
-
An application that had already run
initialize({ pii })got a boundary
that blocked everything: the factory's own argument-freeinitialize()
is a different selection to the core's one-shot cell and rejected with
PII_ACTIVATION_CONFLICT, which this package maps to a fail-closed
blocked/core_error— a silently blocked boundary rather than a
visible error. That conflict now counts as success, since it means the
core is already loaded under the application's own selection. Every
other initialization failure still fails closed exactly as before. -
withDefaultLimitsreadspolicy,placeholderFormatterandonFinding
by name rather than by spreadingoptions, so an options object layered over
a shared base (Object.create(defaults)) keeps them.
createAiContextBoundaryWithdestructures its options, which follows the
prototype chain, so before this an inheritedpolicywould have been
silently dropped and the boundary would have run on the core's default
policy — a quiet weakening, with no error. An inherited limit set is used
rather than overwritten by the preset, and a key this helper does not know
about is forwarded rather than dropped.
Changed
-
The declared
@redact-secret/adapterrange rises to^0.1.3, the
version that carriesactivateCore. The declared
@redact-secret/corerange is unchanged at^0.1.0-beta.6. -
The README leads with the short call and moves the limits below it, with a
table of what each bound covers, and states next to the example that
non-JSON values, binary content and encoded text are blocked rather than
decoded, and that a cancelled operation isaborted.
Not changed, deliberately: limits are still mandatory and still finite.
AI_CONTEXT_DEFAULT_LIMITS is a frozen set of eight positive integers, not
an unbounded mode and not a way to switch a bound off. A limit set that is
passed is used exactly as passed, never merged field by field with the preset,
because a half-specified set should be rejected by the core rather than
silently completed. createAiContextBoundaryWith, the injected API, still
requires all three sets and throws a TypeError without them — pass
withDefaultLimits() to hand it the preset. Every existing caller that passes
all three behaves exactly as it did. test/defaults.test.ts asserts against
the real core that each preset bound is enforced and fails closed as
limit_exceeded, that a streamed text agrees with sanitizeText at every
chunk partition under it, and that an override replaces rather than widens.
Documented
- Activating PII is not the same as masking every PII value: under the
core's default policyHigh-confidence PII redacts whileMediumand
Lowresolve towarn, and awarnfinding leaves the text alone, so
anokoutcome can carry findings whose text was not changed and
lower-confidence PII reaches the model as plaintext. Supply your own
policymapping those findings toredactif you need them masked.
@redact-secret/adapter-mcp 0.1.0-alpha.2
Added
-
piioncreateMcpBoundary, forwarded tocreateAiContextBoundarythe
way the limits already are
(#51). It activates core PII
selectors for the whole process. The factory's contract of never
rejecting is unchanged: a selection that cannot be shown to be active
fails every operation closed asblocked/core_error, which maps to
the fixed blocked result, rather than quietly sanitizing with PII off. -
createMcpBoundary(options?)now fills in any of the three limit sets a
caller leaves out, from@redact-secret/adapter-ai-context's
AI_CONTEXT_DEFAULT_LIMITS(#46), so a
host can start withawait createMcpBoundary()and a checked outcome.
binaryContentandonAuditcompose with the defaults unchanged. -
The
CreateMcpBoundaryOptionsWithDefaultstype.
Fixed
- An application that had already run
initialize({ pii })got a boundary
that blocked everything, because the AI-context factory's argument-free
initialize()rejected withPII_ACTIVATION_CONFLICTagainst the
core's one-shot selection cell and that mapped to a fail-closed
blocked/core_error. That conflict now counts as success. Every
other initialization failure still fails closed exactly as before.
Documented
- Activating PII is not the same as masking every PII value: under the
core's default policyHigh-confidence PII redacts whileMediumand
Lowresolve towarn, and awarnfinding leaves the text alone, so
anokoutcome can carry findings whose text was not changed. Supply
your ownpolicymapping those findings toredactif you need them
masked.
Changed
- The README leads with the short call, moves the limits below it, and states
next to the example what refuses and why: a binary payload blocks by default
because it cannot be scanned (binaryContent: "pass"passes a string
payload unscanned at its original position), a content type no qualified
protocol revision defines blocks, and a cancelled call isabortedwith
toCallToolResultreturningnull. @redact-secret/adapter-ai-contextrange raised from^0.1.0-alpha.1to
^0.1.0-alpha.2, the version that carries the default limits this release
relies on. Backed by this package's tests and the published-sibling
combination job.
Not changed: there is no unbounded mode, the bounds still fail an oversized
result closed as blocked / limit_exceeded, and createMcpBoundaryWith over
a boundary the host built itself is untouched. test/defaults.test.ts asserts
the defaults, an override, the binary block, an unsupported content type, and
an aborted call on the real core.
@redact-secret/adapter-otel 0.1.2
Added
-
piioncreateRedactingSpanProcessor, with the
CreateRedactingSpanProcessorOptionstype
(#51). It activates core PII
selectors for the whole process through@redact-secret/adapter's
activateCore, and the factory rejects — with a fixed code
(PII_ACTIVATION_NOT_ACTIVE, orPII_ACTIVATION_UNSUPPORTEDagainst a
core that reports no activation) and no selector, input or core message
in the error — rather than return a processor that scans with PII
silently off. -
onOutcome, on bothcreateRedactingSpanProcessorand
RedactingSpanProcessorWith: one input-free summary per span
(#45), carrying the six shared value
counts anddropped.droppedis this processor's own decision — it did
not hand the span to the next processor because a masked value would not
write back. It does not mean the span was sampled out, andfalsedoes
not mean the span was exported: whether the next processor kept it and
whether an exporter succeeded are things this adapter never learns and does
not report. The observer is called synchronously once the span has been
forwarded or dropped; anything it throws is swallowed, never read, and
never changes what is exported; it is re-entrancy- and thread-guarded; and
no exporter or network client is created for it. -
RedactingSpanProcessorOptionsandOtelSpanOutcometypes. The
processor's third argument was already{ policy, maxStringLength }and
still accepts exactly that.
Fixed
-
An application that had already run
initialize({ pii })could not build
this processor: the factory's own argument-freeinitialize()is a
different selection to the core's one-shot cell and rejected with
PII_ACTIVATION_CONFLICT. That conflict now counts as success, since it
means the core is already loaded under the application's own selection.
Every other initialization failure still rejects exactly as before. -
A span's attribute values are now counted by the processor's own
masker. They were redacted correctly...
Release train 2026.09.26
Release train 2026.09.26. Every package is versioned independently; this train shipped:
- @redact-secret/adapter-ai-context 0.1.0-alpha.1
- @redact-secret/adapter-mcp 0.1.0-alpha.1
- @redact-secret/adapter 0.1.2
@redact-secret/adapter-ai-context 0.1.0-alpha.1
Added
- The
resourceboundary label (redact-secret/redact-secret#843), for the
contents of an MCPresources/readresult. Telemetry-only, like every
label; a type-level addition toBoundaryLabel.
Changed
- Contract change: key-aware
sanitizeValue(redact-secret/redact-secret#842,
redact-secret-adapters#32). A string leaf under an object key that its own
scan does not redact is scanned once more, through the same
scanAndRedact, in its key-context view{"<key>":"<leaf>"}; a finding
there is redacted at the leaf, with leaf offsets. Only the immediate key
counts (array elements, parent and sibling keys give none), a finding
outside the leaf's span that would redact or block blocks aspolicy, and
a view overmaxInputBytesblocks aslimit_exceeded. No key pattern or
name list is added: the core decides. Migration: a leaf that passed in
plaintext because only its key identified it ({"password": "<value>"})
is now replaced by a placeholder and reported inok.findingsand
telemetry; nothing previously redacted or blocked passes. Qualified by the
core fixture vendored at the #842 commit
(packages/adapter-ai-context/test/conformance.test.ts) at both core range
endpoints. - Dependency range:
@redact-secret/adapter^0.1.1→^0.1.2
(redact-secret-adapters#36). The key-awaresanitizeValueneeds the
walkStrictthat hands each leaf its key, first shipped in
@redact-secret/adapter0.1.2. Against the published0.1.1, which
^0.1.1still allowed, the walker passes no key, so a key-identified leaf
such as{"password": "<value>"}was blocked aspolicyinstead of redacted
in place. It failed closed, but it broke the contract above, and no in-repo
test could see it because every one uses the workspace walker.
scripts/check-published-combination.mjsnow installs this package with the
lowest registry version its range allows and runs the key-aware probe.
@redact-secret/adapter-mcp 0.1.0-alpha.1
Added
resources/read(redact-secret/redact-secret#843,
redact-secret-adapters#33):sanitizeResourceResult,
sanitizeResourceRead(host placement, around a clientreadResource),
andwrapResourceReadHandler(a server read callback of either SDK line,
McpServer.registerResourcefixed URIs and URI templates, or a low-level
resources/readhandler). AReadResourceResultis one AI-context
sanitizeValueunder the newresourcelabel, then the same key-context
backstop; entrytextis scanned as text whatever itsmimeType; an entry
must be exactly one oftextorblob, and ablobfollows
binaryContent. Failures map to fixed JSON-RPC errors (code-32603, a
fixed message, nodata) throughtoReadResourceResponse, and the wrapper
throws them asMcpResourceError; a read failure is the newread_error
outcome, its error never read. The auditstagegainsresource.
Qualified by the coremcp-resources-readfixture and runner vendored at
the #843 commit (test/conformance*.test.ts), replayed over real SDK
clients and servers at both endpoints of both lines on stdio and
Streamable HTTP (test/resources-transport.test.ts), and exercised at the
host placement intest/e2e.test.ts. No declared range changes.
Changed
-
Dependency range:
@redact-secret/adapter-ai-context^0.1.0-alpha→
^0.1.0-alpha.1(redact-secret-adapters#36). The narrowed key-context
backstop below relies on the key-awaresanitizeValue, which the published
0.1.0-alphadoes not have. Paired with it, a_meta.passwordleaf in a
resources/readresult was blocked aspolicyinstead of redacted.
scripts/check-published-combination.mjsguards the pairing. -
Contract change: the key-context check is narrowed to a backstop
(redact-secret/redact-secret#842, redact-secret-adapters#32). The
AI-contextsanitizeValueis now key-aware and redacts a leaf its own key
identifies in place, so the serialized rescan no longer blocks such a
result; it still blocks, aspolicy, on context only the serialization
shows (a sibling or parent key). Migration: a result or argument set
that wasblocked/policyonly through the key-context check is now
ok, with that leaf replaced by a placeholder and its finding reported
throughonFinding; hosts that relied on the block should watch
onFinding. Nothing previously redacted or blocked passes. Qualified by the
core fixture vendored at the #842 commit
(packages/adapter-mcp/test/conformance.test.ts,
packages/adapter-mcp/test/transport.test.ts) at both SDK line endpoints.
@redact-secret/adapter 0.1.2
Added
walkStricthands each string leaf's visitor a second argument,key:
the object key the leaf sits directly under, orundefinedfor an array
element and the root (redact-secret/redact-secret#842). Visitors that take
one argument are unaffected.@redact-secret/adapter-ai-contextuses it for
its key-awaresanitizeValue.
Release train 2026.09.25
Release train 2026.09.25. Every package is versioned independently; this train shipped:
- @redact-secret/adapter-ai-context 0.1.0-alpha
- @redact-secret/adapter-mcp 0.1.0-alpha
- @redact-secret/adapter-otel 0.1.1
- @redact-secret/adapter-pino 0.1.1
- @redact-secret/adapter 0.1.1
@redact-secret/adapter-ai-context 0.1.0-alpha
First release, as a prerelease.
Added
- The framework-neutral AI-context boundary (redact-secret/redact-secret#610,
redact-secret-adapters#12):createAiContextBoundary(options)(live: loads
and initializes@redact-secret/coreon call) and
createAiContextBoundaryWith(core, options)(injected), each returning
sanitizeText,sanitizeValue,sanitizeToolResult,buildContext, and
openStream. Every operation ends in a frozenok/blocked/aborted
outcome with a fixed reason set (BLOCK_REASONS); findings cross the
boundary as allowlisted copies (SAFE_FINDING_FIELDS); initialization,
callback, lifecycle and limit failures map to fixed, input-free outcomes.
Nested values go through@redact-secret/adapter'swalkStrict. "tool-arguments"inBoundaryLabel, for the arguments of a tool call
(the MCP boundary's opt-in argument sanitation, redact-secret/redact-secret#612).
Telemetry only; it never changes an outcome.AiContextStream.accepting: a read-only, input-free boolean that istrue
until the stream fails, is aborted, or is finalized, so a host can stop
pulling from a producer whose output would be discarded unscanned
(redact-secret/redact-secret#612).- Qualified by replaying the core's
conformance/fixtures/ai-context-boundary.json,
vendored at core commit0e3ba9592b6fa80fafdea47639921987c36ba323
(fixtures/core/pins.json), through the public API on the real core, before
and afterinitialize(). - Declared range:
@redact-secret/core ^0.1.0-beta.6, as a required peer
dependency, backed by the conformance replay and
test/e2e.test.tsat both range endpoints in CI. - Depends on
@redact-secret/adapter ^0.1.1, the first version that exports
walkStrict.0.1.0lacks it, so the import failed against it.
@redact-secret/adapter-mcp 0.1.0-alpha
First release, as a prerelease.
Added
- The supported MCP redaction boundary (redact-secret/redact-secret#612,
redact-secret-adapters#13), as a thin specialization of
@redact-secret/adapter-ai-context:createMcpBoundary(options)(live)
andcreateMcpBoundaryWith(aiContextBoundary, options)(injected), each
returningsanitizeToolResult,sanitizeToolArguments(opt-in, label
tool-arguments),sanitizeToolCall,sanitizeStreamedToolResult,
wrapToolHandler, andwrapStreamedToolHandler. The whole
CallToolResultis one AI-contextsanitizeValue, followed by the
key-context check. Binary payloads block by default (binaryContent: "pass"to opt out), and unknown block types block. A streamed result
stops pulling from its producer, and closes it, once the stream stops
accepting. Tool and handler errors becometool_errorand are never
read. Every non-okoutcome maps to a fixedisError: true
CallToolResult(toCallToolResult), never to a JSON-RPC error.
Cancellation delivers nothing.onAuditreceives one
{ stage, outcome, reason?, code? }record per crossing. - Qualified by replaying the core's
conformance/fixtures/mcp-boundary.json
with the core's own runner (conformance/mcp-boundary.mjs), both vendored
at core commit0e3ba9592b6fa80fafdea47639921987c36ba323
(fixtures/core/pins.json), through the public API on the real core,
before and afterinitialize()(test/conformance*.test.ts). The same
fixture is replayed with real SDK clients and servers over stdio and
Streamable HTTP (test/transport.test.ts), and end to end through a host's
log, store and model context, including a real subprocess producer
(test/e2e.test.ts). - Declared ranges:
@redact-secret/core ^0.1.0-beta.6(required peer), and as
optional peers@modelcontextprotocol/sdk >=1.13.0 <=1.30.1and
@modelcontextprotocol/client/ `@modelcontextprotocol/server=2.0.0 <=2.1.0
. These are backed bytest/transport.test.tsandtest/e2e.test.tsat both endpoints of every range in CI (range-endpoints`). 1.13.0 negotiates protocol 2025-06-18; 1.30.1, 2.0.0
and 2.1.0 negotiate 2025-11-25. - Depends on
@redact-secret/adapter-ai-context ^0.1.0-alpha(which pulls in
@redact-secret/adapter ^0.1.1).
@redact-secret/adapter-otel 0.1.1
Changed
@redact-secret/adapterrange raised from^0.1.0to^0.1.1, the
version with the fail-closed walker fixes this release relies on (a
malformed scanner result, non-plain objects, throwing getters). Backed
by this package's tests, which run against the workspace's
@redact-secret/adapter0.1.1, and by the npm install smoke test.createRedactingSpanProcessorloads@redact-secret/coreon call, like
@redact-secret/adapter'screateMaskSecrets, so importing the injected
API never loads the native core. No API change.MaskLeafOptionsis re-exported for typingoptions.@redact-secret/core ^0.1.0-beta.6moves fromdependenciesto
peerDependencies, same range. As a regular dependency, a core version in
the application outside that range installed a second, separately
initialized copy of the native core. Now there is exactly one. npm 7+ and
pnpm install a required peer automatically. Backed by the same range-endpoint
CI jobs, which already resolved the core range from either field.
Deprecated
RedactAttributesOptions, an alias ofMaskLeafOptionsthat adds nothing.
It still works and will be removed in a future major version.
Fixed
onEndnever throws into the SDK. A span whose fields do not take the
masked write (for example, attributes frozen by an earlier processor) is
dropped with a one-timeREDACT_SECRET_SPAN_DROPPEDprocess warning naming
the field, never its value. Before, a frozen bag threw aTypeErrorout of
span.end(). The status is now replaced rather than mutated.- The SDK's optional
onEndinghook is now forwarded to the wrapped
processor. Before, a wrapped processor that relied on it never saw it. - The span name, every event's name, the status message, and every link's
attributes are now redacted; before, only span and event attributes were. - A string-array attribute with a
nullorundefinedelement is now
redacted element by element, keeping the holes in place. Before, any
non-string element made the whole array pass through unmasked.
@redact-secret/adapter-pino 0.1.1
Added
createRedactingStreamWrite/createRedactingStreamWriteWith, a pino
hooks.streamWritethat masks every string value in the finished JSON line.
hooks.logMethodnever sees child-logger bindings (child(),
setBindings()) ormixin()output, so withlogMethodalone a secret in
either reached the destination in plaintext. Install both hooks.
Changed
@redact-secret/adapterrange raised from^0.1.0to^0.1.1, the
version with the fail-closed walker fixes this release relies on (a
malformed scanner result, non-plain objects, throwing getters). Backed
by this package's tests, which run against the workspace's
@redact-secret/adapter0.1.1, and by the npm install smoke test.createRedactingLogMethodandcreateRedactingStreamWriteload
@redact-secret/coreon call, like@redact-secret/adapter's
createMaskSecrets, so importing the injected API never loads the native
core. No API change.formatPinoMessageis marked@internal: still exported for
compatibility, but not a supported API.@redact-secret/core ^0.1.0-beta.6moves fromdependenciesto
peerDependencies, same range. As a regular dependency, a core version in
the application outside that range installed a second, separately
initialized copy of the native core. Now there is exactly one. npm 7+ and
pnpm install a required peer automatically. Backed by the same range-endpoint
CI jobs, which already resolved the core range from either field.
Fixed
logger.error(err, "custom")now logs"custom"asmsg. Before, a leading
Errorwas rewritten to[{ err }, err.message, ...rest], which replaced
the caller's message witherr.messageand interpolated the caller's
arguments into it. The hook now hands pino a masked copy of the error that
keeps its prototype, so pino's own handling applies: the caller's message
wins, andlogger.error(err)still gets the maskederr.message.- A masked
Errorkeeps its class: pino'serrserializer now logs
type: "TypeError"(or whatever the class is) instead of"Object", for a
leadingErrorand for one under a merging-object key, whatever the
logger'serrorKeyis. Nothing in the hook assumes the key iserrany
more. logger.info(undefined, fmt, ...values)(ornullfirst) now joins the
message with its values before scanning, as pino formats it; before, the
parts were scanned separately and a secret split across them was missed.- A logger's
msgPrefixis now scanned together with the message, so a
prefix such as"api_key="gives the core the context to detect the value
that follows it. - The
logMethodhook no longer throws into pino when an argument cannot be
formatted (for example%dwith aSymbol): pino logs[REDACTED:ERROR]
instead of the raw arguments.
@redact-secret/adapter 0.1.1
Added
walkStrict(value, limits, visitors), the all-or-nothing variant of t...
Release train 2026.09.22
Release train 2026.09.22. Every package is versioned independently; this train shipped:
- @redact-secret/adapter-otel 0.1.0
- @redact-secret/adapter-pino 0.1.0
- @redact-secret/adapter 0.1.0
- redact-secret-adapters (PyPI) 0.1.0
@redact-secret/adapter-otel 0.1.0
Initial release. Not yet published — this heading gains a release date once
the Release workflow first publishes this package.
Added
createRedactingSpanProcessor, wrapping anySpanProcessor-shaped object:
redacts every string and string-array attribute on a span and its events in
onEnd, before delegating. Attribute names are not allowlisted, so
OpenInference and GenAI semantic-convention attributes are covered without
hardcoding either convention.- Declared ranges:
@redact-secret/core ^0.1.0-beta.6, peer
@opentelemetry/sdk-trace-base ^2.0.0, verified by a real span passed
throughonEndat both ends of the range, asserting the mutation actually
took effect on the real span object.
@redact-secret/adapter-pino 0.1.0
Initial release. Not yet published — this heading gains a release date once
the Release workflow first publishes this package.
Added
createRedactingLogMethod, ahooks.logMethodintegration: value-based
redaction over the exact string pino would format from a message and its
interpolation arguments, alongside — not instead of — pino's own
path-basedredactoption.- Declared ranges:
@redact-secret/core ^0.1.0-beta.6, peerpino ^10.0.0.
pino ^10.0.0is verified by a realpinologger writing to a captured
stream at both ends of the range;pino 9.xis deliberately not declared —
it may work, but it is untested, so it is not claimed.
@redact-secret/adapter 0.1.0
Initial release. Not yet published — this heading gains a release date once
the Release workflow first publishes this package.
Added
createMaskSecrets, and the lower-levelmaskLeafWith/maskLogValueWith
/maskSecretsWith, the shared fail-closed masking primitives (L1 mask-leaf
and L2 value-tree walker) every host adapter in this repository is built on.- The
[REDACTED:BLOCKED],[REDACTED:ERROR],[REDACTED:LIMIT_EXCEEDED],
and[REDACTED:CYCLE]markers, andDEFAULT_LIMITS, as public API. - Declared range:
@redact-secret/core ^0.1.0-beta.6, as an optional
peer dependency —scanAndRedactis injected, so this package works
without the core installed.
redact-secret-adapters (PyPI) 0.1.0
Initial release. Not yet published — this heading gains a release date once
the Release workflow first publishes this package.
Added
RedactSecretFilter(redact_secret_adapters.logging_filter): a
logging.Filterthat redacts a record'smsg,args, and exception info
before any handler formats it. Python's standard library has no
value-based redaction of its own.mask_secrets_with/mask_leaf_with/mask_log_value_with
(redact_secret_adapters): the shared fail-closed masking primitives,
usable directly as a masking callback (e.g. Langfuse'smask=).otelmodule (redact_secret_adapters.otel, requires theotelextra): a
SpanProcessorwrapper equivalent to the JSadapter-otelpackage. Writes
throughBoundedAttributes' backing dict, since the Python OpenTelemetry
SDK marks span and event attributes immutable once a span ends, before any
processor hook fires.- Declared ranges:
redact-secret>=0.1.0b6,<0.2;requires-python >=3.10
for the stdlibloggingintegration;otelextra:
opentelemetry-sdk>=1.16.0,<2, verified by a real span passed through a
realTracerProviderat both ends of the range.