Skip to content

v0.72.0

Choose a tag to compare

@dmitrizagidulin dmitrizagidulin released this 10 Sep 19:25
· 4 commits to main since this release

Removed

  • Breaking: getUnlockKeyringWithCapability,
    putUnlockKeyringWithCapability, and deleteUnlockSpaceWithCapability
    (/keyring). getUnlockKeyring, putUnlockKeyring, and deleteUnlockSpace
    take an optional capability instead, 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 of clientRemovalFields.
    One enrolled client's marked verification-method pair and its relation
    membership (all four signing relations plus keyAgreement) 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.

  • enrolledClientVmIds and isLastEnrolledClient (/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 /testing subpath, 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) and accountSignerCheck over
    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 /menders subpath: the mender registry's shared half. It carries the
    InvariantDeclaration and Registration types, the closed vocabularies
    (AUTHORITIES, TRIGGERS, CHAIN_TRIGGERS, ACCOUNT_SHAPES, EVIDENCE,
    MEND_OUTCOMES, GAP_KINDS) and the INVARIANT_IDS census, the
    menderRegistry readers (all, byId, sites, admits, dueAt) with
    heldAuthorities and its ResolvedAuthority kind type, and the derived-set
    helpers transientReachableInvariants, deriveGaps, undeclaredGaps, and
    undeclaredInvariants. menderRegistry checks its table and sites once at
    construction and throws a TypeError on a duplicated declaration id, a site
    reporting an undeclared invariant, or a guardedBy on a site that is not a
    login-routing one (RegistrationSite is a union on trigger, so the type
    forbids the third). A detector is not a mender: an invariant no site reports
    derives a none gap whether or not it declares holdsWhen, and
    transientReachableInvariants counts 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: runMenderBlock runs one chain trigger's
    registrations in list order, filtered by the held authorities and by each
    reported declaration's when(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 own warn
    string through the wallet-supplied Logger, reports failed carrying
    err.name alone, and the block continues. A registration whose entries do not
    match the invariants it reports warns and is normalized to failed entries
    carrying MEND_REPORT_SHAPE_ERROR. onOutcome is the single place an entry
    is reported. An optional registrations list 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 one MendReport. report doubles as runMenderBlock's
    onOutcome, and settled resolves 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 .name off a
    non-Error throw.

  • LoginRoute (/menders): the route type InvariantDeclaration.when reads,
    { popup: boolean } today.

  • addHistoryProfileCreated, addHistoryCollectionShared, and
    addHistoryCollectionUnshared (/space), completing the wallet-activity
    builder set. Their type / summary bytes match what the wallets were
    writing inline, so existing records are unaffected.

  • isDelegationExpired and the RevokeGenerationDelegationOutcome type
    (/clientAnnex): the expiry check and the outcome union
    revokeTreatingAlreadyRevokedAsSuccess now returns.

  • revokeRecordedGrant, classifyGrantRevocationRefusal,
    embeddedParentCapability, isClientAnnexDid, and the AccountSignerCheck,
    GrantRevocationOutcome, and GrantRevocationRefusal types (/clientAnnex):
    revoking one recorded app or agent grant under the same policy
    revokeTreatingAlreadyRevokedAsSuccess applies to a generation delegation.
    The one local skip is a grant expired beyond REVOCATION_CLOCK_SKEW_MS;
    everything else is POSTed; AlreadyRevokedError is success; a plain
    ValidationError is read against the verified account document as expired,
    orphaned (a root-delegated grant whose signer left the document),
    signer-gone (an embedded parent delegation whose proof key left the
    document), or generation-swapped (a parent generation delegation naming a
    generation the document no longer points at), and rethrown when the client
    cannot say why. It composes delegationExpired, delegationAtExpiry, and
    delegationSignerGone (/webvh) with deriveGrantSignerState (/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, and 0011 say durable
    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 in INVARIANT_IDS.
    did-webvh-account-log.md gains 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 its CeremonyId, and gains the
    recovery-code issuance and revocation rows.

  • menderRegistry's dueAt takes an optional route. With one, a registration
    is due only when every reported declaration either declares no when
    predicate or admits that route; without one, the route test does not apply and
    the reader behaves as before.

  • Breaking: deleteUnlockSpace returns
    { outcome: 'deleted' | 'not-found' } in both forms (a 404 is reported, not
    decided), where the root-invoked form previously resolved void.

  • fetchKeyringRecord's kdf parameter 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.

  • CapabilityAgent now comes from @interop/capability-agent; the
    @interop/webkms-client dependency is dropped. The unlock identity derivation
    is unchanged.

  • The account-document relation reader memoizes its verificationMethod index
    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 with LadderAttributionError, nothing
    written) is documented as the checked half of the ladderCommitment contract
    on unlockKeyVerificationMethod. The seedless bind and the remembered
    recovery continuation's replacement member are named as the two emitters that
    still take the value on trust.

  • mendCredentialAnchoredAccount hands 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-client ValidationError as success, and now takes the
    locally verified account document (accountDoc). It skips the POST only for a
    delegation whose own expires is past by more than REVOCATION_CLOCK_SKEW_MS
    (ten minutes; an absent or unparseable expires is not treated as expired),
    and otherwise POSTs whatever the caller's document says about the signer. It
    reads was-client 0.58.0's AlreadyRevokedError as success, classifies a plain
    ValidationError as 'expired' when now is inside the skew band around the
    delegation's expires and as 'signer-gone' when the proof key has checkably
    left the document under capabilityDelegation (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, beside zcapExpiring and recordedZcapStale, 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 in revokeError. 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 of revoked.

  • ClientAnnexInventoryRetirement (/unlock) gains an optional revoke member
    (ClientAnnexSwapRevokeOutcome, the union ClientAnnexGenerationSwap names
    its revoke with) so a swapped report 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 under Promise.allSettled instead of Promise.all,
    reports only the revoked and already-revoked ids in revoked, 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-client dependency bumped to ^0.58.0, for
    AlreadyRevokedError.