What to declassify
Optional
spaces: string | numberUse the details
function as a template literal tag to create
informative error messages. The assertion functions take such messages
as optional arguments:
assert(sky.isBlue(), details`${sky.color} should be "blue"`);
or following the normal convention to locally rename details
to X
and quote
to q
like const { details: X, quote: q } = assert;
:
assert(sky.isBlue(), X`${sky.color} should be "blue"`);
However, note that in most cases it is preferable to instead use the Fail
template literal tag (which has the same input signature as details
but automatically creates and throws an error):
sky.isBlue() || Fail`${sky.color} should be "blue"`;
The details template tag returns a DetailsToken
object that can print
itself with the formatted message in two ways.
It will report full details to the console, but
mask embedded substitution values with their typeof information in the thrown error
to prevent revealing secrets up the exceptional path. In the example
above, the thrown error may reveal only that sky.color
is a string,
whereas the same diagnostic printed to the console reveals that the
sky was green. This masking can be disabled for an individual substitution value
using quote
.
The raw
property of an input template array is ignored, so a simple
array of strings may be provided directly.
Aka the makeError
function as imported from @endo/errors
Recording unredacted details for the console.
Optional
details: DetailsThe details of what was asserted
Optional
errConstructor: GenericErrorConstructorAn optional alternate error constructor to use
Optional
options: AssertMakeErrorOptionsUse the Fail
function as a template literal tag to efficiently
create and throw a details
-style error only when a condition is not satisfied.
condition || Fail`...complaint...`;
This avoids the overhead of creating usually-unnecessary errors like
assert(condition, details`...complaint...`);
while improving readability over alternatives like
condition || assert.fail(details`...complaint...`);
However, due to current weakness in TypeScript, static reasoning
is less powerful with the ||
patterns than with an assert
call.
Until/unless https://github.com/microsoft/TypeScript/issues/51426 is fixed,
for ||
-style assertions where this loss of static reasoning is a problem,
instead express the assertion as
if (!condition) {
Fail`...complaint...`;
}
or, if needed,
if (!condition) {
// `throw` is noop since `Fail` throws, but it improves static analysis
throw Fail`...complaint...`;
}
Aka the annotateError
function as imported from @endo/errors
Annotate an error with details, potentially to be used by an
augmented console such as the causal console of console.js
, to
provide extra information associated with logged errors.
To "declassify" and quote a substitution value used in a
details`...`
template literal, enclose that substitution expression
in a call to quote
. This makes the value appear quoted
(as if with JSON.stringify
) in the message of the thrown error. The
payload itself is still passed unquoted to the console as it would be
without quote
.
For example, the following will reveal the expected sky color, but not the actual incorrect sky color, in the thrown error's message:
sky.color === expectedColor || Fail`${sky.color} should be ${quote(expectedColor)}`;
The normal convention is to locally rename details
to X
and quote
to q
like const { details: X, quote: q } = assert;
, so the above example would then be
sky.color === expectedColor || Fail`${sky.color} should be ${q(expectedColor)}`;
What to declassify
Optional
spaces: string | number
Embed a string directly into error details without wrapping punctuation. To avoid injection attacks that exploit quoting confusion, this must NEVER be used with data that is possibly attacker-controlled. As a further safeguard, we fall back to quoting any input that is not a string of sufficiently word-like parts separated by isolated spaces (rather than throwing an exception, which could hide the original problem for which explanatory details are being constructed---i.e.,
assert.details`...`
should never be the source of a new exception, nor should an attempt to render its output, although we could instead decide to handle the latter by inline replacement similar to that ofbestEffortStringify
for producing rendered messages like(an object) was tagged "[Unsafe bare string]"
).