Repository navigation
refactor(core): inbound dispatch and join protocol in core, one message-type registry, typed remote errors - #605
Merged
Conversation
…:inbound process_inbound_message, InboundEffects, VerifyJob/PreVerified/Arrival/ Deferred and the helpers they need had no TUI dependency, so they move to openvtc-core unchanged. The three per-panel InboundReply structs become aliases of one core ThreadedReply<R>. The headless loop (join_cmd::apply_inbound) becomes openvtc_core::inbound::apply_inline, which repos_cmd and join_cmd call instead of reaching into state_handler. The dispatcher's tests move with it; the one that applies a reply to the TUI's Repos view stays in the CLI (inbound_glue_tests). Test-only VerifyJob variants are behind a new test-support feature the CLI enables from dev-dependencies only. Refs #530 Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
…into core RDidPlan, plan_relationship_did, RDidPlan::create_io and the VTA key minting behind it move to openvtc_core::relationships::keys, with relationship_did_signer. They now return OpenVTCError instead of anyhow::Error. The bounded VTA retry the setup flow and the R-DID minting share moves to openvtc_core::vta_task::retry (with its tests); the CLI keeps vta_retry as a re-export for its setup code. Refs #530 Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
…core::join The parts of the join sequence that touch only Config and the network move to openvtc_core::join::sequence: reading a community's manifest over HTTP (learn_over_http / NotLearned / learn_signing), choosing the membership's context, choosing the submit transport (choose_submit_route, which returns the note the TUI used to show inline), signing and sending the submit (submit, with a SubmitError the caller words), the pending record, and rolling back a minted persona. The join status poll moves whole to openvtc_core::join::status_poll. The TUI's run_join_sequence and the headless community join now call the same submit and transport choice instead of two copies. What the person is shown stays with each caller. Minting a persona, invitation resolution and the answers/hidden-proof steps stay in join_flow for the join-flow rework (#529). Refs #530 Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
… registry openvtc_core::inbound::registry::ROUTES lists every inbound type this client handles and the Family it belongs to. The transport's accept gate (didcomm::routes_inbound_type / classify_inbound) admits a type exactly when classify() gives it a family, and process_inbound matches on that family exhaustively, one handler function per family. The hand-written OPENVTC_CATCH_ALL_PATTERN regex and the order-dependent if-chain are gone, and verification_job triages on the same families. Routes are disjoint; the families that share traffic (a trust-task-error offered to every view, a credential delivery and a problem report vetting reads first) do so inside their handler, in the order the if-chain used. The gate no longer admits whole namespaces no handler claims (spec/vtc/*, the legacy openvtc/vtc/* authority, any linuxfoundation.org/openvtc/*). Those messages were dropped by the dispatcher as unknown before; they are now dropped at the gate, still at warn for Trust Task and OpenVTC protocol namespaces. The census test moves to core and checks the registry. Closes #531 Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
…, ErrorClass)
OpenVTCError::Remote { service, kind, detail } carries what kind of remote
failure happened: Unreachable, Timeout, AuthRejected, Contract, NotFound,
Refused { code } or Failed, each a different remedy (R6.4). RemoteKind
classifies VtaError, ATMError, Trust Task refusal codes and HTTP statuses
in one place; OpenVTCError::class() and errors::class_of() (through an
anyhow chain) give the UI an ErrorClass with is_remote() and remedy().
DiscoverError::kind() and MessagingError::class() do the same for peer
HTTP fetches and the messaging layer.
VTA client calls in core now build Remote via OpenVTCError::vta(context,
&e) (persona pool/profile/binding/world/contacts/lifecycle/disclosure/
join answers, devices, rebuild, community contexts, relationship keys,
git signing, the connect path); responses missing a field they must carry
are Contract. The persona pool's "is it still there" check matches the
NotFound kind instead of the substring "notFound". Startup's VTA-failure
branch and the diagnosis read the class.
Refs #536
Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
inbound_dispatch_e2e sends from one party over the in-process mediator and puts what the other's transport delivers through the inbound gate and process_inbound_message, running any deferred proof check off the loop as the runtime loop does: a trust-pong closing our ping and a trust-ping recorded, a relationship request proven against the sender's did:peer and queued, a VRC proven and queued, a community's signed refusal rejecting a pending join, and an unclaimed type refused by the gate. The harness gains start_profile_inbound, which delivers every message with its sender. Part of #537 Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
… typed remote errors Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
…y 404 A bare REST 404/410 (an older VTA, a misrouted request) is reported as the failure it is rather than as "no single stored value". Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
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.
Moves the protocol logic that had no TUI dependency out of
openvtc/src/state_handler/intoopenvtc-core, derives the inbound accept gate and the dispatcher from one registry, and gives remote failures a typed class. Seven commits, each building and passingclippy -D warningsandcargo test --workspaceon its own: three moves, then the registry, then typed errors, then tests, then the changelog.Closes #530
Closes #531
Closes #536
Part of #537
What moved where (#530)
openvtc-core)state_handler/message_dispatch.rs(whole file:process_inbound_message,InboundEffects,VerifyJob,PreVerified,Arrival,Deferred,issue_member_vmc_for, triage helpers, 36 tests)inbound/mod.rs,inbound/tests.rsInboundReplystructs are now aliases of oneinbound::ThreadedReply<R>. The one test that applies a reply to the TUI's Repos view stays in the CLI (state_handler/inbound_glue_tests.rs).join_cmd::apply_inboundinbound::apply_inlinerepos_cmdandjoin_cmdcall core now, notstate_handler.relationship_actions::{RDidPlan, CreatedRDid, plan_relationship_did, create_io, create_relationship_keys, relationship_did_signer}relationships::keysOpenVTCErrorinstead ofanyhow::Error.setup_sequence::vta::{vta_retry, vta_retryable}(and their tests)vta_task::{retry, retryable, MAX_ATTEMPTS}vta_retryas a re-export.join_flow::{learn_over_http, NotLearned, learn_signing, note_signing, suggested_context, context_taken, build_pending_record, forget_minted_persona, RESOLVE_TIMEOUT}join::sequencerun_join_sequenceandjoin_cmd)join::sequence::{choose_submit_route, SubmitRoute, TransportNote, submit, SubmitError}state_handler/join_status_poll.rs(whole file)join::status_pollWhere a function used to write to TUI
State, core now returns a value (SubmitRoute.note,SubmitError,InboundEffects) and the CLI applies it. Core has noStateor ratatui types.Not moved yet (the join-flow rework, #529, picks it up): the rest of
run_join_sequence. That covers minting a fresh persona intostate.setup, resolving and verifying the invitation (vault lookup, linkage proof), answering the community's questions from a face, the hidden-vetting proof precheck, the listener start/await, and the page/progress plumbing. These steps are interleaved withStatewrites andstate_txsends at almost every step. Moving them cleanly needs the progress-callback seam #529 introduces.setup_sequence/(persona minting, VTA provisioning;mint_persona_intotwice) is untouched.The registry (#531)
openvtc_core::inbound::registry::ROUTESis a&[Route]of(TypeMatcher, Family).TypeMatcherisExact,PrefixorPredicate(fn(&str) -> bool). A predicate is used where the owning module already defines its types:witness::is_reply_type,JoinProtocol::is_submit_response, and vetting'smay_claimminus the three types it shares.Familyis declared through a small macro soFamily::ALLis complete by construction.Gate.
didcomm::routes_inbound_typeandclassify_inboundadmit a type exactly whenregistry::classifyreturns a family. The hand-writtenOPENVTC_CATCH_ALL_PATTERNregex and theregexdependency are gone.Dispatcher.
process_inbounddoes the same pre-routing steps as before (age, sender binding, replay, size, envelope open, deferral). It then makes one exhaustivematch family { … }with one handler function per family. The 25-branch if-chain is gone, and a new family without a handler does not compile.verification_jobtriages on the same families.Shared traffic. Routes are disjoint, so their order means nothing; a test checks this. Three families share traffic inside their handler, in the order the if-chain used:
trust-task-erroris offered to capability, git-ns, rooms, elections, witness, vetting, a renewal of ours, then the join;Each handler body is the old branch text. Only its variable bindings changed.
Census.
openvtc/tests/inbound_gate_census.rsmoved toopenvtc-core/tests/inbound_gate_census.rsand now checks the registry. It checks that every routed type reaches its expected family, every family has a route, no type is claimed twice, the gate equals the registry, everytrust-task-errorversion is admitted, and unrouted types are refused.Visible change: the gate no longer admits whole namespaces that no handler claims: any
spec/vtc/*, the legacytrusttasks.org/openvtc/vtc/*authority, and anylinuxfoundation.org/openvtc/*. Before this PR, such messages reached the dispatcher and were dropped as "unknown message type". Now the gate drops them, and they are still logged atwarn: the gate's warn now also covers the OpenVTC protocol namespaces. Every type the new gate admits was admitted by the old regex, so the gate only got narrower.didcomm_transport_e2eused a made-uplinuxfoundation.org/openvtc/test/1.0/pingtype that only the old broad gate admitted; it now uses a real routed type.Typed remote errors (#536)
OpenVTCError::Remote { service: RemoteService, kind: RemoteKind, detail }(additive;OpenVTCErroris#[non_exhaustive]).RemoteService:Vta,Mediator,Peer,Http.RemoteKind:Unreachable,Timeout,AuthRejected,Contract,NotFound,Refused { code },Failed.RemoteKind::from_vta(&VtaError)(usesvta_receive_leg::is_reply_timeoutfor reply timeouts),from_atm(&ATMError)(uses its typed HTTP status),from_refusal_code(Trust Task / problem-report codes, scoped or not), andfrom_http_status.OpenVTCError::class() -> ErrorClass(withis_remote()andremedy()),remote_kind(), anderrors::class_of(&dyn Error), which walks ananyhowchain.ErrorClassmaps the older variants by their documented meaning:VtaandResolver→Unreachable,Auth→AuthRejected,ATM→ classified.DiscoverError::kind()(peer HTTP manifest fetch) andMessagingError::class()(listener/send) give the same classes for those layers.Where it is used:
OpenVTCError::vta(context, &e)/OpenVTCError::remote(..)). These cover persona pool, profile, binding, world, contacts, lifecycle, disclosure, join answers, claim types and correlation; devices; rebuild; community contexts (vta_failure); relationship keys; git signing; and the VTA connect path. Responses missing a field they must carry are classedContract.OpenVTCError::Vta(String)constructions went from 75 to 18 occurrences. Of those 18, 6 are real constructors left on local or shape conditions; the rest are the variant itself, matches and tests.Config(String)sites in core, 5 were remote failures (git signing's VTA calls) and are converted. The 154 left are local config, storage, encoding or crypto errors, plus 3 local preconditions that moved in with dispatch. Splitting those further (Clock,Encoding,Io, …) is left for later.format!("{e}").contains("notFound"). It now checksRemoteKind::NotFound, which also counts a plain REST 404/410 as gone.main.rs's VTA-failure branch picks its hint from the class, anddiagnostics::diagnosehas aRemotearm with the class's remedy.Wording that changed: VTA failures render as
VTA <kind>: <context>: <sdk error>(e.g.VTA timed out: …,VTA rejected our credentials: …) instead ofVTA Error: ….vta_failure's auth and forbidden cases are nowRemoterather thanAuth; same text, typed.Not converted (string matching that is not about failure class):
git_workspace::clone_failure_wordsparsesgit's stderr, which is the only signal there is.holder_grant::needs_holder_grantandvetting_actions::faces::preview_refusalmatch specific refusal phrases the VTA sends with no code. That needs codes upstream (R3.7).ui/pages/main/components/identity_panel.rs(failed.contains("connection refused")) is in the directory another PR is editing, so it is deliberately untouched. It and the connection header move toclass()in the follow-up the issue names.setup_sequence/vta.rsstill wrapsVtaErrorinanyhow!strings withexplain().Tests (#537, part)
openvtc-core/tests/inbound_dispatch_e2e.rsdrivesprocess_inbound_messageend to end. Alice sends over the in-process test mediator; Bob's transport unpacks the message; it goes throughroutes_inbound_typeand the dispatcher; and any deferred proof check is run off the loop and handed back, as the runtime loop does. The tests:did:peer, and it is queued;trust-task-errorin the binding envelope rejects our pending join and tears the session down;They are
#[ignore]d like the rest of the mediator suite (CI's coverage job runs them with--include-ignored).The harness gained
start_profile_inbound, which delivers every message with its sender. Reviewer note: the delivery layer reports the forwarding mediator assenderand does not expose the authcrypt unpack metadata. The harness therefore uses the innerfromof an encrypted message as the authenticated sender. That is sound for these tests, because the harness authcrypt-packs everything it sends, but it is not the productionencrypted_from_kidcheck.Also new: unit tests for the error classifiers and
class_ofthroughanyhow; census tests on the registry; and the CLI glue test for the Repos view.What is left
ErrorClass(andidentity_panel.rs) → the follow-up PR for refactor(errors): give remote failures a typed class instead ofConfig(String)/Vta(String)and string matching #536's UI half.Config(String)split intoClock/Encoding/Io/Transportand the CLIResult<_, String>remote paths → later refactor(errors): give remote failures a typed class instead ofConfig(String)/Vta(String)and string matching #536 follow-up.#[ignore]d tests #537: the join-saga e2e with failure injection, theRuntimeharness test, coverage floors, and the#[ignore]policy.Pre-merge checklist (dev guide §9)
reqwest::Client::new()/ bare fetch; all clients have finite timeouts (R1.2). No new clients; the moved code keeps its existing bounded timeouts (RESOLVE_TIMEOUT,JOB_TIMEOUT,VTA_TIMEOUT).submitreturnsOk, and a minted persona is still rolled back on a failed send.vta_task::retryis the same 3-attempt exponential back-off, moved.warnfor Trust Task and OpenVTC namespaces.fromof an authcrypt message (see Tests). Removing the publicOPENVTC_CATCH_ALL_PATTERNis a breakingopenvtc-coreAPI change, so this PR should not be backported to a release branch.Verification
cargo fmt --all --checkcargo clippy --workspace --all-targets --locked -- -D warnings, and with--no-default-featurescargo test --workspace --locked, and with--no-default-featurescargo test --workspace --locked -- --include-ignoredcargo clippy -p openvtc --all-targets --features dev-overrides -- -D warningscargo test -p openvtc --features dev-overridesRUSTDOCFLAGS='-D warnings' cargo doc --workspace --no-depscargo machete