Skip to content

Commit 0cf6eed

Browse files
committed
fix(spec): the credential walk reads a schema's public def, so an instrumented lazy schema derives instead of throwing (#24994)
Claude-Session: https://claude.ai/code/session_01D6F9axfoPzR7t8G1J7Ytzz Co-authored-by: Claude <noreply@anthropic.com>
1 parent 441ce01 commit 0cf6eed

2 files changed

Lines changed: 20 additions & 2 deletions

File tree

‎packages/spec/src/kernel/metadata-credential-fields.ts‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,19 @@ interface ZodDefLike {
8888
shape?: Record<string, unknown>;
8989
}
9090

91-
/** The `_zod.def` of a schema, or `undefined` for anything that is not one. */
91+
/**
92+
* The definition of a schema, or `undefined` for anything that is not one.
93+
*
94+
* Read through the public `.def` first, and `_zod.def` only for a core schema
95+
* that has no `.def`: a `lazySchema` Proxy reports `_zod` as a non-configurable
96+
* own property its function target does not have, so a second Proxy wrapped
97+
* around it (a test that instruments a registered schema does exactly this)
98+
* throws a Proxy invariant TypeError on any `_zod` read, while `.def` resolves.
99+
*/
92100
export function zodDefOf(schema: unknown): ZodDefLike | undefined {
93101
if (!schema || (typeof schema !== 'object' && typeof schema !== 'function')) return undefined;
102+
const publicDef = (schema as { def?: ZodDefLike }).def;
103+
if (publicDef && typeof publicDef === 'object' && typeof publicDef.type === 'string') return publicDef;
94104
const internals = (schema as { _zod?: { def?: ZodDefLike } })._zod;
95105
return internals?.def;
96106
}

‎packages/spec/src/kernel/metadata-type-redaction.test.ts‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import {
3030
type MetadataTypeRedactor,
3131
} from './metadata-type-redaction';
3232
import { z } from 'zod';
33-
import { registerMetadataTypeSchema } from './metadata-type-schemas';
33+
import { getMetadataTypeSchema as getMetadataTypeSchemaForTest, registerMetadataTypeSchema } from './metadata-type-schemas';
3434

3535
describe('register/lookup round trip (the registry pattern of registerMetadataTypeSchema)', () => {
3636
it('a registered redactor is returned for its type', () => {
@@ -351,6 +351,14 @@ describe('[ruling B+ on #24966] the third resolution: a redactor DERIVED from th
351351
expect(result.redactedKeys).toEqual(['config.password']);
352352
});
353353

354+
it('derives through a registered schema wrapped in a second Proxy (an instrumented lazy schema)', () => {
355+
const webhook = getMetadataTypeSchemaForTest('webhook');
356+
const wrapped = new Proxy(webhook as object, { get: (t, p, r) => Reflect.get(t, p, r) });
357+
registerMetadataTypeSchema('zz_proxied_rule_test', wrapped as never);
358+
const result = getMetadataTypeRedactor('zz_proxied_rule_test')!(declaredWebhook());
359+
expect(result.redactedKeys).toEqual(['headers', 'secret']);
360+
});
361+
354362
it('the derivation is memoised per schema identity: one redactor across lookups', () => {
355363
expect(getMetadataTypeRedactor('webhook')).toBe(getMetadataTypeRedactor('webhook'));
356364
});

0 commit comments

Comments
 (0)