[DO NOT MERGE] feat(core): add opt-in assertion instrumentation - #6592
[DO NOT MERGE] feat(core): add opt-in assertion instrumentation#6592antonis wants to merge 11 commits into
6 issues
find-bugs: Found 7 issues (1 high, 3 medium, 3 low)
High
Error constructor capture breaks on top-level Error declarations - `packages/core/test/tools/sentryAssertionBabelPlugin.test.ts:39-45`
The hoisted var _Error = Error; alias at program top fails when a module declares a top-level let, const, or var named Error, causing a ReferenceError on load or a TypeError when the assertion fires.
Also found at:
packages/core/src/js/tools/sentryBabelTransformerUtils.ts:5
Medium
formatMessage crashes reporting path on non-coercible format args - `packages/core/src/js/assertion.ts:158-162`
The %d, %i, and %f format specifiers call Number(arg) without a try-catch, so a Symbol, BigInt, or object with a throwing valueOf crashes the reporting path instead of reporting safely.
Also found at:
packages/core/src/js/assertion.ts:244packages/core/src/js/tools/sentryBabelTransformerUtils.ts:8packages/core/test/tools/sentryAssertionBabelPlugin.test.ts:51-54
Short-circuited TDZ identifiers crash on the report path - `packages/core/src/js/tools/sentryAssertionBabelPlugin.ts:493-500`
collectValueIdentifiers can emit identifiers that are in the temporal dead zone; evaluating them on the failure path throws a ReferenceError instead of reporting the assertion cleanly.
Assertion transform changes semantics when call is used as an expression - `packages/core/src/js/tools/sentryAssertionBabelPlugin.ts:570-571`
The Babel plugin unconditionally replaces every matched CallExpression with condition || reportCall() via path.replaceWith(). Because the original assertion pragmas (invariant, assert, warning, console.assert) return undefined (falsy), the replacement alters the resulting value and control flow when the call is not a standalone statement. For example, warning(cond) && next() becomes (cond || reportCall()) && next(); if cond is falsy, reportCall() returns a truthy event-id string, so next() runs even though the original warning would have returned undefined and skipped it. Similarly, assert(cond) && next() with a truthy cond evaluates to cond (truthy) after transformation, causing next() to run, whereas the original assert returns undefined (falsy) and would skip it. No parent-context check restricts the rewrite to ExpressionStatement nodes, and no tests cover expression-context usages.
Low
captureAssertionViolation return type promises string but can return undefined - `packages/core/src/js/assertion.ts:322`
Return eventId ?? '' instead of raw eventId so the public API always returns a string as declared.
Error message backfill throws TypeError when error has a read-only message property - `packages/core/test/assertion.test.ts:133`
In packages/core/src/js/assertion.ts, the unguarded error.message = message assignment throws when options.error has a non-writable message property (e.g., a frozen or sealed Error). Because the file is an ES module and runs in strict mode, this can turn a report-only assertion into an unexpected crash and prevents hard preconditions from re-throwing their original error.
flattenValues can throw on exotic values objects - `packages/core/test/assertion.test.ts:177`
In packages/core/src/js/assertion.ts, flattenValues calls Object.keys(values) without a surrounding try-catch. While the captureAssertionViolation caller already guards against null/undefined, a Proxy or exotic object with a throwing [[OwnPropertyKeys]] trap would still cause Object.keys to throw, propagating out of a function explicitly designed to be defensive and never throw.
⏱ 50m 3s · 9.0M in / 881.7k out · $4.07
Annotations
Check failure on line 45 in packages/core/test/tools/sentryAssertionBabelPlugin.test.ts
sentry-warden / warden: find-bugs
Error constructor capture breaks on top-level Error declarations
The hoisted `var _Error = Error;` alias at program top fails when a module declares a top-level `let`, `const`, or `var` named `Error`, causing a ReferenceError on load or a TypeError when the assertion fires.
Check failure on line 5 in packages/core/src/js/tools/sentryBabelTransformerUtils.ts
sentry-warden / warden: find-bugs
[YB5-NU3] Error constructor capture breaks on top-level Error declarations (additional location)
The hoisted `var _Error = Error;` alias at program top fails when a module declares a top-level `let`, `const`, or `var` named `Error`, causing a ReferenceError on load or a TypeError when the assertion fires.
Check warning on line 162 in packages/core/src/js/assertion.ts
sentry-warden / warden: find-bugs
formatMessage crashes reporting path on non-coercible format args
The %d, %i, and %f format specifiers call Number(arg) without a try-catch, so a Symbol, BigInt, or object with a throwing valueOf crashes the reporting path instead of reporting safely.
Check warning on line 244 in packages/core/src/js/assertion.ts
sentry-warden / warden: find-bugs
[ZPD-B7P] formatMessage crashes reporting path on non-coercible format args (additional location)
The %d, %i, and %f format specifiers call Number(arg) without a try-catch, so a Symbol, BigInt, or object with a throwing valueOf crashes the reporting path instead of reporting safely.
Check warning on line 8 in packages/core/src/js/tools/sentryBabelTransformerUtils.ts
sentry-warden / warden: find-bugs
[ZPD-B7P] formatMessage crashes reporting path on non-coercible format args (additional location)
The %d, %i, and %f format specifiers call Number(arg) without a try-catch, so a Symbol, BigInt, or object with a throwing valueOf crashes the reporting path instead of reporting safely.
Check warning on line 54 in packages/core/test/tools/sentryAssertionBabelPlugin.test.ts
sentry-warden / warden: find-bugs
[ZPD-B7P] formatMessage crashes reporting path on non-coercible format args (additional location)
The %d, %i, and %f format specifiers call Number(arg) without a try-catch, so a Symbol, BigInt, or object with a throwing valueOf crashes the reporting path instead of reporting safely.
Check warning on line 500 in packages/core/src/js/tools/sentryAssertionBabelPlugin.ts
sentry-warden / warden: find-bugs
Short-circuited TDZ identifiers crash on the report path
`collectValueIdentifiers` can emit identifiers that are in the temporal dead zone; evaluating them on the failure path throws a `ReferenceError` instead of reporting the assertion cleanly.
Check warning on line 571 in packages/core/src/js/tools/sentryAssertionBabelPlugin.ts
sentry-warden / warden: find-bugs
Assertion transform changes semantics when call is used as an expression
The Babel plugin unconditionally replaces every matched `CallExpression` with `condition || reportCall()` via `path.replaceWith()`. Because the original assertion pragmas (`invariant`, `assert`, `warning`, `console.assert`) return `undefined` (falsy), the replacement alters the resulting value and control flow when the call is not a standalone statement. For example, `warning(cond) && next()` becomes `(cond || reportCall()) && next()`; if `cond` is falsy, `reportCall()` returns a truthy event-id string, so `next()` runs even though the original `warning` would have returned `undefined` and skipped it. Similarly, `assert(cond) && next()` with a truthy `cond` evaluates to `cond` (truthy) after transformation, causing `next()` to run, whereas the original `assert` returns `undefined` (falsy) and would skip it. No parent-context check restricts the rewrite to `ExpressionStatement` nodes, and no tests cover expression-context usages.