liminal_server/config/types/lys.rs
1use std::net::SocketAddr;
2
3/// `[auth.lys]`: the Lys issuer whose passes are admitted (ACCESS-001 R2).
4#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize)]
5#[serde(deny_unknown_fields)]
6pub struct LysConfig {
7 #[serde(default, skip_serializing_if = "Option::is_none")]
8 pub drafts: Option<crate::auth_lys::live::drafts::DraftConfig>,
9 /// The issuer URL exactly as the pass's `iss` names it.
10 pub issuer: String,
11 /// The Lys network liminal's subjects are placed under.
12 pub network_id: String,
13 /// Path to the issuer's published key set as JSON, read once at start.
14 pub keys_path: std::path::PathBuf,
15 /// Ask the issuer live for deliberate decisions (opening a link,
16 /// deploying a service, an administrator's act) with the holder's own
17 /// pass. Off, Lys cannot be asked and every deliberate route refuses by
18 /// that name; it never falls back to the pass.
19 #[serde(default)]
20 pub live: bool,
21 /// This liminal as a machine Lys knows, for links (ACCESS-002 R1).
22 #[serde(default)]
23 pub machine: Option<MachineConfig>,
24 /// Argus's functions as liminal services, bound to Lys and the server's
25 /// publish path (ACCESS-003 R1).
26 #[serde(default)]
27 pub services: Option<LysServicesConfig>,
28 /// Address-only broker and its observed-address UDP echo.
29 #[serde(default)]
30 pub broker: Option<BrokerConfig>,
31 /// Blind forwarding of marked relay streams.
32 #[serde(default)]
33 pub relay: Option<crate::services::relay::RelayConfig>,
34 /// Channel membership from Lys's one shared membership contract
35 /// (ACCESS-006 R1): the explicit product mapping of liminal channels to
36 /// placed Lys resources, and the provider route it is asked through.
37 /// Absent, no channel is membership-protected and every channel keeps
38 /// its prior contract.
39 #[serde(default)]
40 pub membership: Option<MembershipConfig>,
41 /// One bounded reader for this log; required beside membership protection.
42 #[serde(default)]
43 pub grant_stream: Option<super::GrantStreamConfig>,
44 /// Agent station bounds; required when any agent is placed.
45 #[serde(default)]
46 pub agents: Option<crate::agents::config::AgentsConfig>,
47 /// The templates services are created from (SRV-028 R1): the only
48 /// command lines this server will ever run for a seat.
49 #[serde(default)]
50 pub templates: crate::services::lifecycle::templates::TemplateSources,
51 /// Required operator bounds and machine-held builder delegation sources.
52 #[serde(default)]
53 pub construction: Option<crate::services::lifecycle::site::ConstructionConfig>,
54 /// The base of Lys's API routes (`.../api/`) for live asks, placements
55 /// and the service routes, when they are not served at the issuer
56 /// itself; absent, the issuer is the base, as before.
57 #[serde(default)]
58 pub api_url: Option<String>,
59 /// Path to this liminal's Lys app credential, read once at start; a new
60 /// service and its subjects are placed under the network with it
61 /// (SRV-028 R3). Absent, every create is refused by name.
62 #[serde(default)]
63 pub app_credential_path: Option<std::path::PathBuf>,
64}
65
66/// `[[auth.lys.templates]]`: one command a seat may create services from
67/// (SRV-028 R1). Read-only at run time.
68#[derive(Clone, PartialEq, Eq, serde::Deserialize)]
69#[serde(deny_unknown_fields)]
70pub struct ServiceTemplateConfig {
71 /// The template's name, one segment.
72 pub name: String,
73 /// The program, an absolute path to an executable file.
74 pub command: std::path::PathBuf,
75 /// Its arguments, passed as written.
76 #[serde(default)]
77 pub args: Vec<String>,
78 /// The subject roots a service of this template serves; each service
79 /// serves `<root>.<service name>`.
80 pub subjects: Vec<String>,
81 /// Names of variables passed through from the server's environment;
82 /// nothing else of it reaches the process.
83 #[serde(default)]
84 pub env: Vec<String>,
85 /// How long a stop waits after SIGTERM before SIGKILL; positive.
86 pub stop_timeout_ms: u64,
87}
88
89/// `[auth.lys.membership]`: channel membership bound to the verified holder
90/// and the placed resource (ACCESS-006 R1).
91///
92/// The mapping is explicit: a channel is membership-protected only when it is
93/// listed here with its workspace and placed resource, and a participant
94/// conversation is placed under a channel only when it is listed here. No
95/// mapping is guessed from a subject string, and a readable parent is never
96/// taken as membership of a child. Every bound is required and positive;
97/// none has a default. Validated whole when the membership gate is built at
98/// start ([`crate::auth_membership::MembershipGate::new`]).
99#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize)]
100#[serde(deny_unknown_fields)]
101pub struct MembershipConfig {
102 /// The membership contract version this liminal speaks; it must equal
103 /// `lys_pass::membership::CONTRACT_VERSION`.
104 pub contract: u32,
105 /// The identity of the Lys grant log decisions are asked from.
106 pub log_identity: String,
107 /// The reset epoch of that grant log.
108 pub log_epoch: u64,
109 /// The product schema's workspace kind, as Lys places it.
110 pub workspace_kind: String,
111 /// The product schema's channel kind, as Lys places it.
112 pub channel_kind: String,
113 /// Path to this liminal's app credential for the Lys membership routes,
114 /// read once at start. Its bytes never appear in a `Debug`.
115 pub credential_path: std::path::PathBuf,
116 /// Most rows one membership page carries; positive.
117 pub page_rows: u32,
118 /// Most encoded row bytes and HTTP answer bytes; positive. The same cap
119 /// bounds reading the app credential before opening any protected route.
120 pub page_bytes: u32,
121 /// Most decisions the local membership index retains at once; positive.
122 /// A decision past it is refused by name before anything is allocated
123 /// for it, never evicted to make room.
124 pub max_decisions: usize,
125 /// The workspace a Lys-admitted `Connect` must hold a current grant in
126 /// (scoped guest admission). Absent, `Connect` asks no admission and a
127 /// protected channel is still decided per act.
128 #[serde(default)]
129 pub connect_workspace: Option<String>,
130 /// The membership-protected channels.
131 pub channels: Vec<MembershipChannelConfig>,
132 /// Participant conversations placed under a protected channel.
133 #[serde(default)]
134 pub conversations: Vec<MembershipConversationConfig>,
135}
136
137/// One membership-protected channel: the liminal channel name, the
138/// workspace it is placed under and the placed resource id.
139#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize)]
140#[serde(deny_unknown_fields)]
141pub struct MembershipChannelConfig {
142 /// The liminal channel (subject) name, matched exactly.
143 pub channel: String,
144 /// The workspace resource id the channel is placed under.
145 pub workspace: String,
146 /// The placed channel resource id.
147 pub resource: String,
148}
149
150/// One participant conversation placed under a protected channel.
151#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize)]
152#[serde(deny_unknown_fields)]
153pub struct MembershipConversationConfig {
154 /// The participant conversation id.
155 pub conversation: u64,
156 /// The protected channel it is placed under, as listed in `channels`.
157 pub channel: String,
158}
159
160/// `[auth.lys.services]`: the production bindings of the ACCESS-003
161/// services. They ask Lys as this machine, so `[auth.lys.machine]` is
162/// required beside it.
163#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize)]
164#[serde(deny_unknown_fields)]
165pub struct LysServicesConfig {
166 /// The machine id Lys records, on whose runner `seats.<name>` starts.
167 pub machine: String,
168 /// The host name service messages are published as (`liminal.<host>`).
169 pub host: String,
170 /// Run the context watch over the `context-watch` channel, reporting
171 /// each reading to Lys.
172 #[serde(default)]
173 pub context_watch: bool,
174}
175
176/// `[auth.lys.broker]`: the address-only broker's UDP echo listener.
177#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize)]
178#[serde(deny_unknown_fields)]
179pub struct BrokerConfig {
180 /// The socket on which a device asks for its observed address.
181 pub udp_listen: SocketAddr,
182}
183
184/// `[auth.lys.machine]`: this liminal's agent identity and pass.
185///
186/// Its links are keyed from the Ed25519 identity Lys recorded for it,
187/// its own end of every crossing is decided from its own pass, and the
188/// holders that may open links to it are named with their public keys.
189/// The link identity is an agent's own key and pass. The machine section
190/// name is retained so existing file-pass configurations still read.
191#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize)]
192#[serde(deny_unknown_fields)]
193pub struct MachineConfig {
194 /// Carrier order and message-scoped direct deadlines.
195 #[serde(default)]
196 pub carrier_choice: crate::link_open::ChoiceConfig,
197 /// The device this machine is a district of, when configured.
198 #[serde(default)]
199 pub parent: Option<String>,
200 /// Path to the agent's Ed25519 seed, 64 hexadecimal digits, read once
201 /// at start. The link handshake keys from its X25519 derivation.
202 pub identity_path: std::path::PathBuf,
203 /// Path to the agent's own Lys pass, verified at start; absent when
204 /// the signed agent dial is configured.
205 #[serde(default)]
206 pub pass_path: std::path::PathBuf,
207 /// The agent whose capability certificate names this identity's key.
208 /// With it set, the pass is asked of Lys at start and again at any link
209 /// open while none is held or the held one is expired or due for
210 /// renewal; a start whose ask Lys refuses is logged once and asks again
211 /// at the next open, never by a restart (ACCESS-009).
212 #[serde(default)]
213 pub agent_id: String,
214 /// The app the agent asks the issuer for a pass to.
215 #[serde(default)]
216 pub audience: String,
217 /// The public key recorded for each holder that may open a link,
218 /// holder id to Ed25519 public key as 64 hexadecimal digits.
219 #[serde(default)]
220 pub machines: std::collections::BTreeMap<String, String>,
221 /// Outbound links keyed from this machine, each configured by name.
222 #[serde(default)]
223 pub links: Vec<OutboundLinkConfig>,
224}
225
226/// One exporting link; an absent wire address leaves carrier choice to the caller.
227#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize)]
228#[serde(deny_unknown_fields)]
229pub struct OutboundLinkConfig {
230 /// The link id placed under the configured network.
231 pub link_id: String,
232 /// The holder whose Ed25519 key is recorded in this machine's directory mirror.
233 pub peer_holder: String,
234 /// The peer's wire listener as host:port, if this link uses the wire.
235 #[serde(default)]
236 pub peer_address: Option<String>,
237 /// Placed subject prefixes exported over this link.
238 pub exports: Vec<String>,
239}