-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(pass-style,exo): exo boundary only throws throwables (#2266)
closes: #XXXX refs: #2223 ## Description Modest step towards #2223 , - bringing all the intended safety: the exo boundary only throws throwables, and that `callWhen` async exo methods only reject with throwable reasons. - but with less flexibility: the definition of passable errors and throwables is narrower than it need be. ### Security Considerations This is one of three necessary steps towards having the exo boundaries become the new intravat defensive security boundary, rather than treating every object boundary as a potential defensive security boundary. The rationale for this step is that the throw-control-path is too hard for reviewers to pay full attention to, so we wish to prevent caps from leaking over the exo boundary via the throw path. (E prevented caps from escaping via throws in general, but we're not in a position to be able to enforce that in general within Hardened JS.) The other two steps are - Converting uses of `Far` for making far objects into making exos. - Addressing the leakage of promise settlements across exo boundaries due to the inability to synchronously enforce such a constraint on a promise passed through the boundary. ### Scaling Considerations Given that the exceptional pathways (throws and rejects) are only used for low frequency exceptional conditions, or at least exceptional conditions whose speed we don't care about, making this slow path a tiny bit slower should be inconsequential. Indeed, I expect the overall impact to be unmeasurable. (But we won't know until we measure!) ### Documentation Considerations This restriction on what can be throws across the exo boundary (or for exo async `callWhen` methods, what can be used as a rejection reason) needs to be documented. But it should not affect any normal code, and so documents an edge case. ### Testing Considerations tests included ### Compatibility Considerations If there are currently any throws or rejects that violate these constraints (likely) where other code depends on these violations (unlikely), then we have a compat problem. ### Upgrade Considerations None. - ~[ ] Includes `*BREAKING*:` in the commit message with migration instructions for any breaking change.~ - [x] Updates `NEWS.md` for user-facing changes.
- Loading branch information
Showing
7 changed files
with
224 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import test from '@endo/ses-ava/prepare-endo.js'; | ||
|
||
import { makeError } from '@endo/errors'; | ||
import { Far, isPassable } from '@endo/pass-style'; | ||
import { M } from '@endo/patterns'; | ||
import { makeExo } from '../src/exo-makers.js'; | ||
|
||
const { defineProperty } = Object; | ||
|
||
const thrower = makeExo( | ||
'Thrower', | ||
M.interface('Thrower', { | ||
throw: M.call(M.raw()).returns(M.any()), | ||
reject: M.callWhen(M.raw()).returns(M.any()), | ||
}), | ||
{ | ||
throw(val) { | ||
throw val; | ||
}, | ||
reject(val) { | ||
throw val; | ||
}, | ||
}, | ||
); | ||
|
||
test('exo only throwables', async t => { | ||
const e = makeError('test error', undefined, { | ||
sanitize: false, | ||
}); | ||
|
||
// Remotables cannot be in passable errors or throwables | ||
defineProperty(e, 'foo', { value: Far('Foo', {}) }); | ||
|
||
let caught; | ||
try { | ||
thrower.throw(e); | ||
} catch (thrown) { | ||
caught = thrown; | ||
} | ||
t.false(isPassable(e)); | ||
t.true(isPassable(caught)); | ||
t.log('throw caught', caught); | ||
|
||
try { | ||
await thrower.reject(e); | ||
} catch (thrown) { | ||
caught = thrown; | ||
} | ||
t.true(isPassable(caught)); | ||
t.log('reject caught', caught); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters