1#![allow(unknown_lints)]
8#![deny(
9 clippy::await_holding_lock,
10 clippy::borrow_as_ptr,
11 clippy::branches_sharing_code,
12 clippy::cast_lossless,
13 clippy::clippy::collection_is_never_read,
14 clippy::cloned_instead_of_copied,
15 clippy::cognitive_complexity,
16 clippy::create_dir,
17 clippy::deref_by_slicing,
18 clippy::derivable_impls,
19 clippy::derive_partial_eq_without_eq,
20 clippy::equatable_if_let,
21 clippy::exhaustive_structs,
22 clippy::expect_used,
23 clippy::expl_impl_clone_on_copy,
24 clippy::explicit_deref_methods,
25 clippy::explicit_into_iter_loop,
26 clippy::explicit_iter_loop,
27 clippy::filetype_is_file,
28 clippy::flat_map_option,
29 clippy::format_push_string,
30 clippy::fn_params_excessive_bools,
31 clippy::future_not_send,
32 clippy::get_unwrap,
33 clippy::implicit_clone,
34 clippy::if_then_some_else_none,
35 clippy::impl_trait_in_params,
36 clippy::implicit_clone,
37 clippy::inefficient_to_string,
38 clippy::inherent_to_string,
39 clippy::iter_not_returning_iterator,
40 clippy::large_types_passed_by_value,
41 clippy::large_include_file,
42 clippy::let_and_return,
43 clippy::manual_assert,
44 clippy::manual_ok_or,
45 clippy::manual_split_once,
46 clippy::manual_let_else,
47 clippy::manual_string_new,
48 clippy::map_flatten,
49 clippy::map_unwrap_or,
50 clippy::missing_enforced_import_renames,
51 clippy::missing_assert_message,
52 clippy::missing_const_for_fn,
53 clippy::must_use_candidate,
54 clippy::mut_mut,
55 clippy::needless_for_each,
56 clippy::needless_option_as_deref,
57 clippy::needless_pass_by_value,
58 clippy::needless_collect,
59 clippy::needless_continue,
60 clippy::non_send_fields_in_send_ty,
61 clippy::nonstandard_macro_braces,
62 clippy::option_if_let_else,
63 clippy::option_option,
64 clippy::rc_mutex,
65 clippy::redundant_else,
66 clippy::same_name_method,
67 clippy::semicolon_if_nothing_returned,
68 clippy::str_to_string,
69 clippy::string_to_string,
70 clippy::too_many_lines,
71 clippy::trivially_copy_pass_by_ref,
72 clippy::trivial_regex,
73 clippy::try_err,
74 clippy::unnested_or_patterns,
75 clippy::unused_async,
76 clippy::unwrap_or_else_default,
77 clippy::useless_let_if_seq,
78 bad_style,
79 clashing_extern_declarations,
80 dead_code,
81 deprecated,
82 explicit_outlives_requirements,
83 improper_ctypes,
84 invalid_value,
85 missing_copy_implementations,
86 missing_debug_implementations,
87 mutable_transmutes,
88 no_mangle_generic_items,
89 non_shorthand_field_patterns,
90 overflowing_literals,
91 path_statements,
92 patterns_in_fns_without_body,
93 private_in_public,
94 trivial_bounds,
95 trivial_casts,
96 trivial_numeric_casts,
97 type_alias_bounds,
98 unconditional_recursion,
99 unreachable_pub,
100 unsafe_code,
101 unstable_features,
102 unused,
103 unused_allocation,
104 unused_comparisons,
105 unused_import_braces,
106 unused_parens,
107 unused_qualifications,
108 while_true,
109 missing_docs
110)]
111#![warn(clippy::exhaustive_enums)]
112#![allow(unused_attributes, clippy::derive_partial_eq_without_eq, clippy::box_default)]
113#![allow(missing_docs)]
116
117pub mod error;
119mod manifest;
120mod options;
121pub mod package;
123mod pull;
124mod push;
125pub mod utils;
126
127pub use error::OciError as Error;
128pub use manifest::*;
129pub use oci_distribution::client::ClientProtocol;
130pub use oci_distribution::manifest::{OciDescriptor, OciImageIndex, OciImageManifest, OciManifest};
131pub use options::*;
132pub use pull::*;
133pub use push::*;
134use serde::{Deserialize, Serialize};
135pub use utils::{
136 get_cache_directory,
137 is_oci_reference,
138 is_wick_package_reference,
139 parse_reference,
140 parse_reference_and_protocol,
141};
142
143use crate::error::OciError;
144
145#[macro_use]
146extern crate tracing;
147
148pub const OCI_VAR_USER: &str = "OCI_USERNAME";
151pub const OCI_VAR_PASSWORD: &str = "OCI_PASSWORD";
153
154const WASM_MEDIA_TYPE: &str = oci_distribution::manifest::WASM_LAYER_MEDIA_TYPE;
155const LAYER_MEDIA_TYPE: &str = oci_distribution::manifest::IMAGE_LAYER_MEDIA_TYPE;
156
157#[derive(Debug, Serialize, Deserialize)]
159#[non_exhaustive]
160pub struct WickOciConfig {
161 pub kind: WickPackageKind,
162 pub root: String,
163}
164
165impl WickOciConfig {
166 #[must_use]
168 pub const fn new(kind: WickPackageKind, root: String) -> Self {
169 Self { kind, root }
170 }
171}
172
173#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
176#[non_exhaustive]
177pub enum WickPackageKind {
178 APPLICATION,
180 COMPONENT,
182 TYPES,
184}
185
186pub async fn fetch_image_manifest(image: &str, options: &OciOptions) -> Result<(OciImageManifest, String), OciError> {
188 if !options.allow_latest && image.ends_with(":latest") {
189 return Err(OciError::LatestDisallowed(image.to_owned()));
190 }
191 debug!(image, "oci remote");
192
193 let image = parse_reference(image)?;
194
195 let auth = options
196 .username()
197 .as_ref()
198 .map_or(oci_distribution::secrets::RegistryAuth::Anonymous, |u| {
199 options
200 .password()
201 .as_ref()
202 .map_or(oci_distribution::secrets::RegistryAuth::Anonymous, |p| {
203 oci_distribution::secrets::RegistryAuth::Basic(u.clone(), p.clone())
204 })
205 });
206
207 let protocol = oci_distribution::client::ClientProtocol::HttpsExcept(options.allow_insecure.clone());
208 let config = oci_distribution::client::ClientConfig {
209 protocol,
210 ..Default::default()
211 };
212 let mut client = oci_distribution::Client::new(config);
213 let (manifest, digest) = client
214 .pull_manifest(&image, &auth)
215 .await
216 .map_err(|e| OciError::OciFetchFailure(image.to_string(), e.to_string()))?;
217 let OciManifest::Image(manifest) = manifest else {
218 return Err(OciError::OciFetchFailure(
219 image.to_string(),
220 "manifest is not an image".to_owned(),
221 ));
222 };
223 Ok((manifest, digest))
224}