1mod error;
35mod filesystem;
36mod memory;
37mod noop;
38
39pub use error::{Error, Result};
40pub use filesystem::{FileSystemCache, SIGSTORE_PRODUCTION_URL, SIGSTORE_STAGING_URL};
41pub use memory::InMemoryCache;
42pub use noop::NoCache;
43
44use std::future::Future;
45use std::pin::Pin;
46use std::sync::Arc;
47use std::time::Duration;
48
49pub type CacheGetFuture<'a> = Pin<Box<dyn Future<Output = Result<Option<Vec<u8>>>> + Send + 'a>>;
51
52pub type CacheOpFuture<'a> = Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>;
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
57pub enum CacheKey {
58 RekorPublicKey,
60 RekorLogInfo,
62 FulcioTrustBundle,
64 FulcioConfiguration,
66 TrustedRoot,
68}
69
70impl CacheKey {
71 pub fn as_str(&self) -> &'static str {
73 match self {
74 CacheKey::RekorPublicKey => "rekor_public_key",
75 CacheKey::RekorLogInfo => "rekor_log_info",
76 CacheKey::FulcioTrustBundle => "fulcio_trust_bundle",
77 CacheKey::FulcioConfiguration => "fulcio_configuration",
78 CacheKey::TrustedRoot => "trusted_root",
79 }
80 }
81
82 pub fn default_ttl(&self) -> Duration {
84 match self {
85 CacheKey::RekorPublicKey => Duration::from_secs(24 * 60 * 60), CacheKey::FulcioTrustBundle => Duration::from_secs(24 * 60 * 60), CacheKey::TrustedRoot => Duration::from_secs(24 * 60 * 60), CacheKey::FulcioConfiguration => Duration::from_secs(7 * 24 * 60 * 60), CacheKey::RekorLogInfo => Duration::from_secs(60 * 60), }
94 }
95}
96
97pub trait CacheAdapter: Send + Sync {
103 fn get(&self, key: CacheKey) -> CacheGetFuture<'_>;
109
110 fn set(&self, key: CacheKey, value: &[u8], ttl: Duration) -> CacheOpFuture<'_>;
114
115 fn remove(&self, key: CacheKey) -> CacheOpFuture<'_>;
117
118 fn clear(&self) -> CacheOpFuture<'_>;
120}
121
122pub trait CacheAdapterExt: CacheAdapter {
124 fn get_or_set<'a, F, Fut>(
126 &'a self,
127 key: CacheKey,
128 ttl: Duration,
129 compute: F,
130 ) -> Pin<Box<dyn Future<Output = Result<Vec<u8>>> + Send + 'a>>
131 where
132 F: FnOnce() -> Fut + Send + 'a,
133 Fut: Future<Output = Result<Vec<u8>>> + Send + 'a,
134 {
135 Box::pin(async move {
136 if let Some(cached) = self.get(key).await? {
138 return Ok(cached);
139 }
140
141 let value = compute().await?;
143
144 let _ = self.set(key, &value, ttl).await;
146
147 Ok(value)
148 })
149 }
150
151 fn get_or_set_default<'a, F, Fut>(
153 &'a self,
154 key: CacheKey,
155 compute: F,
156 ) -> Pin<Box<dyn Future<Output = Result<Vec<u8>>> + Send + 'a>>
157 where
158 F: FnOnce() -> Fut + Send + 'a,
159 Fut: Future<Output = Result<Vec<u8>>> + Send + 'a,
160 {
161 self.get_or_set(key, key.default_ttl(), compute)
162 }
163}
164
165impl<T: CacheAdapter + ?Sized> CacheAdapterExt for T {}
167
168impl<T: CacheAdapter + ?Sized> CacheAdapter for Arc<T> {
170 fn get(&self, key: CacheKey) -> CacheGetFuture<'_> {
171 (**self).get(key)
172 }
173
174 fn set(&self, key: CacheKey, value: &[u8], ttl: Duration) -> CacheOpFuture<'_> {
175 (**self).set(key, value, ttl)
176 }
177
178 fn remove(&self, key: CacheKey) -> CacheOpFuture<'_> {
179 (**self).remove(key)
180 }
181
182 fn clear(&self) -> CacheOpFuture<'_> {
183 (**self).clear()
184 }
185}
186
187impl CacheAdapter for Box<dyn CacheAdapter> {
189 fn get(&self, key: CacheKey) -> CacheGetFuture<'_> {
190 (**self).get(key)
191 }
192
193 fn set(&self, key: CacheKey, value: &[u8], ttl: Duration) -> CacheOpFuture<'_> {
194 (**self).set(key, value, ttl)
195 }
196
197 fn remove(&self, key: CacheKey) -> CacheOpFuture<'_> {
198 (**self).remove(key)
199 }
200
201 fn clear(&self) -> CacheOpFuture<'_> {
202 (**self).clear()
203 }
204}
205
206pub fn default_cache_dir() -> Result<std::path::PathBuf> {
213 let project_dirs = directories::ProjectDirs::from("dev", "sigstore", "sigstore-rust")
214 .ok_or_else(|| Error::Io("Could not determine cache directory".into()))?;
215 Ok(project_dirs.cache_dir().to_path_buf())
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221
222 #[test]
223 fn test_cache_key_as_str() {
224 assert_eq!(CacheKey::RekorPublicKey.as_str(), "rekor_public_key");
225 assert_eq!(CacheKey::FulcioTrustBundle.as_str(), "fulcio_trust_bundle");
226 }
227
228 #[test]
229 fn test_cache_key_default_ttl() {
230 assert!(CacheKey::RekorPublicKey.default_ttl().as_secs() > 0);
232 assert!(CacheKey::FulcioConfiguration.default_ttl().as_secs() > 0);
233 }
234}