1pub mod ca;
15pub mod plumb;
16pub mod policy;
17
18pub use plumb::Plumbing;
19pub use policy::{EgressSecretSpec, EgressSpec, Entry, HostPattern, Policy, SecretBinding};
20
21use crate::client::Client;
22use crate::error::Result;
23use plumb::{KEY_POLICY, Props};
24
25#[derive(Debug, Clone)]
27pub struct Contribution {
28 pub plumbing: Plumbing,
29 pub nic: Props,
30 pub config: Props,
31}
32
33pub fn contribute(spec: &EgressSpec, project: &str, instance: &str) -> Result<Contribution> {
37 let network = plumb::network_name(project, instance);
38 let policy = Policy::from_spec(spec, &network)?;
39 let plumbing = Plumbing::new(project, instance, policy);
40 let mut config = Props::new();
41 config.insert(KEY_POLICY.into(), plumbing.policy_json());
42 config.insert(plumb::KEY_FOR.into(), plumbing.owner());
43 for s in &plumbing.policy.secrets {
44 config.insert(format!("environment.{}", s.env), s.placeholder.clone());
45 }
46 if !plumbing.policy.secrets.is_empty() {
47 config.extend(ca::guest_env());
48 }
49 Ok(Contribution {
50 nic: plumbing.nic(),
51 plumbing,
52 config,
53 })
54}
55
56pub fn before_apply(client: &Client, p: &Plumbing, report: &mut dyn FnMut(&str)) -> Result<()> {
58 if !p.policy.secrets.is_empty() {
60 ca::Ca::ensure(&p.network)?;
61 }
62 plumb::prepare(client, p, report)?;
63 Ok(())
64}
65
66pub fn after_ready(client: &Client, p: &Plumbing) -> Result<()> {
68 if p.policy.secrets.is_empty() {
69 return Ok(());
70 }
71 match ca::Ca::load(&p.network)? {
72 Some(ca) => ca::install(client, &p.instance, &ca),
73 None => Err(crate::error::Error::invalid(format!(
74 "{}: the egress CA is missing from this host's state directory; recreate the sandbox",
75 p.instance
76 ))),
77 }
78}