feat(core): the presentation oracle, and where the console can actually reach - #206
Merged
Conversation
…ly reach
`rooms/keys/present` was missing, and its absence was not visible as a gap.
Every host-served room task takes an authority presentation and nothing in
this library could produce one — so `records/{list,get,put}` and
`epoch/mint` were exported, typechecked, and impossible to call. A coverage
count does not catch that: the missing family sits in a different half of
the surface from the ones it made unreachable.
Adds `roomsKeysPresent`, `roomsKeysChain` and `roomsEpochChain`.
The presentation is checked before it is returned. The published schemas
type the two ends of that value differently — `present`'s response is a
bare open object, every host task `$ref`s `AuthorityPresentation` whose
`membership` and `authority` are REQUIRED — so an incomplete answer is
representable, and the only ways past are a blind cast or a check. A blind
cast moves the failure: the host refuses with "no authority chain
presented", an accusation aimed at the member, three hops from the agent
that actually answered incompletely. Checking here names the party that did.
Two of the three new functions are built as typed literals rather than the
spread-and-cast this module uses elsewhere, because that cast hides a
misspelled member — the freshness value is `nonce`, and the schema's
description calls it a challenge, which is what I first wrote.
Also records a finding worth not rediscovering: **the browser console
cannot call the host-served half at all.** Its bridge passes only
`{type, payload}` so the offscreen document mints and signs the envelope,
and the background then addresses it to the wallet's own VTA — so a
`service` naming a host is dropped and the call lands at an agent that does
not serve it. Nothing type-checks as wrong. `rooms/keys/backfill` and
`rooms/owner/register` (trustoverip/dtgwg-trust-tasks-tf#402) are the fix:
the member's agent makes the call, being the party that can.
Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
🛡️ AI Agentic Security Code Review🔎 A manual security review is recommended before merging. Please contact the Security team for specifics and remediation guidance.
|
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The gap that was invisible
rooms/keys/presentwas missing from the rooms client, and its absence did not look like a gap. Every host-served room task takes an authority presentation; nothing in this library could produce one. SoroomsRecordsList,roomsRecordsGet,roomsRecordsPutandroomsEpochMintwere exported, typechecked, documented — and impossible to call.A coverage count does not catch that. The missing family sits in a different half of the surface from the ones it made unreachable, so the number moved by one while four functions were dead.
Adds
roomsKeysPresent,roomsKeysChain, androomsEpochChain.The presentation is checked where it is produced
The published schemas type the two ends of the same value differently:
rooms/keys/present's response declarespresentationas a bare open object, while every host task$refsAuthorityPresentation, whosemembershipandauthorityare REQUIRED. An incomplete answer is therefore representable, and the only ways past it are a blind cast or a check.A blind cast moves the failure somewhere useless. The host refuses with "no authority chain presented; a room operation is authorized by the chain" — an accusation aimed at the member, three hops away from the agent that actually answered incompletely. Checking here names the party that did.
(Worth a look upstream: the two ends of one value could share the
$ref.)Two functions build typed literals instead of spread-and-cast
The
as unknown as Payloadpattern this module uses elsewhere hides a misspelled member. It nearly did: the freshness value onrooms/keys/presentisnonce, and the schema's description calls it a challenge, which is what I first wrote.packages/core/tests/rooms.present-and-chain.mjspins both the name and that an absent one is absent rather than null.The finding worth not rediscovering
The browser console cannot call the host-served half of this family at all.
manager/carrier.tspasses exactly{type, payload}— deliberately, so the offscreen document mints and signs the envelope rather than counter-signing one composed in a page.handleManagerTaskthen suppliesvtaDid: active.conn.vtaDidas the recipient.servicenaming a host is dropped, and the call lands at an agent that does not serve it.Nothing type-checks as wrong, and the test harness answers by task URI regardless of recipient — so a fake agent happily replies to a call the console could never make.
keys/{list,open,seal,present,chain}rooms/createowner/{invite,issue-membership,issue-authority}records/{list,get,put}vta/webvh/dids/createepoch/{mint,chain}This means the create-a-room flow merged in #204 always fails at its second step — the DID is minted (the agent's own work, which succeeds) and the registration cannot be sent. The
Mintedrecovery panel built for the rare case fires every time. It fails loudly rather than corrupting anything, but it reads as a broken agent.The module header now records all of this, including which surfaces the host-served functions are for: a server-side consumer or a CLI with its own channel.
The fix, already specified
trustoverip/dtgwg-trust-tasks-tf#402 adds
rooms/keys/backfillandrooms/owner/register— the member's own agent makes the host call, being the party that can. It already holds the credentials, mints the presentation, and holds the group state. Once VTI implements them, the console finishes the create flow and gains the history repair its rooms pane already names.The backfill pane is deliberately not in this PR: it would be a screen that always fails at its middle hop, and it will be one call rather than three once the task lands.
Verification
npm run lint,npm run build,npm testall green — 1034 tests, 0 failures, of which 7 are new and cover the presentation shape check, thenoncenaming, and thatstored: 0is passed through rather than swallowed (it is what a retry looks like). Coverage census updated 194 → 196 with the reasoning recorded intask-surface.mjs.