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