From 039a47db044d44c9828520885853f2ea2dc3cfa6 Mon Sep 17 00:00:00 2001 From: Michael Lieberman Date: Fri, 12 Apr 2024 04:40:53 +0000 Subject: [PATCH] Fix get output to support new abstractions This changes some of the stuff around to push the actual functionality into the right abstractions so eventually this will be more extensible. There is an issue #75 where it's unclear how we can download the release asset via the API, making downoading assets from private repos impossible right now. --- Cargo.lock | 264 +++++++++++++++++++++++---- skootrs-bin/src/helpers.rs | 138 ++++++-------- skootrs-lib/Cargo.toml | 1 + skootrs-lib/src/service/output.rs | 60 +++++- skootrs-lib/src/service/project.rs | 33 +++- skootrs-lib/templates/goreleaser.yml | 2 +- skootrs-model/src/skootrs/mod.rs | 21 ++- 7 files changed, 380 insertions(+), 139 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84432e5..552338e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,7 +30,7 @@ dependencies = [ "actix-service", "actix-utils", "ahash", - "base64", + "base64 0.21.7", "bitflags 2.4.1", "brotli", "bytes", @@ -39,8 +39,8 @@ dependencies = [ "encoding_rs", "flate2", "futures-core", - "h2", - "http", + "h2 0.3.22", + "http 0.2.11", "httparse", "httpdate", "itoa", @@ -75,7 +75,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d22475596539443685426b6bdadb926ad0ecaefdfc5fb05e5e3441f15463c511" dependencies = [ "bytestring", - "http", + "http 0.2.11", "regex", "serde", "tracing", @@ -384,6 +384,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" + [[package]] name = "basic-toml" version = "0.1.9" @@ -961,7 +967,26 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.11", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "816ec7294445779408f36fe57bc5b7fc1cf59664059096c65f905c1c61f58069" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 1.1.0", "indexmap", "slab", "tokio", @@ -1007,6 +1032,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.5" @@ -1014,7 +1050,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", - "http", + "http 0.2.11", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +dependencies = [ + "bytes", + "futures-core", + "http 1.1.0", + "http-body 1.0.0", "pin-project-lite", ] @@ -1055,9 +1114,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.3.22", + "http 0.2.11", + "http-body 0.4.5", "httparse", "httpdate", "itoa", @@ -1069,6 +1128,26 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.4", + "http 1.1.0", + "http-body 1.0.0", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "hyper-rustls" version = "0.24.2" @@ -1076,8 +1155,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http", - "hyper", + "http 0.2.11", + "hyper 0.14.27", "log", "rustls", "rustls-native-certs", @@ -1091,7 +1170,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper", + "hyper 0.14.27", "pin-project-lite", "tokio", "tokio-io-timeout", @@ -1104,10 +1183,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper", + "hyper 0.14.27", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.2.0", + "hyper-util", "native-tls", "tokio", "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "hyper 1.2.0", + "pin-project-lite", + "socket2 0.5.5", + "tokio", + "tower", + "tower-service", + "tracing", ] [[package]] @@ -1233,7 +1348,7 @@ version = "9.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c7ea04a7c5c055c175f189b6dc6ba036fd62306b58c66c9f6389036c503a3f4" dependencies = [ - "base64", + "base64 0.21.7", "js-sys", "pem", "ring 0.17.6", @@ -1484,16 +1599,16 @@ checksum = "abfeeafb5fa0da7046229ec3c7b3bd2981aae05c549871192c408d59fc0fffd5" dependencies = [ "arc-swap", "async-trait", - "base64", + "base64 0.21.7", "bytes", "cfg-if", "chrono", "either", "futures", "futures-util", - "http", - "http-body", - "hyper", + "http 0.2.11", + "http-body 0.4.5", + "hyper 0.14.27", "hyper-rustls", "hyper-timeout", "jsonwebtoken", @@ -1521,16 +1636,16 @@ checksum = "054a8bf47dfa8f89bb0dcf17e485e9f49f2586c05bf0aa67b8ec5a9e7bc8dfd5" dependencies = [ "arc-swap", "async-trait", - "base64", + "base64 0.21.7", "bytes", "cfg-if", "chrono", "either", "futures", "futures-util", - "http", - "http-body", - "hyper", + "http 0.2.11", + "http-body 0.4.5", + "hyper 0.14.27", "hyper-rustls", "hyper-timeout", "jsonwebtoken", @@ -1728,7 +1843,7 @@ version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3163d2912b7c3b52d651a055f2c7eec9ba5cd22d26ef75b8dd3a59980b185923" dependencies = [ - "base64", + "base64 0.21.7", "serde", ] @@ -1986,16 +2101,58 @@ version = "0.11.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" dependencies = [ - "base64", + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.22", + "http 0.2.11", + "http-body 0.4.5", + "hyper 0.14.27", + "hyper-tls 0.5.0", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile 1.0.4", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg 0.50.0", +] + +[[package]] +name = "reqwest" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e6cc1e89e689536eb5aeede61520e874df5a4707df811cd5da4aa5fbb2aae19" +dependencies = [ + "base64 0.22.0", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", + "h2 0.4.4", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.2.0", + "hyper-tls 0.6.0", + "hyper-util", "ipnet", "js-sys", "log", @@ -2004,7 +2161,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", + "rustls-pemfile 2.1.2", "serde", "serde_json", "serde_urlencoded", @@ -2017,7 +2174,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg", + "winreg 0.52.0", ] [[package]] @@ -2137,7 +2294,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "schannel", "security-framework", ] @@ -2148,9 +2305,25 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64", + "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.0", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -2434,7 +2607,7 @@ dependencies = [ name = "skootrs-bin" version = "0.1.0" dependencies = [ - "base64", + "base64 0.21.7", "clap", "clap_mangen", "clio", @@ -2443,7 +2616,7 @@ dependencies = [ "opentelemetry", "opentelemetry-jaeger", "opentelemetry_sdk", - "reqwest", + "reqwest 0.11.24", "serde", "serde_json", "serde_yaml", @@ -2464,10 +2637,11 @@ name = "skootrs-lib" version = "0.1.0" dependencies = [ "askama", - "base64", + "base64 0.21.7", "chrono", "futures", "octocrab 0.33.3", + "reqwest 0.12.3", "schemars", "serde", "serde_json", @@ -2533,9 +2707,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.2" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "snafu" @@ -2901,8 +3075,8 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http", - "http-body", + "http 0.2.11", + "http-body 0.4.5", "http-range-header", "iri-string", "pin-project-lite", @@ -3584,6 +3758,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "zerocopy" version = "0.7.32" diff --git a/skootrs-bin/src/helpers.rs b/skootrs-bin/src/helpers.rs index 4d083f6..c0b03b9 100644 --- a/skootrs-bin/src/helpers.rs +++ b/skootrs-bin/src/helpers.rs @@ -1,19 +1,19 @@ -use base64::prelude::*; use inquire::Text; use octocrab::Page; use serde::Serialize; use skootrs_lib::service::{project::ProjectService, source::LocalSourceService}; -use skootrs_model::{ - security_insights::insights10::SecurityInsightsVersion100YamlSchema, - skootrs::{ - facet::InitializedFacet, Config, EcosystemInitializeParams, FacetGetParams, FacetMapKey, - GithubRepoParams, GithubUser, GoParams, InitializedProject, MavenParams, - ProjectArchiveParams, ProjectCreateParams, ProjectGetParams, ProjectOutputParams, - ProjectOutputReference, ProjectOutputType, ProjectOutputsListParams, ProjectReleaseParam, - RepoCreateParams, SkootError, SourceInitializeParams, SupportedEcosystems, - }, +use skootrs_model::skootrs::{ + facet::InitializedFacet, Config, EcosystemInitializeParams, FacetGetParams, FacetMapKey, + GithubRepoParams, GithubUser, GoParams, InitializedProject, MavenParams, ProjectArchiveParams, + ProjectCreateParams, ProjectGetParams, ProjectOutput, ProjectOutputGetParams, + ProjectOutputReference, ProjectOutputType, ProjectOutputsListParams, ProjectReleaseParam, + RepoCreateParams, SkootError, SourceInitializeParams, SupportedEcosystems, +}; +use std::{ + collections::{HashMap, HashSet}, + io::Write, + str::FromStr, }; -use std::{collections::HashSet, io::Write, str::FromStr}; use strum::VariantNames; use tracing::debug; @@ -280,18 +280,15 @@ impl Output { /// Returns an error if the project output can't be fetched from a project release. pub async fn get<'a, T: ProjectService + ?Sized>( config: &Config, - _project_service: &'a T, - project_output_params: Option, - ) -> Result { + project_service: &'a T, + project_output_params: Option, + ) -> Result { let project_output_params = match project_output_params { Some(p) => p, - None => Output::prompt_project_output(config).await?, + None => Output::prompt_output_get(config, project_service).await?, }; - let output = reqwest::get(project_output_params.project_output) - .await? - .text() - .await?; + let output = project_service.output_get(project_output_params).await?; Ok(output) } @@ -319,71 +316,48 @@ impl Output { Ok(output_list) } - async fn prompt_project_output(config: &Config) -> Result { - let projects = Project::list(config).await?; - let selected_project = - inquire::Select::new("Select a project", projects.iter().collect()).prompt()?; - let selected_output_type = - inquire::Select::new("Select an output type", vec!["SBOM"]).prompt()?; - // TODO: This should probably be passed in by the config? - let mut cache = InMemoryProjectReferenceCache::load_or_create("./skootcache")?; - let project = cache.get(selected_project.clone()).await?; - - let selected_output = match selected_output_type { - "SBOM" => { - let skootrs_model::skootrs::InitializedRepo::Github(repo) = &project.repo; - let sec_ins_content_items = octocrab::instance() - .repos(repo.organization.get_name(), &repo.name) - .get_content() - .path("SECURITY-INSIGHTS.yml") - .r#ref("main") - .send() - .await?; - - let sec_ins = sec_ins_content_items - .items - .first() - .ok_or_else(|| SkootError::from("Failed to get security insights"))?; - - let content = sec_ins.content.as_ref().ok_or_else(|| { - SkootError::from("Failed to get content of security insights") - })?; - let content_decoded = - base64::engine::general_purpose::STANDARD.decode(content.replace('\n', ""))?; - let content_str = std::str::from_utf8(&content_decoded)?; - let insights: SecurityInsightsVersion100YamlSchema = - serde_yaml::from_str::(content_str)?; - let sbom_vec = insights - .dependencies - .ok_or_else(|| { - SkootError::from("Failed to get dependencies value from security insights") - })? - .sbom - .ok_or_else(|| { - SkootError::from("Failed to get sbom value from security insights") - })?; - - let sbom_files: Vec = sbom_vec - .iter() - .filter_map(|s| s.sbom_file.clone()) - .collect(); - - inquire::Select::new("Select an SBOM", sbom_files).prompt()? - } - _ => { - unimplemented!() - } - }; - - let selected_output_type_enum = match selected_output_type { - "SBOM" => ProjectOutputType::SBOM, - _ => ProjectOutputType::Custom("Other".to_string()), + async fn prompt_output_get<'a, T: ProjectService + ?Sized>( + config: &Config, + project_service: &'a T, + ) -> Result { + let selected_project = Project::get(config, project_service, None).await?; + let project_output_list_params = ProjectOutputsListParams { + initialized_project: selected_project.clone(), + // TODO: This should be a prompt. + release: ProjectReleaseParam::Latest, }; - - Ok(ProjectOutputParams { - project_url: selected_project.clone(), - project_output_type: selected_output_type_enum, + let output_list = + Output::list(config, project_service, Some(project_output_list_params)).await?; + let type_output_map: HashMap> = output_list + .iter() + .map(|o| (o.output_type.to_string(), o.name.clone())) + .fold( + HashMap::new(), + |mut acc: HashMap>, (key, value)| { + acc.entry(key).or_default().push(value); + acc + }, + ); + let selected_output_type = inquire::Select::new( + "Select an output type", + type_output_map.keys().cloned().collect(), + ) + .prompt()?; + let select_output_type_enum = ProjectOutputType::from_str(&selected_output_type)?; + let selected_output = inquire::Select::new( + "Select an output", + type_output_map + .get(&selected_output_type) + .ok_or_else(|| SkootError::from("Failed to get output type"))? + .clone(), + ) + .prompt()?; + Ok(ProjectOutputGetParams { + initialized_project: selected_project.clone(), + project_output_type: select_output_type_enum, project_output: selected_output.clone(), + // TODO: This should be selectable + release: ProjectReleaseParam::Latest, }) } } diff --git a/skootrs-lib/Cargo.toml b/skootrs-lib/Cargo.toml index d15b14b..efb74bb 100644 --- a/skootrs-lib/Cargo.toml +++ b/skootrs-lib/Cargo.toml @@ -20,6 +20,7 @@ skootrs-model = { path = "../skootrs-model" } sha2 = "0.10.8" url = "2.5.0" base64 = "0.21.7" +reqwest = "0.12.3" [dev-dependencies] tempdir = "0.3.7" diff --git a/skootrs-lib/src/service/output.rs b/skootrs-lib/src/service/output.rs index b0b0839..3ad6f41 100644 --- a/skootrs-lib/src/service/output.rs +++ b/skootrs-lib/src/service/output.rs @@ -17,20 +17,25 @@ use octocrab::models::repos::{Asset, Release}; use skootrs_model::skootrs::{ - ProjectOutputReference, ProjectOutputType, ProjectOutputsListParams, SkootError, + ProjectOutput, ProjectOutputGetParams, ProjectOutputReference, ProjectOutputType, + ProjectOutputsListParams, SkootError, }; - pub trait OutputService { - fn outputs_list( + fn list( &self, params: ProjectOutputsListParams, ) -> impl std::future::Future, SkootError>> + Send; + + fn get( + &self, + _params: ProjectOutputGetParams, + ) -> impl std::future::Future> + Send; } pub struct LocalOutputService; impl OutputService for LocalOutputService { - fn outputs_list( + fn list( &self, params: ProjectOutputsListParams, ) -> impl std::future::Future, SkootError>> + Send @@ -46,6 +51,23 @@ impl OutputService for LocalOutputService { } } } + + async fn get(&self, params: ProjectOutputGetParams) -> Result { + match params.initialized_project.repo { + skootrs_model::skootrs::InitializedRepo::Github(g) => { + let github_params = GithubOutputGetParams { + release: GithubReleaseHandler::get_release(GithubReleaseParams { + owner: g.organization.get_name(), + repo: g.name.clone(), + tag: params.release.tag(), + }) + .await?, + name: params.project_output, + }; + GithubReleaseHandler::get_output(github_params).await + } + } + } } struct GithubReleaseHandler; @@ -92,10 +114,35 @@ impl GithubReleaseHandler { // Follows: https://github.com/ossf/sbom-everywhere/blob/main/reference/sbom_naming.md _ if asset.name.contains(".spdx.") => ProjectOutputType::SBOM, _ if asset.name.contains(".cdx.") => ProjectOutputType::SBOM, + _ if asset.name.contains(".intoto.") => ProjectOutputType::InToto, // TODO: Add more types _ => ProjectOutputType::Custom("Unknown".to_string()), } } + + async fn get_output(params: GithubOutputGetParams) -> Result { + let asset = params + .release + .assets + .iter() + .find(|a| a.name == params.name) + .ok_or("Asset not found".to_string())?; + + // TODO: Figure out how to support assets in private repos + let content = reqwest::get(asset.browser_download_url.clone()) + .await + .map_err(|e| e.to_string())? + .text() + .await?; + + Ok(ProjectOutput { + reference: ProjectOutputReference { + name: asset.name.clone(), + output_type: Self::get_type(asset), + }, + output: serde_json::to_string_pretty(&content)?, + }) + } } struct GithubReleaseParams { @@ -103,3 +150,8 @@ struct GithubReleaseParams { repo: String, tag: Option, } + +struct GithubOutputGetParams { + release: Release, + name: String, +} diff --git a/skootrs-lib/src/service/project.rs b/skootrs-lib/src/service/project.rs index 7129d3a..0ef2ec7 100644 --- a/skootrs-lib/src/service/project.rs +++ b/skootrs-lib/src/service/project.rs @@ -22,8 +22,8 @@ use crate::service::facet::{FacetSetParamsGenerator, RootFacetService}; use skootrs_model::skootrs::{ facet::{CommonFacetCreateParams, InitializedFacet, SourceFile}, FacetGetParams, FacetMapKey, InitializedProject, InitializedSource, ProjectArchiveParams, - ProjectCreateParams, ProjectGetParams, ProjectOutputReference, ProjectOutputsListParams, - SkootError, + ProjectCreateParams, ProjectGetParams, ProjectOutput, ProjectOutputGetParams, + ProjectOutputReference, ProjectOutputsListParams, SkootError, }; use super::{ @@ -83,6 +83,11 @@ pub trait ProjectService { params: ProjectOutputsListParams, ) -> impl std::future::Future, SkootError>> + Send; + fn output_get( + &self, + _params: ProjectOutputGetParams, + ) -> impl std::future::Future> + Send; + /// Archives an initialized project. /// /// # Errors @@ -255,13 +260,20 @@ where &self, params: ProjectOutputsListParams, ) -> Result, SkootError> { - self.output_service.outputs_list(params).await + self.output_service.list(params).await } async fn list_facets(&self, params: ProjectGetParams) -> Result, SkootError> { Ok(self.get(params).await?.facets.keys().cloned().collect()) } + async fn output_get( + &self, + params: ProjectOutputGetParams, + ) -> Result { + self.output_service.get(params).await + } + async fn archive(&self, params: ProjectArchiveParams) -> Result { self.repo_service .archive(params.initialized_project.repo) @@ -539,7 +551,7 @@ mod tests { } impl OutputService for MockOutputService { - async fn outputs_list( + async fn list( &self, _params: ProjectOutputsListParams, ) -> Result, SkootError> { @@ -548,6 +560,19 @@ mod tests { output_type: ProjectOutputType::SBOM, }]) } + + async fn get( + &self, + _params: skootrs_model::skootrs::ProjectOutputGetParams, + ) -> Result { + Ok(skootrs_model::skootrs::ProjectOutput { + reference: ProjectOutputReference { + name: "test".into(), + output_type: ProjectOutputType::SBOM, + }, + output: "test".into(), + }) + } } #[tokio::test] diff --git a/skootrs-lib/templates/goreleaser.yml b/skootrs-lib/templates/goreleaser.yml index 6ad6b3b..59423b9 100644 --- a/skootrs-lib/templates/goreleaser.yml +++ b/skootrs-lib/templates/goreleaser.yml @@ -91,7 +91,7 @@ sboms: - id: bins cmd: trivy args: ["fs", ".", "--format", "spdx-json", "--output", "${artifact}.spdx.sbom.json"] - artifacts: any + artifacts: binary documents: - "${artifact}.spdx.sbom.json" diff --git a/skootrs-model/src/skootrs/mod.rs b/skootrs-model/src/skootrs/mod.rs index 995e226..64e8d75 100644 --- a/skootrs-model/src/skootrs/mod.rs +++ b/skootrs-model/src/skootrs/mod.rs @@ -18,7 +18,7 @@ pub mod facet; use std::{collections::HashMap, error::Error, fmt, str::FromStr}; use serde::{Deserialize, Serialize}; -use strum::{EnumString, VariantNames}; +use strum::{Display, EnumString, VariantNames}; use url::Host; use utoipa::ToSchema; @@ -184,14 +184,16 @@ impl ProjectReleaseParam { /// The paramaters for getting the output of a project, e.g. an SBOM from a release #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] -pub struct ProjectOutputParams { - /// The URL of the Skootrs project to get the output from. - pub project_url: String, - /// The type of output to get from the project. +pub struct ProjectOutputGetParams { + /// The initialized project to get the output from. + pub initialized_project: InitializedProject, + /// The type of output, e.g. SBOM, to get from the project. pub project_output_type: ProjectOutputType, // TODO: Should project_output be a part of the ProjectOutputType enum? /// The output to get from the project. pub project_output: String, + /// The release to get the output from. + pub release: ProjectReleaseParam, } /// The parameters for archiving a project. @@ -203,12 +205,15 @@ pub struct ProjectArchiveParams { } /// The set of supported output types -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(Serialize, Deserialize, Clone, Debug, EnumString, VariantNames, Default, Display)] #[cfg_attr(feature = "openapi", derive(ToSchema))] pub enum ProjectOutputType { - /// An output type for getting an SBOM from a project. + #[default] + /// An output type for an SBOM from a project. SBOM, - /// An output type for getting a custom output from a project. + /// An output type for an in-toto attestation from a project. + InToto, + /// An output type for a custom output from a project. Custom(String), }