Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
549 changes: 333 additions & 216 deletions Cargo.lock

Large diffs are not rendered by default.

52 changes: 45 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,22 @@ openvtc-core = { version = "0.3", path = "openvtc-core", default-features = fals
dtg-credentials = "0.2"

aes-gcm = "0.11"
argon2 = "0.5"
# The one direct requirement in this workspace that was behind its latest
# release. Safe to move even though it derives key material: Argon2id is a
# specified KDF and `derive_argon2_key` calls `hash_password_into`, its plain
# implementation — same algorithm, version and params in, same 32 bytes out. So
# the unlock code and the `ProtectedConfig` seed are byte-identical across the
# bump and every existing config still opens. What 0.6 actually breaks is the
# `password-hash` 0.6 PHC-string surface, which we do not touch.
#
# It does not resolve the 0.5/0.6 duplicate, and is not trying to: 0.5.3 is
# `affinidi-messaging-mediator-common`'s requirement, reaching us through
# `affinidi-messaging-sdk`, and no line we control moves it. The bump puts us on
# the same copy as `vta-service` rather than on the older one.
argon2 = "0.6"
# 0.8.5 is `vta-sdk` 0.27's and `vta-service` 0.19's own requirement — the floor
# is set by the graph, and this line only records it.
affinidi-tdk = "0.8.5"
affinidi-tdk = "0.10"
affinidi-data-integrity = "0.7"
# The delivery layer (D1). Replaced `affinidi-messaging-didcomm-service`, the
# type-routed framework both VTI services had already cut over from (#189).
Expand Down Expand Up @@ -95,7 +107,7 @@ affinidi-messaging-core = "0.1.6"
# Earlier floors are below this one by construction: 0.19.4 (#694) was the
# `live_stream_next*` read guard that blocked `stop_websocket` for the remainder
# of a 10s poll window, so quitting the TUI mid-window paid it.
affinidi-messaging-sdk = "0.19.10"
affinidi-messaging-sdk = "0.21"
# `StreamExt::next` on the `BoxStream` returned by `MessagingService::subscribe`.
futures-util = "0.3"
# Agent names (DID shortcuts). `agent-names` carries the parse /
Expand All @@ -108,7 +120,7 @@ futures-util = "0.3"
# this line states it. Stating it keeps the manifest honest about what the graph
# actually resolves rather than implying 0.1.2 is still viable.
agent-names = "0.1.3"
affinidi-did-resolver-cache-sdk = { version = "0.8.19", features = [
affinidi-did-resolver-cache-sdk = { version = "0.8.34", features = [
"agent-names",
] }
anyhow = "1.0"
Expand Down Expand Up @@ -200,8 +212,8 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
# 0.9 → 0.11 move needed a third crate to follow as well: the messaging stack
# carries `trust-tasks-rs` types in its own API, so `affinidi-messaging-sdk` has
# a floor of 0.19.9 above for the same reason (affinidi-tdk-rs #717).
trust-tasks-rs = "0.11"
trust-tasks-capability-client = "0.9"
trust-tasks-rs = "0.17"
trust-tasks-capability-client = "0.17"
tui-input = "0.15"
url = "2.5"
uuid = { version = "1.23", features = ["v4", "fast-rng", "serde"] }
Expand Down Expand Up @@ -251,7 +263,7 @@ uuid = { version = "1.23", features = ["v4", "fast-rng", "serde"] }
# 0.25.1 beside 0.27.0. That is the third consecutive cycle it has done so — see
# the floor note on `did-git-sign` in `openvtc/Cargo.toml`, which is where the
# obligation is written down.
vta-sdk = { version = "0.27", features = [
vta-sdk = { version = "0.31", features = [
"session",
"client",
# The SAME per-platform credential-store registration pnm-cli uses
Expand Down Expand Up @@ -289,3 +301,29 @@ openpgp-card-rpgp = "0.8"
lto = true
codegen-units = 1
strip = "symbols"

# `did-git-sign` 0.4.6 — the latest published release — requires `vta-sdk ^0.27`,
# and that one edge re-splits `vta-sdk`, `affinidi-tdk`, `affinidi-messaging-sdk`
# and `trust-tasks-rs` into two copies each against this workspace's 0.31. It does
# not merely fail to unify types: `vta-keys` 0.2.9 does not compile against
# `vti-common` 0.15, so the whole workspace fails to build.
#
# OpenVTC/verifiable-git-infrastructure#33 is the release that ends it — the VGI
# workspace onto vta-sdk 0.31 and TDK 0.10, no source change, green on its own
# pipeline. Its head is a better dependency than the stale published crate, so
# this workspace takes it directly rather than waiting on the publish: the
# requirement in `openvtc/Cargo.toml` still names `0.4.6` (the version VGI carries
# at that rev), and this patch is what decides where that 0.4.6 comes from.
#
# Pinned by `rev`, never by `branch` — a further push to that PR must not silently
# change what this builds against. VGI's own manifest pins `trql-client` the same
# way, and both git sources are allow-listed in `deny.toml`.
#
# **Delete this whole block the moment VGI publishes 0.4.7 on vta-sdk 0.31**, and
# raise the floor in `openvtc/Cargo.toml` to name that release. `publish = false`
# here, so a git source costs this workspace nothing on its own release path — but
# it is still a dependency on an unmerged branch, which is a thing to unwind
# rather than to keep.
[patch.crates-io]
did-git-sign = { git = "https://github.com/OpenVTC/verifiable-git-infrastructure", rev = "462032cfd4adcec9bc00ee957e2e60b7e42c7dac" }
vgi-core = { git = "https://github.com/OpenVTC/verifiable-git-infrastructure", rev = "462032cfd4adcec9bc00ee957e2e60b7e42c7dac" }
20 changes: 16 additions & 4 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,19 @@ skip-tree = [
unknown-registry = "deny"
unknown-git = "deny"
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
# trql-client rides a rev-pinned git dependency until the trust-registry
# release pipeline can publish >= 0.8 to crates.io (the published 0.7.0
# predates the crate's library and must not be used).
allow-git = ["https://github.com/affinidi/affinidi-trust-registry-rs"]
# Both entries are rev-pinned git sources standing in for a release that has not
# happened yet, and both are meant to be deleted rather than lived with.
#
# * `verifiable-git-infrastructure` — `did-git-sign`'s published 0.4.6 requires
# `vta-sdk ^0.27`, which does not build against this workspace's 0.31. The
# `[patch.crates-io]` block in the root `Cargo.toml` takes VGI#33's head
# instead; delete both when VGI publishes 0.4.7. The rationale is written out
# in full there.
# * `affinidi-trust-registry-rs` — `trql-client` rides a rev-pinned git
# dependency until the trust-registry release pipeline publishes a version
# built on the current trust-tasks line. It reaches this workspace only
# through VGI, whose own manifest pins the same rev.
allow-git = [
"https://github.com/OpenVTC/verifiable-git-infrastructure",
"https://github.com/affinidi/affinidi-trust-registry-rs",
]
4 changes: 2 additions & 2 deletions openvtc-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ criterion = { version = "0.8", features = ["html_reports"] }
# embedded in the test process with the JWT keys, DID document, ACL
# defaults, and local-DID whitelisting set up. Replaces the hand-rolled
# harness that did the same dance manually.
affinidi-messaging-test-mediator = "0.2"
affinidi-messaging-test-mediator = "0.4"
# In-process MockVta for the bootstrap e2e (VTI#406/#427 test-support seams).
# `vta-service` is the VTA server crate; it carries the credential-vault
# lifecycle tasks (receive/query/archive/delete/restore/purge) + the
Expand All @@ -118,7 +118,7 @@ affinidi-messaging-test-mediator = "0.2"
# ApproveScope, ContextDirection}` as its own public API, so a graph holding two
# sdks has two distinct `ApproveScope` types that do not unify. VTI republished
# this crate for exactly this reason (see its Cargo.toml note on `publish`).
vta-service = { version = "0.19", default-features = false, features = ["test-support", "rest", "didcomm"] }
vta-service = { version = "0.22", default-features = false, features = ["test-support", "rest", "didcomm"] }
base64 = { workspace = true }
ed25519-dalek-bip32 = { workspace = true }
secrecy = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion openvtc-core/src/capabilities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::pack_and_send;
pub use trust_tasks_capability_client::{
CAPABILITY_DISABLE_TYPE, CAPABILITY_ENABLE_TYPE, CAPABILITY_LIST_TYPE, CapabilityReply,
CapabilitySummary, TRUST_TASK_ENVELOPE_TYPE, build_list_document, build_toggle_document,
parse_capability_reply, parse_envelope_reply,
parse_capability_reply, parse_envelope_document, parse_envelope_reply,
};

/// Attach an `eddsa-jcs-2022` Data-Integrity proof over `doc` (minus the
Expand Down
5 changes: 5 additions & 0 deletions openvtc-core/tests/join_lifecycle_e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@ async fn respond_status(
status: status.to_string(),
needs: Vec::new(),
presentation_definition: None,
// Refusal detail (vta-sdk 0.31): carried only on a `rejected`
// status, which this helper does not exercise.
code: None,
reason: None,
decided_at: None,
};
let response = Message::build(
Uuid::new_v4().to_string(),
Expand Down
48 changes: 35 additions & 13 deletions openvtc-core/tests/mockvta_bootstrap_e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
//! NOTE: depends on the `vta-service` git dev-dependency (the VTA server crate
//! is not on crates.io); its git source is allow-listed in `deny.toml`.

use vta_sdk::client::{CreateContextRequest, CreateDidWebvhRequest, VtaClient};
use vta_sdk::client::{ClientIdentity, CreateContextRequest, CreateDidWebvhRequest, VtaClient};
use vta_sdk::protocols::did_management::create::WebvhPathMode;
use vta_sdk::provision_client::{
EphemeralSetupKey, ProvisionAsk, provision_admin_rotated_via_rest,
Expand Down Expand Up @@ -90,12 +90,26 @@ async fn bootstrap_creates_top_context_and_lists_webvh_server() {
// Authenticated client. `mint_token` with an empty contexts vec is
// super-admin (top-level context creation is super-admin only); it bypasses
// the DIDComm-packed live handshake the REST-only mock can't unpack.
let token = mock
.ctx
.mint_token("did:key:z6MkOpenVtcAdmin", "admin", vec![])
.await;
let client = VtaClient::new(mock.base_url());
client.set_token_async(token).await;
//
// The token authenticates the *connection*; from vta-sdk 0.31 a dispatched
// Trust-Task document also needs an in-band `recipient` and a `proof` (SPEC
// §7.2 items 5b/7a), which the client can only produce from a
// `ClientIdentity`. So the admin is a real, self-resolving `did:key` whose
// private key the client holds, and the token is minted for *that* DID —
// item 6 rejects a document whose in-band issuer disagrees with the
// identity the transport authenticated as.
let admin = EphemeralSetupKey::generate().expect("generate admin key");
let token = mock.ctx.mint_token(&admin.did, "admin", vec![]).await;
let client = VtaClient::authenticated(
mock.base_url(),
ClientIdentity {
client_did: admin.did.clone(),
private_key_multibase: admin.private_key_multibase().to_string(),
vta_did: mock.vta_did().to_string(),
},
token,
)
.await;

// State-A: create the account's top-level context.
let ctx = client
Expand Down Expand Up @@ -137,12 +151,20 @@ async fn persona_did_webvh_mint_round_trips() {
// server-managed mint publishes and resolves entirely in-process (VTI#431).
let mock = MockVta::start_with_webvh_host().await;

let token = mock
.ctx
.mint_token("did:key:z6MkOpenVtcMintAdmin", "admin", vec![])
.await;
let client = VtaClient::new(mock.base_url());
client.set_token_async(token).await;
// Signed-document identity as above: a real `did:key` the client can sign
// as, and a token minted for the same DID.
let admin = EphemeralSetupKey::generate().expect("generate admin key");
let token = mock.ctx.mint_token(&admin.did, "admin", vec![]).await;
let client = VtaClient::authenticated(
mock.base_url(),
ClientIdentity {
client_did: admin.did.clone(),
private_key_multibase: admin.private_key_multibase().to_string(),
vta_did: mock.vta_did().to_string(),
},
token,
)
.await;

// State-B: mint the persona did:webvh against the hosting server.
let minted = client
Expand Down
20 changes: 14 additions & 6 deletions openvtc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,20 @@ anyhow.workspace = true
# own repo (OpenVTC/verifiable-git-infrastructure); openvtc is a downstream
# consumer of the published crate.
#
# Floor is 0.4.6: the first release built on vta-sdk 0.27, so it is what leaves
# ONE vta-sdk in this binary. This is the third consecutive cycle where that
# sentence had to be rewritten — 0.4.3 was the first on 0.23, 0.4.5 the first on
# 0.25 — so read it as a standing obligation rather than a historical note: when
# the workspace's vta-sdk minor moves, VGI has to publish before this line can
# follow, and until it does the graph carries two sdks.
# Floor is 0.4.6, but 0.4.6 is NOT where this resolves from: the `did-git-sign`
# entry under `[patch.crates-io]` in the root manifest redirects it to VGI#33's
# head, the unpublished commit that takes VGI to vta-sdk 0.31. The published
# 0.4.6 requires `^0.27`, which against this workspace's 0.31 does not merely
# split the graph — `vta-keys` 0.2.9 will not compile against `vti-common` 0.15,
# so the build fails outright. Read the patch block for the full rationale and
# for what to delete once 0.4.7 exists; this line then names 0.4.7.
#
# That patch is what the standing obligation now looks like when it is not yet
# discharged. It is the fourth consecutive cycle — 0.4.3 was the first release on
# vta-sdk 0.23, 0.4.5 the first on 0.25, 0.4.6 the first on 0.27 — so read the
# rule rather than the version: when the workspace's vta-sdk minor moves, VGI has
# to move with it, and until it publishes, the graph carries two sdks unless
# something says otherwise.
#
# The floor must name the exact release, never a lower caret. `"0.4.3"` admitted
# 0.4.5, which requires `vta-sdk ^0.25` — so while this workspace was already on
Expand Down
11 changes: 10 additions & 1 deletion openvtc/src/state_handler/message_dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,16 @@ pub async fn process_inbound_message(
// document's `threadId` (== our request id). Foreign trust tasks riding
// the same envelope type are ignored here.
if message.typ == openvtc_core::capabilities::TRUST_TASK_ENVELOPE_TYPE {
if let Some((thid, reply)) = openvtc_core::capabilities::parse_envelope_reply(&message.body)
// trust-tasks-capability-client 0.17 folded the §4.9 correlation check
// into the parse: `parse_envelope_reply` now takes the thread id the
// caller is waiting on. This is a fan-in point that is waiting on
// nothing in particular, so the document is read first and classified
// against its own `threadId`; the correlation that matters is still
// `apply_capability_replies` matching it to the open view's
// `pending_thid`, and an uncorrelated reply is dropped there.
if let Some((thid, doc)) =
openvtc_core::capabilities::parse_envelope_document(&message.body)
&& let Some(reply) = openvtc_core::capabilities::parse_capability_reply(&doc, &thid)
{
capability_replies.push((thid, reply));
}
Expand Down
25 changes: 21 additions & 4 deletions openvtc/src/state_handler/setup_vta_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::state_handler::{
};
use std::sync::Arc;
use tokio::sync::{mpsc, watch};
use vta_sdk::client::VtaClient;
use vta_sdk::client::{ClientIdentity, VtaClient};
use vta_sdk::provision_client::{
DiagStatus, EphemeralSetupKey, Protocol, ProvisionAsk, VtaEvent, VtaIntent, VtaReply,
apply_update, pending_list, provision_admin_rotated_via_rest, run_connection_test,
Expand Down Expand Up @@ -450,9 +450,26 @@ pub(crate) async fn handle_vta_start_provision(
state.setup.vta.messages.push(MessageType::Info(
"VTA authentication successful.".to_string(),
));
let client = VtaClient::new(&vta_url);
client.set_token(token_result.access_token);
client
// `new` + `set_token` is the shape vta-sdk 0.31 stopped
// accepting: a bearer token authenticates the connection,
// but SPEC §7.2 items 5b/7a want an in-band `recipient` and
// a document `proof`, which the client can only produce
// from the identity it signs as. Without it the very next
// Trust-Task dispatch on this client — the context probe
// below — fails with "authenticated but carries no
// ClientIdentity". `connect_auto`'s REST arm builds exactly
// this; this branch is hand-rolled only because the wizard
// needs the token itself to cache.
VtaClient::authenticated(
&vta_url,
ClientIdentity {
client_did: admin.admin_did.clone(),
private_key_multibase: admin.admin_private_key_mb.clone(),
vta_did: vta_did.clone(),
},
token_result.access_token,
)
.await
}
Err(e) => {
state
Expand Down
Loading