Repository navigation
Move the transaction policy engine to @tetherto/wdk-policies - #127
Conversation
The policy engine is opt-in and imports nothing from the rest of core,
only zod, yet every install of @tetherto/wdk ships it. It moves to
tetherto/wdk-policies and is published as @tetherto/wdk-policies, a
plugin that attaches to a WDK instance. Core keeps one middleware hook
so the plugin can still govern every account the instance hands out.
Removed:
- src/policy/, types/src/policy/ and docs/policy-exclusions-audit.md.
- WDK#registerPolicy, WDK#getPolicyExclusions, the constructor options
maxConditionTimeoutMs and policyExclusions, _applyPolicies, and the
engine calls in dispose.
- From index.js: PolicyViolationError, PolicyConfigurationError,
DEFAULT_POLICY_EXCLUSIONS, DENIAL_CODES and the policy typedefs.
- tests/wdk-policy.test.js, which moves with the engine.
- The policy sections of README.md and AGENTS.md, replaced by a
pointer to the new package.
- zod from dependencies.
Changed, in _runMiddlewares:
- A middleware receives a second argument, { blockchain, index, path }.
index is absent for getAccountByPath; path is the account's full
derivation path.
- A middleware's non-nullish return value replaces the account. The
next middleware, and the caller of getAccount, get the replacement.
- Middlewares run after _registerProtocols, where the engine used to
wrap the account, so the account a middleware returns already has
the protocol getters.
Kept from the engine fixes that landed before the move:
- #117: protocols are still built when a getter is called, through
account._buildProtocol(category, label, subject). The plugin passes
its governed account as the subject, so a protocol registered on the
account is built with it. A protocol registered with
wdk.registerProtocol is still built with the original account.
- #120: path is the one recorded the first time WDK saw the account,
not a fresh read of account.path, so a later change to the account
cannot change the path middlewares receive.
New typedef MiddlewareContext. MiddlewareFunction becomes
(account, context) => Promise<account | void>. The middleware tests
expect the context argument and gain two replacement cases, a
first-seen path case, and two cases for how _buildProtocol treats a
middleware's wrapper.
A middleware that returns a value by accident now replaces the
account.
Version 1.0.0-beta.21.
Refs #122
The inline comments in _registerProtocols still described the policy proxy, which no longer lives in core. Their content now sits in the method's JSDoc, written in terms of a middleware's wrapper. Also rewraps the documentation lines this PR added that ran past 120 columns.
- _getAccountPath and _registerProtocols carry only @Private, in the source and the declarations. - Stub values returned by mocks use the DUMMY_ prefix and dummy- placeholder strings. - The account-protocol test asserts the exact protocol instance instead of its class, and the two new protocol tests have shorter names.
|
One compatibility note while reading this alongside the plugin: since a middleware's return value now replaces the account, middlewares written as concise arrows for beta.20 change behaviour silently, e.g. |
1.0.0-beta.21 was released from main with the engine still in core, so the move ships in the next version.
|
Thanks, that's a real sharp edge. We'd rather not add a runtime check for it, though. |
Take main's bare-node-runtime ^1.5.2. zod stays removed.
path can be null, as in wdk-wallet, and a middleware may return any IWalletAccount.
Description
The transaction policy engine leaves core. It moves to tetherto/wdk-policies and is published as
@tetherto/wdk-policies, an opt-in plugin that attaches to a WDK instance. Core keeps one small middleware hook, so the plugin can still govern every account the instance hands out.Removed
src/policy/,types/src/policy/anddocs/policy-exclusions-audit.md.WDK#registerPolicy,WDK#getPolicyExclusions, the constructor optionsmaxConditionTimeoutMsandpolicyExclusions,_applyPolicies, and the engine calls indispose.index.js:PolicyViolationError,PolicyConfigurationError,DEFAULT_POLICY_EXCLUSIONS,DENIAL_CODES, and the policy typedefs.tests/wdk-policy.test.js, which moves with the engine.README.mdandAGENTS.md, replaced by a pointer to the new package.zodfromdependencies.Changed: the middleware hook, in
_runMiddlewares{ blockchain, index, path }.indexis absent forgetAccountByPath;pathis the account's full derivation path, ornullif the account is not bound to a BIP-44 position.getAccount, get the replacement._registerProtocols, where the engine used to wrap the account, so the account a middleware returns already has the protocol getters.New typedef
MiddlewareContext.MiddlewareFunctionbecomes(account, context) => Promise<account | void>.Kept from the engine fixes that landed before the move
account._buildProtocol(category, label, subject). The plugin passes its governed account as the subject, so a protocol registered withaccount.registerProtocolis built with it. A protocol registered withwdk.registerProtocolis still built with the original account, as fix(policy)!: construct protocols with the governed account #117 decided.pathin the middleware context is the one recorded the first time WDK saw the account, not a fresh read ofaccount.path.Motivation and Context
Every install of core ships the engine and its
zoddependency, whether or not the app registers a single policy. The engine is in beta and opt-in by nature: nothing else in core uses it, and the files insrc/policy/import nothing from the rest of core, onlyzod.A wrapper around the WDK instance would have needed no core change, but the code that created the instance could still get ungoverned accounts from it. The hook keeps today's property that every account the instance hands out goes through the engine.
What a developer changes
new WDK(seed, { maxConditionTimeoutMs, policyExclusions })new WDK(seed)andnew WdkPolicies({ maxConditionTimeoutMs, policyExclusions })wdk.registerPolicy(policies, options)new WdkPolicies().attach(wdk, 'ethereum').register(policies, options)wdk.getPolicyExclusions()policies.getExclusions()wdk.dispose(blockchains)wdk.dispose(blockchains), pluspolicies.dispose(blockchains)@tetherto/wdk@tetherto/wdk-policiesPolicies, rules, conditions, the evaluation context, simulation, denial codes and the error classes do not change.
Changelog note
@tetherto/wdk-policies;registerPolicy,getPolicyExclusions, the two constructor options and the policy exports are removed from core.{ blockchain, index, path }as a second argument.wdk-examples/wdk/middleware.tsand the docs' middleware guide, return nothing.Verification
npm test: 56 pass. The middleware tests expect the context argument and gain six cases: two replacement cases, the first-seen path, a null path, and how_buildProtocoltreats a middleware's wrapper for account-registered and wallet-registered protocols. Each of the last four fails if the property it pins is reverted.npm run lint: clean.@tetherto/wdk-policies. See Receive the transaction policy engine from wdk-core wdk-policies#2.Related Issue
Closes #122
Companion: tetherto/wdk-policies#2
Type of change
Release order
@tetherto/wdk, the next beta, from this PR.@tetherto/wdk-policies1.0.0-beta.1, right behind it. Its lockfile and CI need that core version on npm.