Skip to content

Commit e7158a9

Browse files
committed
fix(ses,lockdown): make filenames in stacktraces clickable
1 parent 4f519e4 commit e7158a9

12 files changed

+115
-42
lines changed

packages/lockdown/commit-debug.js

+10-6
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ lockdown({
2121
// NOTE TO REVIEWERS: If you see the following line commented out,
2222
// this may be a development accident that should be fixed before merging.
2323
//
24-
errorTaming: 'unsafe-debug',
24+
errorTaming: 'unsafe',
2525

2626
// The default `{stackFiltering: 'concise'}` setting usually makes for a
2727
// better debugging experience, by severely reducing the noisy distractions
2828
// of the normal verbose stack traces. Which is why we comment
29-
// out the `'verbose'` setting is commented out below. However, some
30-
// tools look for the full filename that it expects in order
29+
// out the other settings below. However, some
30+
// tools look for the full filename path that it expects in order
3131
// to fetch the source text for diagnostics,
3232
//
3333
// Another reason for not commenting it out: The cause
@@ -36,10 +36,14 @@ lockdown({
3636
// uncomment out the following line. But please do not commit it in that
3737
// state.
3838
//
39-
// NOTE TO REVIEWERS: If you see the following line *not* commented out,
40-
// this may be a development accident that MUST be fixed before merging.
39+
// NOTE TO REVIEWERS: If you see the `stackFiltering` settings *not*
40+
// commented out below, this may be a development accident that MUST be
41+
// fixed before merging.
4142
//
42-
// stackFiltering: 'verbose',
43+
// stackFiltering: 'concise', // Omit frames and shorten paths
44+
// stackFiltering: 'omit-frames', // Only omit frames. Do not shorten paths
45+
// stackFiltering: 'shorten-paths', // Only shorten paths. Do not omit frames
46+
// stackFiltering: 'verbose', // Do not omit frames or shorten paths
4347

4448
// The default `{overrideTaming: 'moderate'}` setting does not hurt the
4549
// debugging experience much. But it will introduce noise into, for example,

packages/lockdown/pre.js

+12-11
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,12 @@ export const lockdown = defaultOptions => {
102102
// this may be a development accident that MUST be fixed before merging.
103103
//
104104
// errorTaming: 'unsafe',
105-
//
106-
//
105+
107106
// The default `{stackFiltering: 'concise'}` setting usually makes for a
108107
// better debugging experience, by severely reducing the noisy distractions
109108
// of the normal verbose stack traces. Which is why we comment
110-
// out the `'verbose'` setting is commented out below. However, some
111-
// tools look for the full filename that it expects in order
109+
// out the other settings below. However, some
110+
// tools look for the full filename path that it expects in order
112111
// to fetch the source text for diagnostics,
113112
//
114113
// Another reason for not commenting it out: The cause
@@ -117,12 +116,15 @@ export const lockdown = defaultOptions => {
117116
// uncomment out the following line. But please do not commit it in that
118117
// state.
119118
//
120-
// NOTE TO REVIEWERS: If you see the following line *not* commented out,
121-
// this may be a development accident that MUST be fixed before merging.
122-
//
123-
// stackFiltering: 'verbose',
124-
//
119+
// NOTE TO REVIEWERS: If you see the `stackFiltering` settings *not*
120+
// commented out below, this may be a development accident that MUST be
121+
// fixed before merging.
125122
//
123+
// stackFiltering: 'concise', // Omit frames and shorten paths
124+
// stackFiltering: 'omit-frames', // Only omit frames. Do not shorten paths
125+
// stackFiltering: 'shorten-paths', // Only shorten paths. Do not omit frames
126+
// stackFiltering: 'verbose', // Do not omit frames or shorten paths
127+
126128
// The default `{overrideTaming: 'moderate'}` setting does not hurt the
127129
// debugging experience much. But it will introduce noise into, for example,
128130
// the vscode debugger's object inspector. During debug and test, if you can
@@ -134,8 +136,7 @@ export const lockdown = defaultOptions => {
134136
// this may be a development accident that MUST be fixed before merging.
135137
//
136138
// overrideTaming: 'min',
137-
//
138-
//
139+
139140
// The default `{consoleTaming: 'safe'}` setting usually makes for a
140141
// better debugging experience, by wrapping the original `console` with
141142
// the SES replacement `console` that provides more information about

packages/ses-ava/test/raw-ava-reject.test.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ lockdown({
1515
// the current relevant environment variable setting. To get results
1616
// independent of that, always uncomment one setting for each switch.
1717
//
18-
stackFiltering: 'concise', // Default. Hide infrastructure, shorten paths
19-
// stackFiltering: 'verbose', // Include `assert` infrastructure
18+
stackFiltering: 'concise', // Default. Omit likely uninteresting frames. Shorten paths
19+
// stackFiltering: 'omit-frames', // Only omit infrastructure frames
20+
// stackFiltering: 'shorten-paths', // Only shorten paths
21+
// stackFiltering: 'verbose', // Original frames with original paths
2022
consoleTaming: 'safe', // Default. Console with access to redacted info
2123
// consoleTaming: 'unsafe', // Host console lacks access to redacted info
2224
// errorTaming: 'safe', // Default. Hide redacted info on error

packages/ses-ava/test/raw-ava-throw.test.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ lockdown({
1515
// the current relevant environment variable setting. To get results
1616
// independent of that, always uncomment one setting for each switch.
1717
//
18-
stackFiltering: 'concise', // Default. Hide infrastructure, shorten paths
19-
// stackFiltering: 'verbose', // Include `assert` infrastructure
18+
stackFiltering: 'concise', // Default. Omit likely uninteresting frames. Shorten paths
19+
// stackFiltering: 'omit-frames', // Only omit infrastructure frames
20+
// stackFiltering: 'shorten-paths', // Only shorten paths
21+
// stackFiltering: 'verbose', // Original frames with original paths
2022
consoleTaming: 'safe', // Default. Console with access to redacted info
2123
// consoleTaming: 'unsafe', // Host console lacks access to redacted info
2224
// errorTaming: 'safe', // Default. Hide redacted info on error

packages/ses-ava/test/ses-ava-reject.test.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ lockdown({
1616
// the current relevant environment variable setting. To get results
1717
// independent of that, always uncomment one setting for each switch.
1818
//
19-
stackFiltering: 'concise', // Default. Hide infrastructure, shorten paths
20-
// stackFiltering: 'verbose', // Include `assert` infrastructure
19+
stackFiltering: 'concise', // Default. Omit likely uninteresting frames. Shorten paths
20+
// stackFiltering: 'omit-frames', // Only omit infrastructure frames
21+
// stackFiltering: 'shorten-paths', // Only shorten paths
22+
// stackFiltering: 'verbose', // Original frames with original paths
2123
consoleTaming: 'safe', // Default. Console with access to redacted info
2224
// consoleTaming: 'unsafe', // Host console lacks access to redacted info
2325
// errorTaming: 'safe', // Default. Hide redacted info on error

packages/ses-ava/test/ses-ava-throw.test.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ lockdown({
1616
// the current relevant environment variable setting. To get results
1717
// independent of that, always uncomment one setting for each switch.
1818
//
19-
stackFiltering: 'concise', // Default. Hide infrastructure, shorten paths
20-
// stackFiltering: 'verbose', // Include `assert` infrastructure
19+
stackFiltering: 'concise', // Default. Omit likely uninteresting frames. Shorten paths
20+
// stackFiltering: 'omit-frames', // Only omit infrastructure frames
21+
// stackFiltering: 'shorten-paths', // Only shorten paths
22+
// stackFiltering: 'verbose', // Original frames with original paths
2123
consoleTaming: 'safe', // Default. Console with access to redacted info
2224
// consoleTaming: 'unsafe', // Host console lacks access to redacted info
2325
// errorTaming: 'safe', // Default. Hide redacted info on error

packages/ses/NEWS.md

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
User-visible changes in `ses`:
22

3-
# v1.12.0 (2025-03-11)
3+
# Next release
4+
5+
- Two new `stackFiltering:` options are added
6+
- `'omit-frames'` -- Only omit likely uninteresting frames. Keep original paths.
7+
- `'shorten-paths'` -- Only shorten paths to text likely clickable in an IDE
48

5-
- The `evalTaming:` option values are renamed:
9+
This fills out the matrix of what should have been orthogonal options.
10+
The existing `'concise'` setting both omits likely uninteresting frames and
11+
shortens their paths. The existing `'verbose'` setting does neither.
12+
13+
# v1.12.0 (2025-03-11)
614

15+
- The `evalTaming:` option values are renamed
716
- from `'safeEval'`, `'unsafeEval'`, and `'noEval'`
817
- to `'safe-eval'`, `'unsafe-eval'`, and `'no-eval'`
918

packages/ses/docs/lockdown.md

+9-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Each option is explained in its own section below.
3030
| `reporting` | `'platform'` | `'console'` `'none'` | where to report warnings ([details](#reporting-options))
3131
| `unhandledRejectionTrapping` | `'report'` | `'none'` | handling of finalized unhandled rejections ([details](#unhandledrejectiontrapping-options)) |
3232
| `evalTaming` | `'safe-eval'` | `'unsafe-eval'` `'no-eval'` | `eval` and `Function` of the start compartment ([details](#evaltaming-options)) |
33-
| `stackFiltering` | `'concise'` | `'verbose'` | deep stacks signal/noise ([details](#stackfiltering-options)) |
33+
| `stackFiltering` | `'concise'` | `'omit-frames'` `'shorten-paths'` `'verbose'` | deep stacks signal/noise ([details](#stackfiltering-options)) |
3434
| `overrideTaming` | `'moderate'` | `'min'` or `'severe'` | override mistake antidote ([details](#overridetaming-options)) |
3535
| `overrideDebug` | `[]` | array of property names | detect override mistake ([details](#overridedebug-options)) |
3636
| `domainTaming` | `'safe'` | `'unsafe'` | Node.js `domain` module ([details](#domaintaming-options)) |
@@ -633,7 +633,11 @@ bugs.
633633
```js
634634
lockdown(); // stackFiltering defaults to 'concise'
635635
// or
636-
lockdown({ stackFiltering: 'concise' }); // Preserve important deep stack info
636+
lockdown({ stackFiltering: 'concise' }); // Preserve important deep stack info. Omit likely uninteresting frames. Shorten paths to likely clickable strings in an IDE
637+
// vs
638+
lockdown({ stackFiltering: 'omit-frames' }); // Only omit likely uninteresting frames. Preserve original paths
639+
// vs
640+
lockdown({ stackFiltering: 'shorten-paths' }); // Preserve original frames. shorten their paths to likely clickable strings in an IDE.
637641
// vs
638642
lockdown({ stackFiltering: 'verbose' }); // Console shows full deep stacks
639643
```
@@ -643,6 +647,8 @@ If `lockdown` does not receive a `stackFiltering` option, it will respect
643647

644648
```console
645649
LOCKDOWN_STACK_FILTERING=concise
650+
LOCKDOWN_STACK_FILTERING=omit-frames
651+
LOCKDOWN_STACK_FILTERING=shorten-paths
646652
LOCKDOWN_STACK_FILTERING=verbose
647653
```
648654

@@ -659,7 +665,7 @@ that information is no longer an extraneous distraction. Sometimes the noise
659665
you filter out actually contains the signal you're looking for. The
660666
`'verbose'` setting shows, on the console, the full raw stack information
661667
for each level of the deep stacks.
662-
Either setting of `stackFiltering` setting is safe. Stack information will
668+
Any setting of `stackFiltering` is safe. Stack information will
663669
or will not be available from error objects according to the `errorTaming`
664670
option and the platform error behavior.
665671

packages/ses/docs/reference.md

+9-3
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,10 @@ below.
178178
</tr>
179179
<tr>
180180
<td><code>stackFiltering</code></td>
181-
<td><code>'concise'</code> (default) or <code>'verbose'</code></td>
182-
<td><code>'concise'</code> preserves important deep stack info,<br>
181+
<td><code>'concise'</code> (default) or <code>'omit-frames'</code> or <code>'shorten-paths'</code> or <code>'verbose'</code></td>
182+
<td><code>'concise'</code> preserves important deep stack info, omitting likely unimportant frames and shortening paths<br>
183+
<code>'omit-frames'</code> omits likely unimportant frames<br>
184+
<code>'shorten-paths'</code> shortens paths to text likely clickable in an IDE<br>
183185
<code>'verbose'</code> console shows full deep stacks</td>
184186
</tr>
185187
<tr>
@@ -314,7 +316,11 @@ option and the platform error behavior.
314316
```js
315317
lockdown(); // stackFiltering defaults to 'concise'
316318
// or
317-
lockdown({ stackFiltering: 'concise' }); // Preserve important deep stack info
319+
lockdown({ stackFiltering: 'concise' }); // Preserve important deep stack info, omitting likely unimportant frames and shortening paths
320+
// vs
321+
lockdown({ stackFiltering: 'omit-frames' }); // Omit likely uninteresting frames
322+
// vs
323+
lockdown({ stackFiltering: 'shorten-paths' }); // Shorten paths to text likely clickable in an IDE
318324
// vs
319325
lockdown({ stackFiltering: 'verbose' }); // Console shows full deep stacks
320326
```

packages/ses/src/error/tame-v8-error-constructor.js

+42-7
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,19 @@ export const filterFileName = fileName => {
120120
//
121121
// See thread starting at
122122
// https://github.com/Agoric/agoric-sdk/issues/2326#issuecomment-773020389
123-
const CALLSITE_ELLIPSES_PATTERN = /^((?:.*[( ])?)[:/\w_-]*\/\.\.\.\/(.+)$/;
123+
const CALLSITE_ELLIPSIS_PATTERN1 = /^((?:.*[( ])?)[:/\w_-]*\/\.\.\.\/(.+)$/;
124+
125+
// The ad-hoc rule of the current pattern is that any likely-file-path or
126+
// likely url-path prefix consisting of `.../` should get dropped.
127+
// Anything to the left of the likely path text is kept.
128+
// Everything to the right of `.../` is kept. Thus
129+
// `'Object.bar (.../eventual-send/test/test-deep-send.js:13:21)'`
130+
// simplifies to
131+
// `'Object.bar (eventual-send/test/test-deep-send.js:13:21)'`.
132+
//
133+
// See thread starting at
134+
// https://github.com/Agoric/agoric-sdk/issues/2326#issuecomment-773020389
135+
const CALLSITE_ELLIPSIS_PATTERN2 = /^((?:.*[( ])?)\.\.\.\/(.+)$/;
124136

125137
// The ad-hoc rule of the current pattern is that any likely-file-path or
126138
// likely url-path prefix, ending in a `/` and prior to `package/` should get
@@ -134,21 +146,38 @@ const CALLSITE_ELLIPSES_PATTERN = /^((?:.*[( ])?)[:/\w_-]*\/\.\.\.\/(.+)$/;
134146
// lerna.
135147
const CALLSITE_PACKAGES_PATTERN = /^((?:.*[( ])?)[:/\w_-]*\/(packages\/.+)$/;
136148

149+
// The ad-hoc rule of the current pattern is that any likely-file-path or
150+
// likely url-path prefix of the form `file://` but not `file:///` gets
151+
// dropped.
152+
// Anything to the left of the likely path prefix text is kept. Everything to
153+
// the right of `file://` is kept. Thus
154+
// `'Object.bar (file:///Users/markmiller/src/ongithub/agoric/agoric-sdk/packages/eventual-send/test/test-deep-send.js:13:21)'` is unchanged but
155+
// `'Object.bar (file://test/test-deep-send.js:13:21)'`
156+
157+
// simplifies to
158+
// `'Object.bar (test/test-deep-send.js:13:21)'`.
159+
const CALLSITE_FILE_2SLASH_PATTERN = /^((?:.*[( ])?)file:\/\/([^/].*)$/;
160+
137161
// The use of these callSite patterns below assumes that any match will bind
138162
// capture groups containing the parts of the original string we want
139163
// to keep. The parts outside those capture groups will be dropped from concise
140164
// stacks.
141165
// TODO Enable users to configure CALLSITE_PATTERNS via `lockdown` options.
142166
const CALLSITE_PATTERNS = [
143-
CALLSITE_ELLIPSES_PATTERN,
167+
CALLSITE_ELLIPSIS_PATTERN1,
168+
CALLSITE_ELLIPSIS_PATTERN2,
144169
CALLSITE_PACKAGES_PATTERN,
170+
CALLSITE_FILE_2SLASH_PATTERN,
145171
];
146172

147173
// For a stack frame that should be included in a concise stack trace, if
148174
// `callSiteString` is the original stringified stack frame, return the
149175
// possibly-shorter stringified stack frame that should be shown instead.
150176
// Exported only so it can be unit tested.
151177
// TODO Move so that it applies not just to v8.
178+
/**
179+
* @param {string} callSiteString
180+
*/
152181
export const shortenCallSiteString = callSiteString => {
153182
for (const filter of CALLSITE_PATTERNS) {
154183
const match = regexpExec(filter, callSiteString);
@@ -175,18 +204,24 @@ export const tameV8ErrorConstructor = (
175204

176205
const originalCaptureStackTrace = OriginalError.captureStackTrace;
177206

207+
const omitFrames =
208+
stackFiltering === 'concise' || stackFiltering === 'omit-frames';
209+
210+
const shortenPaths =
211+
stackFiltering === 'concise' || stackFiltering === 'shorten-paths';
212+
178213
// const callSiteFilter = _callSite => true;
179214
const callSiteFilter = callSite => {
180-
if (stackFiltering === 'verbose') {
181-
return true;
215+
if (omitFrames) {
216+
// eslint-disable-next-line @endo/no-polymorphic-call
217+
return filterFileName(callSite.getFileName());
182218
}
183-
// eslint-disable-next-line @endo/no-polymorphic-call
184-
return filterFileName(callSite.getFileName());
219+
return true;
185220
};
186221

187222
const callSiteStringifier = callSite => {
188223
let callSiteString = `${callSite}`;
189-
if (stackFiltering === 'concise') {
224+
if (shortenPaths) {
190225
callSiteString = shortenCallSiteString(callSiteString);
191226
}
192227
return `\n at ${callSiteString}`;

packages/ses/src/lockdown.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,11 @@ export const repairIntrinsics = (options = {}) => {
189189
overrideTaming = /** @type {'moderate' | 'min' | 'severe'} */ (
190190
getenv('LOCKDOWN_OVERRIDE_TAMING', 'moderate', ['min', 'severe'])
191191
),
192-
stackFiltering = getenv('LOCKDOWN_STACK_FILTERING', 'concise', ['verbose']),
192+
stackFiltering = getenv('LOCKDOWN_STACK_FILTERING', 'concise', [
193+
'omit-frames',
194+
'shorten-paths',
195+
'verbose',
196+
]),
193197
domainTaming = getenv('LOCKDOWN_DOMAIN_TAMING', 'safe', ['unsafe']),
194198
evalTaming = getenv('LOCKDOWN_EVAL_TAMING', 'safe-eval', [
195199
'unsafe-eval',

packages/ses/types.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export interface RepairOptions {
4343
| 'safeEval'
4444
| 'unsafeEval'
4545
| 'noEval';
46-
stackFiltering?: 'concise' | 'verbose';
46+
stackFiltering?: 'concise' | 'omit-frames' | 'shorten-paths' | 'verbose';
4747
overrideTaming?: 'moderate' | 'min' | 'severe';
4848
overrideDebug?: Array<string>;
4949
domainTaming?: 'safe' | 'unsafe';

0 commit comments

Comments
 (0)