1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//! DIDComm transport for `provision-integration`.
//!
//! Holder side. Sends a VP-framed [`super::BootstrapRequest`] over an
//! authcrypt'd DIDComm session and receives the sealed
//! `TemplateBootstrap` bundle in the reply. Wire shapes are
//! transport-neutral — the payload that arrives is the same armored
//! bundle the REST endpoint returns.
//!
//! Use this when the holder already has a DIDComm session open to the
//! VTA (e.g., the integration's setup wizard). For file-based offline
//! bootstrap, use the `vta bootstrap provision-integration` CLI on the
//! VTA host.
//!
//! Auth model — layered like an onion. The request is a Trust Task
//! document carried in the DIDComm binding envelope and signed by the
//! *relayer* (the session's DID): that Data Integrity proof, bound to the
//! document's `issuer` and the DIDComm sender, authenticates the relayer,
//! and the VTA's ACL gates it (relayer must be admin in the target
//! context). The DIDComm sender alone authenticates nobody. Inside the
//! body, the VP's `DataIntegrityProof` authenticates the *holder*
//! — the bundle is HPKE-sealed to the holder's X25519 derivation,
//! so only the holder can open it. Sender and holder may legitimately
//! differ; the air-gap onboarding flow relies on this:
//!
//! 1. Third-party integration (air-gapped) signs a BootstrapRequest
//! with its own ephemeral did:key.
//! 2. Request is transferred to the operator's host.
//! 3. Operator's PNM relays the request over its DIDComm session.
//! 4. VTA issues the bundle, sealed to the integration.
//! 5. Operator carries the (encrypted) bundle back across the
//! air-gap; only the integration can decrypt.
use crateDIDCommSession;
use crateVtaError;
use crate;
use Value;
use ;
/// Default DIDComm round-trip timeout (seconds). Generous so the VTA
/// has time to mint keys, render templates, build the webvh log, and
/// seal the bundle — all of which happen synchronously inside the
/// shared library function before the reply lands.
const DEFAULT_TIMEOUT_SECS: u64 = 60;
/// The DIDComm binding envelope — the only DIDComm carriage for a Trust Task.
const TRUST_TASK_ENVELOPE_TYPE: &str = "https://trusttasks.org/binding/didcomm/0.1/envelope";
/// Send a `provision-integration` request over an existing DIDComm
/// session.
///
/// The holder must have an authcrypt'd DIDComm session open to the
/// VTA — see [`DIDCommSession::connect`]. The session's `client_did`
/// must already hold admin role in the target context's ACL; the VTA
/// rejects with `Forbidden` (mapped to [`VtaError::Auth`]) otherwise.
///
/// Returns the same shape the REST endpoint produces: armored sealed
/// bundle + sha256 digest + summary (including `admin_did` /
/// `admin_rolled_over` when the VP requested rollover via
/// `adminTemplate`).
///
/// `assertion` defaults to [`AssertionMode::DidSigned`] when `None`.
///
/// `create_context` opts into super-admin context creation when the
/// target context isn't yet registered — same semantics as the REST
/// path. Default is `false` (caller must have created the context
/// out-of-band).
///
/// `context` is `Option<String>`. Pass `Some(name)` for the
/// integration-class pattern (caller knows which bucket to provision
/// into); pass `None` to let the VTA infer per the canonical Trust
/// Task spec's three rules — typical for wallet-class callers that
/// don't track the maintainer's context layout. See
/// [`crate::provision_integration::http::ProvisionIntegrationRequest::context`]
/// for the full inference rules + error semantics.
///
/// `spec_version` selects the Trust Task wire version, and a caller in this
/// workspace passes [`ProvisionSpecVersion::CURRENT`] — the VTA serves exactly
/// one version of this operation at a time. The older variants remain callable
/// because they still describe wire forms this crate can *render*, which is
/// what makes them testable: [`ProvisionSpecVersion::V0_1`] emits the legacy
/// snake_case option fields + kebab `assertion` under the
/// `provision/integration/0.1` URI, and [`ProvisionSpecVersion::V0_2`] emits
/// lowerCamelCase (`vcValiditySeconds` / `createContext` / `didSigned`) under
/// the `0.2` URI. Neither is dispatchable against a current VTA — both were
/// removed rather than deprecated, so they come back `unsupportedType`.
/// The signed VP carried in `request` is left byte-identical
/// either way — its casing is the holder's, and the VTA dual-accepts both.
/// That is why `request` is a raw [`Value`] and not a typed
/// [`BootstrapRequest`](super::BootstrapRequest): the claim above was
/// false while this took the
/// struct, because serialising it re-rendered the holder's document in
/// this crate's casing.
pub async
/// Send one Trust Task over a raw [`DIDCommSession`]: the document is issued by
/// the session's DID, addressed to its VTA, signed with `key`, carried in the
/// DIDComm binding envelope, and the reply's `payload` is decoded as `T`.
///
/// The signature is what identifies the caller: the VTA refuses any document
/// over DIDComm whose proof, `issuer` and sender are not one DID.
pub async