microsandbox_image/registry/
builder.rs1use oci_client::{
2 Client,
3 client::{Certificate, CertificateEncoding, ClientConfig, ClientProtocol},
4};
5use rustls_pki_types::{CertificateDer, pem::PemObject};
6
7use microsandbox_types::RegistryAuth;
8
9use crate::{
10 cache::GlobalCache,
11 error::{ImageError, ImageResult},
12 platform::Platform,
13};
14
15use super::client::{Registry, resolve_platform_digest};
16
17pub struct RegistryBuilder {
23 pub(super) platform: Platform,
24 pub(super) cache: GlobalCache,
25 pub(super) auth: oci_client::secrets::RegistryAuth,
26 pub(super) insecure_registries: Vec<String>,
27 pub(super) extra_ca_certs: Vec<Vec<u8>>,
28}
29
30impl RegistryBuilder {
35 pub(crate) fn new(platform: Platform, cache: GlobalCache) -> Self {
37 Self {
38 platform,
39 cache,
40 auth: oci_client::secrets::RegistryAuth::Anonymous,
41 insecure_registries: Vec::new(),
42 extra_ca_certs: Vec::new(),
43 }
44 }
45
46 pub fn auth(mut self, auth: RegistryAuth) -> Self {
48 self.auth = match auth {
49 RegistryAuth::Anonymous => oci_client::secrets::RegistryAuth::Anonymous,
50 RegistryAuth::Basic { username, password } => {
51 oci_client::secrets::RegistryAuth::Basic(username, password)
52 }
53 };
54 self
55 }
56
57 pub fn add_insecure_registries(mut self, registries: Vec<String>) -> Self {
59 self.insecure_registries.extend(registries);
60 self
61 }
62
63 pub fn extra_ca_certs(mut self, certs: Vec<Vec<u8>>) -> Self {
65 self.extra_ca_certs = certs;
66 self
67 }
68
69 pub fn build(self) -> ImageResult<Registry> {
74 let protocol = if self.insecure_registries.is_empty() {
75 ClientProtocol::Https
76 } else {
77 ClientProtocol::HttpsExcept(self.insecure_registries)
78 };
79
80 let mut extra_root_certificates = Vec::new();
81 for (i, pem_data) in self.extra_ca_certs.into_iter().enumerate() {
82 let certs: Vec<_> = CertificateDer::pem_slice_iter(&pem_data)
83 .collect::<Result<_, _>>()
84 .map_err(|e| {
85 ImageError::InvalidCertificate(format!("entry {i}: failed to parse: {e}"))
86 })?;
87
88 if certs.is_empty() {
89 return Err(ImageError::InvalidCertificate(format!(
90 "entry {i}: no certificates found in PEM data"
91 )));
92 }
93
94 for cert in certs {
95 extra_root_certificates.push(Certificate {
96 encoding: CertificateEncoding::Der,
97 data: cert.to_vec(),
98 });
99 }
100 }
101
102 let platform = self.platform.clone();
103 let client = Client::new(ClientConfig {
104 protocol,
105 extra_root_certificates,
106 platform_resolver: Some(Box::new(move |manifests| {
107 resolve_platform_digest(manifests, &platform)
108 })),
109 ..Default::default()
110 });
111
112 Ok(Registry {
113 client,
114 auth: self.auth,
115 platform: self.platform,
116 cache: self.cache,
117 })
118 }
119}