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
176
177
//! Host service traits for capability-gated plugin host functions.
//!
//! `uni.kms.*` and `uni.http.*` host functions need a backing host service to
//! perform real work. These traits define that seam in the shared `uni-plugin`
//! crate so every loader (Rhai today; Extism / WASM at the host-fn cutover)
//! binds the *same* abstraction rather than each inventing its own. The host
//! supplies concrete implementations (e.g. a `reqwest`-backed [`HttpEgress`] in
//! `uni-plugin-host`) and hands them to the loader.
//!
//! Secret acquisition has no trait here — it reuses
//! [`crate::secrets::SecretStore`] directly.
use Arc;
use Duration;
use crate;
use crateFnError;
/// A signing / verification service backing the `uni.kms.*` host functions.
///
/// Implementations are expected to enforce nothing about *which* key ids are
/// permissible — that attenuation is checked against the plugin's granted
/// [`crate::Capability::Kms`] before this trait is called.
/// Response returned by an [`HttpEgress`] request.
/// A **blocking** HTTP egress service backing the `uni.http.*` host functions.
///
/// Methods are synchronous because the Rhai engine runs scripts synchronously
/// (inside DataFusion scalar/procedure execution). Implementations must be safe
/// to call from within a Tokio runtime context — e.g. by running the request on
/// a dedicated OS thread rather than blocking a Tokio worker. URL allow-listing,
/// timeout, and response-size limits are enforced by the caller against the
/// plugin's granted [`crate::Capability::Network`]; the `timeout` and
/// `max_bytes` arguments carry those decisions into the request.
///
/// `traceparent`, when `Some`, is injected as the W3C `traceparent` request
/// header so the host's trace context propagates across the plugin boundary
/// into the outbound call (see [`crate::observability::TraceContext::to_traceparent`]).
// ---------------------------------------------------------------------------
// Shared `uni.http.*` policy
// ---------------------------------------------------------------------------
/// Default per-call HTTP timeout when the grant carries no
/// [`Capability::WallClockMillisPerCall`].
///
/// Conservative: long enough for a typical API call, short enough to bound a
/// wedged request.
pub const DEFAULT_HTTP_TIMEOUT: Duration = from_secs;
/// Maximum response body bytes read before truncation — bounds host memory so a
/// hostile or oversized response cannot exhaust it.
pub const MAX_HTTP_RESPONSE_BYTES: usize = 8 * 1024 * 1024;
/// Why a capability-gated HTTP call was refused.
///
/// The loaders share the *decisions* and keep their own *encoding*: the Extism
/// loader maps these onto the numeric `FnError` codes its guest ABI pins
/// (`0xC20`, `0xC21`, `0xC23`), the Rhai loader onto `EvalAltResult` strings.
/// Splitting it this way is what lets both share the policy without either
/// changing its published error contract.
/// Resolve the per-call HTTP timeout from the granted capabilities.
///
/// The first [`Capability::WallClockMillisPerCall`] in the set wins; absent
/// one, [`DEFAULT_HTTP_TIMEOUT`].
/// Run a capability-gated HTTP request: allow-list check, egress presence,
/// timeout resolution, dispatch, then the `>= 400` status gate.
///
/// `body` present selects POST, absent selects GET. `traceparent` is the host's
/// active W3C trace context, threaded through as a parameter rather than read
/// from ambient state so the dispatch stays unit-testable.
///
/// # Errors
///
/// Returns [`HttpPolicyError`] for each refusal reason; see its variants.