This repository was archived by the owner on Jan 19, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathoci.rs
More file actions
146 lines (134 loc) · 4.59 KB
/
oci.rs
File metadata and controls
146 lines (134 loc) · 4.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use anyhow::Result;
use cached::proc_macro::cached;
use kubewarden_policy_sdk::host_capabilities::oci::ManifestDigestResponse;
use policy_fetcher::{
oci_client::{
manifest::{OciImageManifest, OciManifest},
Reference,
},
registry::Registry,
sources::Sources,
};
use serde::{Deserialize, Serialize};
/// Helper struct to interact with an OCI registry
pub(crate) struct Client {
sources: Option<Sources>,
registry: Registry,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ManifestAndConfigResponse {
pub manifest: OciImageManifest,
pub digest: String,
pub config: serde_json::Value,
}
impl Client {
pub fn new(sources: Option<Sources>) -> Self {
let registry = Registry {};
Client { sources, registry }
}
/// Fetch the manifest digest of the OCI resource referenced via `image`
pub async fn digest(&self, image: &str) -> Result<String> {
// this is needed to expand names as `busybox` into
// fully resolved references like `docker.io/library/busybox`
let image_ref: Reference = image.parse()?;
let image_with_proto = format!("registry://{}", image_ref.whole());
let image_digest = self
.registry
.manifest_digest(&image_with_proto, self.sources.as_ref())
.await?;
Ok(image_digest)
}
pub async fn manifest(&self, image: &str) -> Result<OciManifest> {
// this is needed to expand names as `busybox` into
// fully resolved references like `docker.io/library/busybox`
let image_ref: Reference = image.parse()?;
let image_with_proto = format!("registry://{}", image_ref.whole());
let manifest = self
.registry
.manifest(&image_with_proto, self.sources.as_ref())
.await?;
Ok(manifest)
}
pub async fn manifest_and_config(&self, image: &str) -> Result<ManifestAndConfigResponse> {
// this is needed to expand names as `busybox` into
// fully resolved references like `docker.io/library/busybox`
let image_ref: Reference = image.parse()?;
let image_with_proto = format!("registry://{}", image_ref.whole());
let (manifest, digest, config) = self
.registry
.manifest_and_config(&image_with_proto, self.sources.as_ref())
.await?;
Ok(ManifestAndConfigResponse {
manifest,
digest,
config,
})
}
}
// Interacting with a remote OCI registry is time expensive, this can cause a massive slow down
// of policy evaluations, especially inside of PolicyServer.
// Because of that we will keep a cache of the digests results.
//
// Details about this cache:
// * only the image "url" is used as key. oci::Client is not hashable, plus
// the client is always the same
// * the cache is time bound: cached values are purged after 60 seconds
// * only successful results are cached
#[cached(
time = 60,
result = true,
sync_writes = "default",
key = "String",
convert = r#"{ format!("{}", img) }"#,
with_cached_flag = true
)]
pub(crate) async fn get_oci_digest_cached(
oci_client: &Client,
img: &str,
) -> Result<cached::Return<ManifestDigestResponse>> {
oci_client
.digest(img)
.await
.map(|digest| ManifestDigestResponse { digest })
.map(cached::Return::new)
}
// Interacting with a remote OCI registry is time expensive, this can cause a massive slow down
// of policy evaluations, especially inside of PolicyServer.
// Because of that we will keep a cache of the manifest results.
//
// Details about this cache:
// * only the image "url" is used as key. oci::Client is not hashable, plus
// the client is always the same
// * the cache is time bound: cached values are purged after 60 seconds
// * only successful results are cached
#[cached(
time = 60,
result = true,
sync_writes = "default",
key = "String",
convert = r#"{ format!("{}", img) }"#,
with_cached_flag = true
)]
pub(crate) async fn get_oci_manifest_cached(
oci_client: &Client,
img: &str,
) -> Result<cached::Return<OciManifest>> {
oci_client.manifest(img).await.map(cached::Return::new)
}
#[cached(
time = 60,
result = true,
sync_writes = "default",
key = "String",
convert = r#"{ format!("{}", img) }"#,
with_cached_flag = true
)]
pub(crate) async fn get_oci_manifest_and_config_cached(
oci_client: &Client,
img: &str,
) -> Result<cached::Return<ManifestAndConfigResponse>> {
oci_client
.manifest_and_config(img)
.await
.map(cached::Return::new)
}