sbom_walker/source/
mod.rs1mod dispatch;
4mod file;
5mod http;
6
7pub use self::http::*;
8pub use dispatch::*;
9pub use file::*;
10
11use crate::{
12 discover::{DiscoverConfig, DiscoveredSbom},
13 model::metadata::SourceMetadata,
14 retrieve::RetrievedSbom,
15};
16use anyhow::bail;
17use fluent_uri::UriRef;
18use std::{fmt::Debug, future::Future};
19use url::Url;
20use walker_common::fetcher::{Fetcher, FetcherOptions};
21
22pub trait Source: walker_common::source::Source + Clone + Debug {
24 fn load_metadata(&self) -> impl Future<Output = Result<SourceMetadata, Self::Error>>;
25 fn load_index(&self) -> impl Future<Output = Result<Vec<DiscoveredSbom>, Self::Error>>;
26 fn load_sbom(
27 &self,
28 sbom: DiscoveredSbom,
29 ) -> impl Future<Output = Result<RetrievedSbom, Self::Error>>;
30}
31
32pub async fn new_source(
33 discover: impl Into<DiscoverConfig>,
34 fetcher: impl Into<FetcherOptions>,
35) -> anyhow::Result<DispatchSource> {
36 let discover = discover.into();
37 let source = discover.source;
38
39 match UriRef::parse(source.as_str()) {
40 Ok(uri) => match uri.scheme().map(|s| s.as_str()) {
41 Some("file") => {
42 let source = uri.path().as_str();
43 log::debug!("Creating file source: {source}");
44 Ok(FileSource::new(source, FileOptions::new().since(discover.since))?.into())
45 }
46 Some(_scheme) => {
47 log::debug!("Creating HTTP source: {source}");
48 let fetcher = Fetcher::new(fetcher.into()).await?;
49 Ok(HttpSource::new(
50 Url::parse(&source)?,
51 fetcher,
52 HttpOptions::new().since(discover.since).keys(discover.keys),
53 )
54 .into())
55 }
56 None => {
57 bail!(
58 "Failed to parse '{source}' as URL. For SBOMs there is no domain-based lookup"
59 );
60 }
61 },
62 Err(err) => {
63 bail!(
64 "Failed to parse '{source}' as URL. For SBOMs there is no domain-based lookup: {err}"
65 );
66 }
67 }
68}
69
70#[cfg(test)]
71mod test {
72 use crate::discover::DiscoverConfig;
73 use crate::source::new_source;
74 use walker_common::fetcher::FetcherOptions;
75
76 #[tokio::test]
77 pub async fn test_file_source() {
78 let result = new_source(
79 DiscoverConfig {
80 source: "file:/".to_string(),
81 since: None,
82 keys: vec![],
83 },
84 FetcherOptions::default(),
85 )
86 .await;
87
88 assert!(result.is_ok());
89 }
90
91 #[tokio::test]
92 pub async fn test_http_source() {
93 let result = new_source(
94 DiscoverConfig {
95 source: "https://foo.bar/baz".to_string(),
96 since: None,
97 keys: vec![],
98 },
99 FetcherOptions::default(),
100 )
101 .await;
102
103 assert!(result.is_ok());
104 }
105
106 #[tokio::test]
107 pub async fn test_invalid_source() {
108 let result = new_source(
109 DiscoverConfig {
110 source: "/var/files".to_string(),
111 since: None,
112 keys: vec![],
113 },
114 FetcherOptions::default(),
115 )
116 .await;
117
118 assert!(result.is_err());
119 }
120}