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