v0.72.0
Removed
- Breaking:
getUnlockKeyringWithCapability,
putUnlockKeyringWithCapability, anddeleteUnlockSpaceWithCapability
(/keyring).getUnlockKeyring,putUnlockKeyring, anddeleteUnlockSpace
take an optionalcapabilityinstead, so every unlock Space operation has one
request shape whether it is a root invocation or rides the delegated
management zcap. - Breaking:
isSoleEnrolledClient(/clientAnnex), replaced by
isLastEnrolledClient({ doc, signingVmId })(/webvh).
Added
-
clientAdditionFields(/webvh): the add-side twin ofclientRemovalFields.
One enrolled client's marked verification-method pair and its relation
membership (all four signing relations pluskeyAgreement) as one bundle,
which the genesis assembly, the enrollment add entry, the self-enrollment add
entry, and the recovery continuation now take instead of restating the five
relations each. -
enrolledClientVmIdsandisLastEnrolledClient(/webvh): the one read of
which methods are enrolled clients, and the last-client rule over it. The
plain forget, the last-client transition, the enrolled-client listing, and the
disconnect policy's count all decide on it. -
The
/testingsubpath, test fixtures only:recordedGrant(a delegated zcap
as the delegation suite records it, the chain in the proof with a parent
delegation embedded as its last link) andaccountSignerCheckover
SIGNER_FIXTURE(one enrolled client and one ladder VM under
capabilityDelegation, a pointed and an old annex generation). The grant
revocation tests here and in freewallet import them in place of two
hand-written copies. Consumers keep it out of production code by lint
restriction, as with@interop/vh-resource-log/testing. -
The
/menderssubpath: the mender registry's shared half. It carries the
InvariantDeclarationandRegistrationtypes, the closed vocabularies
(AUTHORITIES,TRIGGERS,CHAIN_TRIGGERS,ACCOUNT_SHAPES,EVIDENCE,
MEND_OUTCOMES,GAP_KINDS) and theINVARIANT_IDScensus, the
menderRegistryreaders (all,byId,sites,admits,dueAt) with
heldAuthoritiesand itsResolvedAuthoritykind type, and the derived-set
helperstransientReachableInvariants,deriveGaps,undeclaredGaps, and
undeclaredInvariants.menderRegistrychecks its table and sites once at
construction and throws aTypeErroron a duplicated declaration id, a site
reporting an undeclared invariant, or aguardedByon a site that is not a
login-routingone (RegistrationSiteis a union ontrigger, so the type
forbids the third). A detector is not a mender: an invariant no site reports
derives anonegap whether or not it declaresholdsWhen, and
transientReachableInvariantscounts an unreported declaration only as a
detector checked at a trigger a transient visit fires, under the ladder held
set on the chain. A wallet declares its own table and its own registrations;
nothing here executes a ceremony. -
The mender runner on
/menders:runMenderBlockruns one chain trigger's
registrations in list order, filtered by the held authorities and by each
reported declaration'swhen(route)predicate. An optional seed registration
runs first and its failure aborts the block; past it, a registration that
throws warns once per reported invariant with that declaration's ownwarn
string through the wallet-suppliedLogger, reportsfailedcarrying
err.namealone, and the block continues. A registration whose entries do not
match the invariants it reports warns and is normalized tofailedentries
carryingMEND_REPORT_SHAPE_ERROR.onOutcomeis the single place an entry
is reported. An optionalregistrationslist overrides which registrations
the block runs, under the same authority and route tests, for a wallet that
runs one trigger's list in parts (a settle point partway through); a seed or
override registration listed under another trigger is refused with a
TypeError. A converge-free site the registry indexes beside its
registrations is never executed, whichever list the block runs from. -
mendReportAccumulator(/menders): the report collector a wallet creates
ahead of session assembly, so a routing site's entries and the chain's entries
assemble into oneMendReport.reportdoubles asrunMenderBlock's
onOutcome, andsettledresolves with the assembled report at the first
settle(). -
errorNameOf(/menders): the name a mend report carries for a thrown value
of any shape, so an app-side report site does not read.nameoff a
non-Errorthrow. -
LoginRoute(/menders): the route typeInvariantDeclaration.whenreads,
{ popup: boolean }today. -
addHistoryProfileCreated,addHistoryCollectionShared, and
addHistoryCollectionUnshared(/space), completing thewallet-activity
builder set. Theirtype/summarybytes match what the wallets were
writing inline, so existing records are unaffected. -
isDelegationExpiredand theRevokeGenerationDelegationOutcometype
(/clientAnnex): the expiry check and the outcome union
revokeTreatingAlreadyRevokedAsSuccessnow returns. -
revokeRecordedGrant,classifyGrantRevocationRefusal,
embeddedParentCapability,isClientAnnexDid, and theAccountSignerCheck,
GrantRevocationOutcome, andGrantRevocationRefusaltypes (/clientAnnex):
revoking one recorded app or agent grant under the same policy
revokeTreatingAlreadyRevokedAsSuccessapplies to a generation delegation.
The one local skip is a grant expired beyondREVOCATION_CLOCK_SKEW_MS;
everything else is POSTed;AlreadyRevokedErroris success; a plain
ValidationErroris read against the verified account document asexpired,
orphaned(a root-delegated grant whose signer left the document),
signer-gone(an embedded parent delegation whose proof key left the
document), orgeneration-swapped(a parent generation delegation naming a
generation the document no longer points at), and rethrown when the client
cannot say why. It composesdelegationExpired,delegationAtExpiry, and
delegationSignerGone(/webvh) withderiveGrantSignerState(/clients).
Changed
-
The byoe service-entry convention is read and written through one predicate in
/clientAnnex: the delegated-clients pointer and the generation delegation
each match on the type IRI and the endpoint shape (a string, a map), for the
readers and the in-place re-point alike. A malformed entry of the right type
is now skipped by both, where the writer used to re-point it in place while
the reader could not see it. -
decisions/0002,0004,0006,0008,0010, and0011saydurable
only of server-backed state: their client, session, login, and recovery-spend
uses take the enrolled and remembered words, prose only. -
Every topic doc under
docs/architecture/now states its ceremony's pivot
write, which of the ceremony's other writes sit before and after it, and the
invariants a torn run can leave violated, numbered as inINVARIANT_IDS.
did-webvh-account-log.mdgains an update-key rotation section for the one
ceremony that had no account of its own. -
ARCHITECTURE.md: a mender registry subsection beside "Ceremonies and cascades"
names the registry's unit, the authority values, and the trigger values, and
holds the four menders (the Space-controller promotion, the
credential-anchored mend, the transient readiness ensure, and the login-time
roster sweep) with their invariant ids. The ceremony table keeps only
ceremonies, each row now carrying itsCeremonyId, and gains the
recovery-code issuance and revocation rows. -
menderRegistry'sdueAttakes an optionalroute. With one, a registration
is due only when every reported declaration either declares nowhen
predicate or admits that route; without one, the route test does not apply and
the reader behaves as before. -
Breaking:
deleteUnlockSpacereturns
{ outcome: 'deleted' | 'not-found' }in both forms (a 404 is reported, not
decided), where the root-invoked form previously resolvedvoid. -
fetchKeyringRecord'skdfparameter is required. It no longer defaults to
KEYRING_KDF, so a caller names its unlock method's parameter set and a
method that omits it fails to compile instead of deriving the
passphrase-salted unlock identity and reading the wrong unlock Space. -
CapabilityAgentnow comes from@interop/capability-agent; the
@interop/webkms-clientdependency is dropped. The unlock identity derivation
is unchanged. -
The account-document relation reader memoizes its
verificationMethodindex
per document, so the resource-log controller no longer rebuilds it for each
relation it resolves per log entry. -
publishUnlockKey's fresh-bind check (a recorded update key that is not rung
0 of the ladder seed handed in refuses withLadderAttributionError, nothing
written) is documented as the checked half of theladderCommitmentcontract
onunlockKeyVerificationMethod. The seedless bind and the remembered
recovery continuation's replacement member are named as the two emitters that
still take the value on trust. -
mendCredentialAnchoredAccounthands the account log its roster-mint
preconditions verified to the registry arm instead of reading and verifying it
a second time. -
Breaking:
revokeTreatingAlreadyRevokedAsSuccess(/clientAnnex) no
longer reads every was-clientValidationErroras success, and now takes the
locally verified account document (accountDoc). It skips the POST only for a
delegation whose ownexpiresis past by more thanREVOCATION_CLOCK_SKEW_MS
(ten minutes; an absent or unparseableexpiresis not treated as expired),
and otherwise POSTs whatever the caller's document says about the signer. It
reads was-client 0.58.0'sAlreadyRevokedErroras success, classifies a plain
ValidationErroras'expired'whennowis inside the skew band around the
delegation'sexpiresand as'signer-gone'when the proof key has checkably
left the document undercapabilityDelegation(an absent proof key id, or one
with no fragment, is never read as gone), and rethrows every other failure. It
returns'revoked' | 'already-revoked' | 'expired' | 'signer-gone'instead of
void. -
delegationExpired,delegationAtExpiry,delegationSignerGone, and
REVOCATION_CLOCK_SKEW_MS(/webvh): the revocation-side readings of the
expiry and signer axes, besidezcapExpiringandrecordedZcapStale, with
the opposite fail-safe default (an uncheckable value reads as still standing). -
ClientAnnexGenerationSwap['revoke']gains'expired','signer-gone', and
'refused'members alongside'revoked','no-delegation', and
'log-absent'; a'refused'swap carries the error inrevokeError. A
refused revocation no longer aborts the swap: the fresh generation already
stands, so the swap still re-points and leaves the old generation to the
collect fan-out, which re-attempts the revocation and reports the failure
under the old generation's id while it keeps failing. -
forgetLastEnrolledClient's generation stage revokes the historical doomed
delegations before minting the replacement and the embedded one after it, so a
revocation the server persistently refuses mints at most one fresh delegation
across every re-run (the first run's, minted before the embedded delegation's
refusal is seen) instead of one per re-run. The doomed set is no longer
pre-filtered on expiry; an expired delegation is skipped by the revoke helper
and left out ofrevoked. -
ClientAnnexInventoryRetirement(/unlock) gains an optionalrevokemember
(ClientAnnexSwapRevokeOutcome, the unionClientAnnexGenerationSwapnames
itsrevokewith) so aswappedreport can say what became of the old
generation's delegation; the app-side closure fills it in. -
forgetLastEnrolledClient's ladder-delegation retirement runs its doomed
delegations' revocations underPromise.allSettledinstead ofPromise.all,
reports only the revoked and already-revoked ids inrevoked, and rethrows
the first failed revocation's error verbatim (its name intact, not wrapped)
once every revocation has settled -- halting the ceremony before the removal
entry rather than declaring the resurrection window closed while a delegation
still stands. -
@interop/was-clientdependency bumped to^0.58.0, for
AlreadyRevokedError.