Skip to content

feat: add sensitive struct#41

Open
ccharly wants to merge 15 commits into
mainfrom
cc/feat/superstruct-sensitive
Open

feat: add sensitive struct#41
ccharly wants to merge 15 commits into
mainfrom
cc/feat/superstruct-sensitive

Conversation

@ccharly

@ccharly ccharly commented Jul 2, 2026

Copy link
Copy Markdown

Add a new struct sensitive that can used with object or type. Any value for this field will get redacted automatically if any validation/errors happen.

This also apply if a sibling field validation is failing, so there's no way to make the value escape out of the actual payload being validated.


Note

Medium Risk
Changes failure payloads and messages for schemas using sensitive fields—intentional for security but may break consumers that logged full values; validation semantics are unchanged.

Overview
Adds sensitive(), a struct wrapper that keeps validation behavior the same but replaces secret material in failures with *** (SENSITIVE_REDACTED) in value, default message, and branch (including nested entry failures and refiner names without leaking the raw value).

object() and type() now detect sensitive-marked fields and wrap sibling entry structs so when another field fails, parent objects in branch are shallow-copied with sensitive keys redacted; this uses context.branch so coercion does not break reference matching.

The Struct constructor copies Symbol-keyed properties from spread props so brands (e.g. after optional) still propagate. Public exports include sensitive and SENSITIVE_REDACTED; changelog and validation tests cover siblings, coercion, exactOptional, outer sensitive(object(...)), and non-plain objects.

Reviewed by Cursor Bugbot for commit 37ec520. Bugbot is set up for automated code reviews on this repo. Configure here.

@ccharly ccharly force-pushed the cc/feat/superstruct-sensitive branch from e0df198 to 2a040a5 Compare July 2, 2026 12:52
@ccharly ccharly marked this pull request as ready for review July 2, 2026 14:31
@ccharly ccharly requested a review from a team as a code owner July 2, 2026 14:31

@cursor cursor 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.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d5a2529. Configure here.

Comment thread src/structs/types.ts Outdated
Comment thread src/structs/types.ts
Comment thread src/struct.ts
Comment on lines +74 to +85
// Copy Symbol-keyed properties from `props` so that brands set on an inner
// struct (e.g. the sensitive marker) are automatically inherited by any
// wrapper that spreads the struct into a new constructor call.
for (const sym of Object.getOwnPropertySymbols(props)) {
Object.defineProperty(
this,
sym,
// No need to check for undefined, since we are iterating over
// `Object.getOwnPropertySymbols`.
Object.getOwnPropertyDescriptor(props, sym) as PropertyDescriptor,
);
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This is necessary to forward the brand (marker) inside structs when we are re-constructing them.

Type-wise, that does not change anything, those are just plain symbols that are used as markers for us to detect later if a re-constructed struct was banded as sensitive (we could use this same logic for other kind of decorators in the future too).

Comment thread src/structs/sensitive.ts Outdated
Comment thread src/structs/sensitive.ts Outdated
Comment thread test/validation/sensitive/invalid-outer-object.ts
Comment thread src/structs/sensitive.ts Outdated
Comment thread src/structs/sensitive.ts Outdated
@hmalik88 hmalik88 requested a review from Mrtenz July 8, 2026 09:19

@hmalik88 hmalik88 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.

LGTM, but want @Mrtenz to take a final look 🙇‍♂️

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.

2 participants