mkit_server/scanner_retrieval/
service.rs1use crate::ServerError;
2use crate::pipeline::PipelineConfig;
3use bytes::Bytes;
4
5#[derive(Debug)]
7pub struct RetrievalResponse {
8 pub bytes: Bytes,
10 pub start: u64,
12 pub total: u64,
14 pub partial: bool,
16}
17
18pub(crate) fn missing() -> ServerError {
19 ServerError::not_found("pack not found")
20}
21
22pub fn validate_config(cfg: &PipelineConfig) -> Result<(), ServerError> {
28 let Some(config) = &cfg.scanner_retrieval else {
29 return Ok(());
30 };
31 if !cfg!(feature = "remote-hooks")
32 || !matches!(cfg.auth, crate::pipeline::AuthMode::AuthV2(_))
33 || cfg.indexed.is_none()
34 || cfg.ticket_keys.is_none()
35 || cfg.begin_upload_threshold_bytes != 0
36 || cfg.write_policy == crate::policy::WritePolicy::Open
37 {
38 return Err(ServerError::invalid_argument(
39 "scanner retrieval requires ticketed indexed inspection and auth v2",
40 ));
41 }
42 let mut public = cfg.admin_keys.clone();
43 if let Some(tokens) = &cfg.url_tokens {
44 public.extend(tokens.keys().public_keys());
45 }
46 if let Some(fence) = &cfg.authority_fence {
47 public.extend(fence.public_keys());
48 }
49 let namespaces: Vec<_> = match &cfg.addressing {
50 crate::Addressing::Single { repo } => vec![repo.namespace.as_str().to_owned()],
51 crate::Addressing::Multi(multi) => match &multi.namespace_policy {
52 crate::policy::NamespacePolicy::Allowlist(list) => {
53 list.iter().map(ToString::to_string).collect()
54 }
55 _ => Vec::new(),
56 },
57 };
58 for namespace in namespaces {
59 if let Ok(mkit_core::repo_identity::Namespace::Ed25519(key)) =
60 mkit_core::repo_identity::Namespace::parse(&namespace)
61 {
62 public.push(key);
63 }
64 }
65 config.check_role_keys(&public, &[]).map_err(|_| {
66 ServerError::invalid_argument("scanner retrieval key roles must be distinct")
67 })?;
68 if let Some(tokens) = &cfg.url_tokens
69 && (config.keys.iter().any(|key| {
70 tokens.keys().contains_secret(&key.secret)
71 || tokens.keys().contains_secret(
72 &ed25519_dalek::SigningKey::from_bytes(&key.secret)
73 .verifying_key()
74 .to_bytes(),
75 )
76 }) || config
77 .scanner_keys()
78 .any(|key| tokens.keys().contains_secret(&key)))
79 {
80 return Err(ServerError::invalid_argument(
81 "scanner retrieval and URL token key roles must be distinct",
82 ));
83 }
84 if let Some(tickets) = &cfg.ticket_keys
85 && (config.keys.iter().any(|key| {
86 tickets.contains_secret(&key.secret)
87 || tickets.contains_ed25519_public(&key.secret)
88 || tickets.contains_secret(
89 &ed25519_dalek::SigningKey::from_bytes(&key.secret)
90 .verifying_key()
91 .to_bytes(),
92 )
93 || tickets.contains_ed25519_public(
94 &ed25519_dalek::SigningKey::from_bytes(&key.secret)
95 .verifying_key()
96 .to_bytes(),
97 )
98 }) || config
99 .scanner_keys()
100 .any(|key| tickets.contains_secret(&key) || tickets.contains_ed25519_public(&key)))
101 {
102 return Err(ServerError::invalid_argument(
103 "scanner retrieval and ticket key roles must be distinct",
104 ));
105 }
106 Ok(())
107}