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
//! Storage transports selected by the execution host.
use std::fmt::{self, Debug, Formatter};
use serde::{Deserialize, Serialize};
/// Resolved storage configuration, serialized across the lockstep native boundary.
///
/// This describes storage I/O, not resource lookup or publication. The runtime
/// owns transport policy and instrumentation. Additional transports can extend
/// this contract without exposing storage callbacks to SDK consumers.
#[derive(Clone, Serialize, Deserialize)]
#[serde(tag = "backend", rename_all = "snake_case", deny_unknown_fields)]
pub enum StorageConfig {
/// Explicit local files. The host is responsible for authorizing this root.
Local {
/// Absolute `file://` directory URI, ending in `/`.
root_uri: String,
},
/// Object storage accessed through the SPFS signing transport.
Spfs {
/// Plain HTTP(S) URL of the storage shim, not a control-plane endpoint.
endpoint: String,
/// Authorized `spfsm://` or `spfsu://` mount root, or a directory URI ending in `/`.
root_uri: String,
/// Initial operation-scoped credential. Renewal belongs to the host.
credential: String,
/// Host-resolved alias of the same root for Table-owned blob references.
#[serde(default, skip_serializing_if = "Option::is_none")]
root_alias: Option<String>,
},
/// Object storage at an S3 provider, accessed with a session the host vended for this root.
S3 {
/// Authorized `s3://bucket/prefix/` root, ending in `/`.
root_uri: String,
/// Initial session, as JSON [`S3Session`]. Renewals return the same shape.
credential: String,
/// The root's SPFS address, which the table's object references name.
#[serde(default, skip_serializing_if = "Option::is_none")]
root_alias: Option<String>,
},
/// Object storage in Google Cloud Storage, accessed with an access token the host vended for
/// this root.
Gcs {
/// Authorized `gs://bucket/prefix/` root, ending in `/`.
root_uri: String,
/// Initial token, as JSON [`GcsSession`]. Renewals return the same shape.
credential: String,
/// The root's SPFS address, which the table's object references name.
#[serde(default, skip_serializing_if = "Option::is_none")]
root_alias: Option<String>,
},
}
/// A short-lived Cloud Storage access token scoped to one root, as the host renews it.
#[derive(Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct GcsSession {
pub access_token: String,
/// When the token stops working, in Unix microseconds.
pub expires_at_micros: i64,
}
impl Debug for GcsSession {
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("GcsSession")
.field("expires_at_micros", &self.expires_at_micros)
.finish_non_exhaustive()
}
}
/// A short-lived S3 session scoped to one root, as the host renews it.
#[derive(Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct S3Session {
pub access_key_id: String,
pub secret_access_key: String,
pub session_token: String,
/// The region the session signs for.
pub region: String,
/// The S3-compatible endpoint that minted the session; absent for AWS.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub endpoint: Option<String>,
/// When the session stops working, in Unix microseconds.
pub expires_at_micros: i64,
}
impl Debug for S3Session {
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("S3Session")
.field("region", &self.region)
.field("endpoint", &self.endpoint)
.field("expires_at_micros", &self.expires_at_micros)
.finish_non_exhaustive()
}
}
impl Debug for StorageConfig {
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Local { root_uri } => formatter
.debug_struct("Local")
.field("root_uri", root_uri)
.finish(),
Self::Spfs {
endpoint, root_uri, ..
} => formatter
.debug_struct("Spfs")
.field("endpoint", endpoint)
.field("root_uri", root_uri)
.finish_non_exhaustive(),
Self::S3 { root_uri, .. } => formatter
.debug_struct("S3")
.field("root_uri", root_uri)
.finish_non_exhaustive(),
Self::Gcs { root_uri, .. } => formatter
.debug_struct("Gcs")
.field("root_uri", root_uri)
.finish_non_exhaustive(),
}
}
}
#[cfg(test)]
mod tests {
use super::StorageConfig;
#[test]
fn storage_configuration_is_typed_and_redacts_credentials() {
let config = StorageConfig::Spfs {
endpoint: "https://storage.example.test".into(),
root_uri: "spfsm://mount/table/".into(),
credential: "scoped-secret".into(),
root_alias: None,
};
assert!(!format!("{config:?}").contains("scoped-secret"));
let encoded = serde_json::to_value(config).unwrap();
assert_eq!(encoded["backend"], "spfs");
assert!(serde_json::from_value::<StorageConfig>(encoded).is_ok());
assert!(
serde_json::from_str::<StorageConfig>(
r#"{"backend":"local","root_uri":"file:///tmp/","credential":"unexpected"}"#
)
.is_err()
);
}
}