diff --git a/.gitignore b/.gitignore index f0135e5..56485de 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ .vscode .DS_Store state.db -.envrc \ No newline at end of file +.envrc +skootcache \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 0576fe6..f4e4717 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3764,9 +3764,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.112" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d1bd37ce2324cf3bf85e5a25f96eb4baf0d5aa6eba43e7ae8958870c4ec48ed" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "indexmap 2.2.3", "itoa", @@ -3969,6 +3969,7 @@ dependencies = [ "skootrs-model", "skootrs-rest", "skootrs-statestore", + "strum", "tokio", "tracing", "tracing-bunyan-formatter", @@ -3982,6 +3983,7 @@ version = "0.1.0" dependencies = [ "ahash 0.8.7", "askama", + "base64", "chrono", "futures", "octocrab 0.33.3", @@ -3990,10 +3992,12 @@ dependencies = [ "serde", "serde_json", "serde_yaml", + "sha2", "skootrs-model", "tempdir", "tokio", "tracing", + "url", "utoipa", ] @@ -4007,6 +4011,9 @@ dependencies = [ "serde", "serde_json", "serde_yaml", + "sha2", + "strum", + "url", "utoipa", ] @@ -4036,6 +4043,7 @@ dependencies = [ name = "skootrs-statestore" version = "0.1.0" dependencies = [ + "serde_json", "skootrs-lib", "skootrs-model", "surrealdb", @@ -4201,6 +4209,28 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "723b93e8addf9aa965ebe2d11da6d7540fa2283fcea14b3371ff055f7ba13f5f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a3417fc93d76740d974a01654a09777cb500428cc874ca9f45edfe0c4d4cd18" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.48", +] + [[package]] name = "subtle" version = "2.5.0" diff --git a/Cargo.toml b/Cargo.toml index a530539..0fe1137 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ resolver = "2" [workspace.lints.rust] unsafe_code = "forbid" +missing_docs = "warn" [workspace.lints.clippy] enum_glob_use = "deny" @@ -17,4 +18,4 @@ pedantic = "deny" nursery = "deny" unwrap_used = "deny" missing_errors_doc = "allow" -module_name_repetitions = "allow" +module_name_repetitions = "allow" \ No newline at end of file diff --git a/skootrs-bin/Cargo.toml b/skootrs-bin/Cargo.toml index d6546d2..db7f73b 100644 --- a/skootrs-bin/Cargo.toml +++ b/skootrs-bin/Cargo.toml @@ -3,6 +3,10 @@ name = "skootrs-bin" version = "0.1.0" edition = "2021" +[[bin]] +name = "skootrs" +path = "src/main.rs" + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] @@ -27,6 +31,7 @@ reqwest = "0.11.24" base64 = "0.21.7" clio = { version = "0.3.5", features = ["clap", "clap-parse"] } serde = "1.0.197" +strum = "0.26.1" [build-dependencies] clap_mangen = "0.2.20" diff --git a/skootrs-bin/src/helpers.rs b/skootrs-bin/src/helpers.rs index 7a6302e..cf4f997 100644 --- a/skootrs-bin/src/helpers.rs +++ b/skootrs-bin/src/helpers.rs @@ -6,20 +6,30 @@ use skootrs_lib::service::{ facet::LocalFacetService, project::{LocalProjectService, ProjectService}, repo::LocalRepoService, - source::{LocalSourceService, SourceService}, + source::LocalSourceService, }; use skootrs_model::{ security_insights::insights10::SecurityInsightsVersion100YamlSchema, skootrs::{ - EcosystemParams, GithubRepoParams, GithubUser, GoParams, InitializedProject, MavenParams, - ProjectParams, RepoParams, SkootError, SkootrsConfig, SourceParams, SUPPORTED_ECOSYSTEMS, + Config, EcosystemInitializeParams, FacetGetParams, FacetMapKey, GithubRepoParams, + GithubUser, GoParams, InitializedProject, MavenParams, ProjectCreateParams, + ProjectGetParams, ProjectOutputParams, ProjectOutputType, RepoCreateParams, SkootError, + SourceInitializeParams, SupportedEcosystems, SUPPORTED_ECOSYSTEMS, }, }; -use std::collections::HashMap; +use std::{ + collections::{HashMap, HashSet}, + str::FromStr, +}; +use strum::VariantNames; +use tracing::debug; -use skootrs_model::skootrs::facet::InitializedFacet; use skootrs_statestore::SurrealProjectStateStore; +use skootrs_statestore::{ + GitProjectStateStore, InMemoryProjectReferenceCache, ProjectReferenceCache, ProjectStateStore, +}; +// TODO: This should have a project service member. pub struct Project; impl Project { @@ -28,27 +38,35 @@ impl Project { /// Creates a new skootrs project by prompting the user for repository details and language selection. /// The project can be created for either Go or Maven ecosystems right now. /// The project is created in Github, cloned down, and then initialized along with any other security supporting - /// tasks. If the project_params is not provided, the user will be prompted for the project details. + /// tasks. If the `project_params` is not provided, the user will be prompted for the project details. /// /// # Errors /// /// Returns an error if the user is not authenticated with Github, or if the project can't be created /// for any other reason. - pub async fn create( - config: &SkootrsConfig, - project_service: T, - project_params: Option, + pub async fn create<'a, T: ProjectService + ?Sized>( + config: &Config, + project_service: &'a T, + project_params: Option, ) -> Result<(), SkootError> { let project_params = match project_params { Some(p) => p, - None => Project::prompt_project(config).await?, + None => Project::prompt_create(config).await?, + }; + + let project = project_service.initialize(project_params).await?; + let git_state_store = GitProjectStateStore { + source: project.source.clone(), + source_service: LocalSourceService {}, }; - project_service.initialize(project_params).await?; + let mut local_cache = InMemoryProjectReferenceCache::load_or_create("./skootcache")?; + git_state_store.create(project.clone()).await?; + local_cache.set(project.repo.full_url()).await?; Ok(()) } - async fn prompt_project(config: &SkootrsConfig) -> Result { + async fn prompt_create(config: &Config) -> Result { let name = Text::new("The name of the repository").prompt()?; let description = Text::new("The description of the repository").prompt()?; let user = octocrab::instance().current().user().await?.login; @@ -66,41 +84,250 @@ impl Project { .collect(), ) .prompt()?; - let language = inquire::Select::new("Select a language", SUPPORTED_ECOSYSTEMS.to_vec()); + let language = + inquire::Select::new("Select a language", SupportedEcosystems::VARIANTS.to_vec()); let gh_org = match organization { x if x == user => GithubUser::User(x.to_string()), x => GithubUser::Organization(x.to_string()), }; - let repo_params = match language.prompt()? { - "Go" => RepoParams::Github(GithubRepoParams { + let language_prompt = language.prompt()?; + let ecosystem_params = match SupportedEcosystems::from_str(language_prompt)? { + SupportedEcosystems::Go => EcosystemInitializeParams::Go(GoParams { name: name.clone(), - description, - organization: gh_org, + host: format!("github.com/{organization}"), }), - "Maven" => RepoParams::Github(GithubRepoParams { - name: name.clone(), - description, - organization: gh_org, + // TODO: Unclear if this is the right way to handle Maven group and artifact. + SupportedEcosystems::Maven => EcosystemInitializeParams::Maven(MavenParams { + group_id: format!("com.{organization}.{name}"), + artifact_id: name.clone(), }), - _ => { - unreachable!("Unsupported language") - } }; - Ok(ProjectParams { + let repo_params = RepoCreateParams::Github(GithubRepoParams { + name: name.clone(), + description, + organization: gh_org, + }); + + Ok(ProjectCreateParams { name: name.clone(), repo_params, - ecosystem_params: EcosystemParams::Go(GoParams { - name: name.clone(), - host: format!("github.com/{organization}"), - }), - source_params: SourceParams { + ecosystem_params, + source_params: SourceInitializeParams { parent_path: config.local_project_path.clone(), }, }) } + + /// Fetches and prints out the contents of an `InitializedProject` in JSON format. + /// + /// # Errors + /// + /// Returns an error if the project can't be fetched for some reason. + pub async fn get<'a, T: ProjectService + ?Sized>( + config: &Config, + _project_service: &'a T, + project_get_params: Option, + ) -> Result { + let mut cache = InMemoryProjectReferenceCache::load_or_create("./skootcache")?; + let project_get_params = match project_get_params { + Some(p) => p, + None => Project::prompt_get(config).await?, + }; + let project = cache.get(project_get_params.project_url.clone()).await?; + println!("{}", serde_json::to_string(&project)?); + Ok(project) + } + + async fn prompt_get(_config: &Config) -> Result { + let projects = Project::list().await?; + let selected_project = + inquire::Select::new("Select a project", projects.iter().collect()).prompt()?; + Ok(ProjectGetParams { + project_url: selected_project.clone(), + }) + } + + async fn list() -> Result, SkootError> { + let cache = InMemoryProjectReferenceCache::load_or_create("./skootcache")?; + let projects: HashSet = cache.list().await?; + Ok(projects) + } + + /// Prints out the list of projects. + /// + /// # Errors + /// + /// Returns an error if the list of Skootrs projects can't be fetched for some reason. + pub async fn print_list() -> Result<(), SkootError> { + let projects = Project::list().await?; + println!("{}", serde_json::to_string(&projects)?); + Ok(()) + } +} + +pub struct Facet; + +impl Facet { + /// Prints out the content of a facet. This includes things like source files or API bundles. + /// + /// # Errors + /// + /// Returns an error if the facet content or project can't be fetched for some reason. + pub async fn get<'a, T: ProjectService + ?Sized>( + config: &Config, + project_service: &'a T, + facet_get_params: Option, + ) -> Result<(), SkootError> { + let facet_get_params = if let Some(p) = facet_get_params { + p + } else { + let project = Project::get(config, project_service, None).await?; + let facet_map_keys = project.facet_key_set(); + let fmk = Facet::prompt_get(config, facet_map_keys.into_iter().collect())?; + FacetGetParams { + project_url: project.repo.full_url(), + facet_map_key: fmk, + } + }; + + let facet_with_content = project_service + .get_facet_with_content(facet_get_params) + .await?; + + debug!("{:?}", facet_with_content); + println!("{}", serde_json::to_string(&facet_with_content)?); + + Ok(()) + } + + fn prompt_get( + _config: &Config, + facet_map_keys: Vec, + ) -> Result { + let facet_type = inquire::Select::new("Select a facet", facet_map_keys).prompt()?; + + Ok(facet_type) + } + + /// Prints out the list of facets for a project. This includes things like source files or API bundles. + /// + /// # Errors + /// + /// Returns an error if the project or list of facets can't be fetched for some reason. + pub async fn print_list<'a, T: ProjectService + ?Sized>( + config: &Config, + project_service: &'a T, + project_get_params: Option, + ) -> Result<(), SkootError> { + let project_get_params = match project_get_params { + Some(p) => p, + None => Project::prompt_get(config).await?, + }; + let project = project_service.get(project_get_params).await?; + let facet_map_keys = project.facet_key_set(); + println!("{}", serde_json::to_string(&facet_map_keys)?); + Ok(()) + } +} + +pub struct Output; + +impl Output { + /// Prints out the content of a project output. This includes things like SBOMs or SLSA attestations. + /// + /// # Errors + /// + /// 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<(), SkootError> { + let project_output_params = match project_output_params { + Some(p) => p, + None => Output::prompt_project_output(config).await?, + }; + + let output = reqwest::get(project_output_params.project_output) + .await? + .text() + .await?; + + println!("{output}"); + + Ok(()) + } + + async fn prompt_project_output(_config: &Config) -> Result { + let projects = Project::list().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()), + }; + + Ok(ProjectOutputParams { + project_url: selected_project.clone(), + project_output_type: selected_output_type_enum, + project_output: selected_output.clone(), + }) + } } /// Returns `Ok(())` if the project creation is successful, otherwise returns an error. @@ -147,15 +374,15 @@ pub async fn create() -> std::result::Result<(), SkootError> { name: name.clone(), host: format!("github.com/{organization}"), }; - let project_params = ProjectParams { + let project_params = ProjectCreateParams { name: name.clone(), - repo_params: RepoParams::Github(GithubRepoParams { + repo_params: RepoCreateParams::Github(GithubRepoParams { name, description, organization: gh_org, }), - ecosystem_params: EcosystemParams::Go(go_params), - source_params: SourceParams { + ecosystem_params: EcosystemInitializeParams::Go(go_params), + source_params: SourceInitializeParams { parent_path: "/tmp".to_string(), // FIXME: This should be configurable }, }; @@ -175,15 +402,15 @@ pub async fn create() -> std::result::Result<(), SkootError> { artifact_id: name.clone(), }; - let project_params = ProjectParams { + let project_params = ProjectCreateParams { name: name.clone(), - repo_params: RepoParams::Github(GithubRepoParams { + repo_params: RepoCreateParams::Github(GithubRepoParams { name, description, organization: gh_org, }), - ecosystem_params: EcosystemParams::Maven(maven_params), - source_params: SourceParams { + ecosystem_params: EcosystemInitializeParams::Maven(maven_params), + source_params: SourceInitializeParams { parent_path: "/tmp".to_string(), // FIXME: This should be configurable }, }; @@ -217,7 +444,7 @@ pub async fn create() -> std::result::Result<(), SkootError> { /// /// Returns an error if the state store is not able to be accessed or if the selected project or facet /// is not found. -pub async fn get_facet() -> std::result::Result<(), SkootError> { +/*pub async fn get_facet() -> std::result::Result<(), SkootError> { let project = prompt_project().await?; let facet_to_project: HashMap = project @@ -254,7 +481,7 @@ pub async fn get_facet() -> std::result::Result<(), SkootError> { println!("{facet_content}"); Ok(()) -} +}*/ /// Returns `Ok(())` if the able to print out a dump of the statestore. /// @@ -273,7 +500,7 @@ async fn get_all() -> std::result::Result, SkootError> { let projects = state_store.select_all().await?; Ok(projects) } - +/* fn get_facet_content( facet: &InitializedFacet, project: &InitializedProject, @@ -299,7 +526,7 @@ fn get_facet_content( Ok(content.join("\n")) } } -} +}*/ /// This function is for prompting the user to get outputs from a Skootrs project /// diff --git a/skootrs-bin/src/main.rs b/skootrs-bin/src/main.rs index c4ee09a..f424724 100644 --- a/skootrs-bin/src/main.rs +++ b/skootrs-bin/src/main.rs @@ -15,7 +15,7 @@ //! Tool for creating and managing secure-by-default projects. //! -//! This crate is for the binary that acts as the CLI which interacts +//! This crate is for the binary that acts as the CLI which interacts //! with the other crates in the Skootrs project. //! //! The CLI is built using the `clap` crate, and the commands are @@ -29,22 +29,22 @@ pub mod helpers; use clap::{Parser, Subcommand}; +use clio::Input; use skootrs_lib::service::ecosystem::LocalEcosystemService; use skootrs_lib::service::facet::LocalFacetService; use skootrs_lib::service::project::LocalProjectService; use skootrs_lib::service::repo::LocalRepoService; use skootrs_lib::service::source::LocalSourceService; use skootrs_model::skootrs::SkootError; -use clio::Input; -use helpers::{dump, get_facet, get_output}; +use helpers::{get_output, Facet, Output}; use opentelemetry::global; use opentelemetry_sdk::propagation::TraceContextPropagator; +use serde::de::DeserializeOwned; use tracing::error; use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer}; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::{EnvFilter, Registry}; -use serde::de::DeserializeOwned; /// Skootrs is a CLI tool for creating and managing secure-by-default projects. /// The commands are using noun-verb syntax. So the commands are structured like: @@ -99,7 +99,12 @@ enum ProjectCommands { }, /// Get the metadata for a particular project. #[command(name = "get")] - Get, + Get { + /// This is an optional input parameter that can be used to pass in a file, pipe, url, or stdin. + /// This is expected to be YAML or JSON. If it is not provided, the CLI will prompt the user for the input. + #[clap(value_parser)] + input: Option, + }, /// List all the projects known to the local Skootrs #[command(name = "list")] List, @@ -110,10 +115,20 @@ enum ProjectCommands { enum FacetCommands { /// Get the data for a facet of a particular project. #[command(name = "get")] - Get, + Get { + /// This is an optional input parameter that can be used to pass in a file, pipe, url, or stdin. + /// This is expected to be YAML or JSON. If it is not provided, the CLI will prompt the user for the input. + #[clap(value_parser)] + input: Option, + }, /// List all the facets that belong to a particular project. #[command(name = "list")] - List + List { + /// This is an optional input parameter that can be used to pass in a file, pipe, url, or stdin. + /// This is expected to be YAML or JSON. If it is not provided, the CLI will prompt the user for the input. + #[clap(value_parser)] + input: Option, + }, } /// This is the enum for what nouns the `output` command can take. @@ -121,10 +136,15 @@ enum FacetCommands { enum OutputCommands { /// Get the data for a release output of a particular project. #[command(name = "get")] - Get, + Get { + /// This is an optional input parameter that can be used to pass in a file, pipe, url, or stdin. + /// This is expected to be YAML or JSON. If it is not provided, the CLI will prompt the user for the input. + #[clap(value_parser)] + input: Option, + }, /// List all the release outputs that belong to a particular project. #[command(name = "list")] - List + List, } /// This is the enum for what nouns the `daemon` command can take. @@ -135,33 +155,6 @@ enum DaemonCommands { Start, } -/*enum SkootrsCli { - /// Create a new project. - #[command(name = "create")] - Create, - /// Start the REST server. - #[command(name = "daemon")] - Daemon, - /// Dump the current state of the projects database. - #[command(name = "dump")] - Dump, - /// Get the data for a facet of a particular project. - #[command(name = "get-facet")] - GetFacet, - - #[command(name = "get")] - Get { - #[clap(subcommand)] - resource: GetCommands, - }, -} - -/// This is the enum for what nouns the `get` command can take. -#[derive(Subcommand, Debug)] -enum GetCommands { - Output -}*/ - fn init_tracing() { let app_name = "skootrs"; @@ -197,16 +190,17 @@ fn init_project_service() -> LocalProjectService< LocalSourceService, LocalFacetService, > { - let project_service = LocalProjectService { + LocalProjectService { repo_service: LocalRepoService {}, ecosystem_service: LocalEcosystemService {}, source_service: LocalSourceService {}, facet_service: LocalFacetService {}, - }; - project_service + } } -fn parse_optional_input(input: Option) -> Result, SkootError> { +fn parse_optional_input( + input: Option, +) -> Result, SkootError> { match input { Some(input) => { // This should also support JSON since most modern YAML is a superset of JSON. @@ -214,7 +208,7 @@ fn parse_optional_input(input: Option) -> Result Ok(None) + None => Ok(None), } } @@ -231,68 +225,74 @@ async fn main() -> std::result::Result<(), SkootError> { let project_service = init_project_service(); // TODO: This should only default when it can't pull a valid config from the environment. - let config = skootrs_model::skootrs::SkootrsConfig::default(); + let config = skootrs_model::skootrs::Config::default(); match cli { - SkootrsCli::Project { project } => { - match project { - ProjectCommands::Create { input } => { - let project_params = parse_optional_input(input)?; - if let Err(ref error) = helpers::Project::create(&config, project_service, project_params).await { - error!(error = error.as_ref(), "Failed to create project"); - } + SkootrsCli::Project { project } => match project { + ProjectCommands::Create { input } => { + let project_create_params = parse_optional_input(input)?; + if let Err(ref error) = + helpers::Project::create(&config, &project_service, project_create_params).await + { + error!(error = error.as_ref(), "Failed to create project"); } - ProjectCommands::Get => { - if let Err(ref error) = dump().await { - error!(error = error.as_ref(), "Failed to get project info"); - } - } - ProjectCommands::List => { - if let Err(ref error) = dump().await { - error!(error = error.as_ref(), "Failed to list projects"); - } + } + ProjectCommands::Get { input } => { + let project_get_params = parse_optional_input(input)?; + if let Err(ref error) = + helpers::Project::get(&config, &project_service, project_get_params).await + { + error!(error = error.as_ref(), "Failed to get project info"); } } - } - SkootrsCli::Facet { facet } => { - match facet { - FacetCommands::Get => { - if let Err(ref error) = get_facet().await { - error!(error = error.as_ref(), "Failed to get facet"); - } + ProjectCommands::List => { + if let Err(ref error) = helpers::Project::print_list().await { + error!(error = error.as_ref(), "Failed to list projects"); } - FacetCommands::List => { - if let Err(ref error) = get_facet().await { - error!(error = error.as_ref(), "Failed to list facets for project"); - } + } + }, + SkootrsCli::Facet { facet } => match facet { + FacetCommands::Get { input } => { + let facet_get_params = parse_optional_input(input)?; + if let Err(ref error) = + Facet::get(&config, &project_service, facet_get_params).await + { + error!(error = error.as_ref(), "Failed to get facet"); } } - } - SkootrsCli::Output { output } => { - match output { - OutputCommands::Get => { - if let Err(ref error) = get_output().await { - error!(error = error.as_ref(), "Failed to get output"); - } + FacetCommands::List { input } => { + let project_get_params = parse_optional_input(input)?; + if let Err(ref error) = + Facet::print_list(&config, &project_service, project_get_params).await + { + error!(error = error.as_ref(), "Failed to list facets for project"); } - OutputCommands::List => { - if let Err(ref error) = get_output().await { - error!(error = error.as_ref(), "Failed to list outputs for project"); - } + } + }, + SkootrsCli::Output { output } => match output { + OutputCommands::Get { input } => { + let output_get_params = parse_optional_input(input)?; + if let Err(ref error) = + Output::get(&config, &project_service, output_get_params).await + { + error!(error = error.as_ref(), "Failed to get output"); } } - } - SkootrsCli::Daemon { daemon } => { - match daemon { - DaemonCommands::Start => { - tokio::task::spawn_blocking(|| { - skootrs_rest::server::rest::run_server().expect("Failed to start REST Server"); - }) - .await - .expect("REST Server Task Panicked"); + OutputCommands::List => { + if let Err(ref error) = get_output().await { + error!(error = error.as_ref(), "Failed to list outputs for project"); } } - } + }, + SkootrsCli::Daemon { daemon } => match daemon { + DaemonCommands::Start => { + tokio::task::spawn_blocking(|| { + skootrs_rest::server::rest::run_server().expect("Failed to start REST Server"); + }) + .await + .expect("REST Server Task Panicked"); + } + }, } Ok(()) diff --git a/skootrs-lib/Cargo.toml b/skootrs-lib/Cargo.toml index 9c2dfb2..99ac056 100644 --- a/skootrs-lib/Cargo.toml +++ b/skootrs-lib/Cargo.toml @@ -19,6 +19,9 @@ tracing = "0.1" futures = "0.3.30" skootrs-model = { path = "../skootrs-model" } ahash = "0.8.7" +sha2 = "0.10.8" +url = "2.5.0" +base64 = "0.21.7" [dev-dependencies] tempdir = "0.3.7" diff --git a/skootrs-lib/src/service/ecosystem.rs b/skootrs-lib/src/service/ecosystem.rs index 317a22f..4f8b394 100644 --- a/skootrs-lib/src/service/ecosystem.rs +++ b/skootrs-lib/src/service/ecosystem.rs @@ -5,7 +5,7 @@ use std::process::Command; use tracing::info; use skootrs_model::skootrs::{ - EcosystemParams, GoParams, InitializedEcosystem, InitializedGo, InitializedMaven, + EcosystemInitializeParams, GoParams, InitializedEcosystem, InitializedGo, InitializedMaven, InitializedSource, MavenParams, SkootError, }; @@ -20,7 +20,7 @@ pub trait EcosystemService { /// Returns an error if the ecosystem can't be initialized. fn initialize( &self, - params: EcosystemParams, + params: EcosystemInitializeParams, source: InitializedSource, ) -> Result; } @@ -33,18 +33,18 @@ pub struct LocalEcosystemService {} impl EcosystemService for LocalEcosystemService { fn initialize( &self, - params: EcosystemParams, + params: EcosystemInitializeParams, source: InitializedSource, ) -> Result { match params { - EcosystemParams::Maven(m) => { + EcosystemInitializeParams::Maven(m) => { LocalMavenEcosystemHandler::initialize(&source.path, &m)?; Ok(InitializedEcosystem::Maven(InitializedMaven { group_id: m.group_id, artifact_id: m.artifact_id, })) } - EcosystemParams::Go(g) => { + EcosystemInitializeParams::Go(g) => { LocalGoEcosystemHandler::initialize(&source.path, &g)?; Ok(InitializedEcosystem::Go(InitializedGo { name: g.name, diff --git a/skootrs-lib/src/service/facet.rs b/skootrs-lib/src/service/facet.rs index 4088b29..2dba523 100644 --- a/skootrs-lib/src/service/facet.rs +++ b/skootrs-lib/src/service/facet.rs @@ -21,7 +21,7 @@ #![allow(clippy::module_name_repetitions)] #![allow(clippy::unused_self)] -use std::{error::Error, str::FromStr}; +use std::str::FromStr; use askama::Template; use chrono::Datelike; @@ -34,7 +34,7 @@ use skootrs_model::{ }, skootrs::{ facet::{ - APIBundleFacet, APIBundleFacetParams, APIContent, CommonFacetParams, FacetParams, FacetSetParams, InitializedFacet, SourceBundleFacet, SourceBundleFacetParams, SourceFileContent, SourceFileFacet, SourceFileFacetParams, SupportedFacetType + APIBundleFacet, APIBundleFacetParams, APIContent, CommonFacetCreateParams, FacetCreateParams, FacetSetCreateParams, InitializedFacet, SourceBundleFacet, SourceBundleFacetCreateParams, SourceFile, SourceFileContent, SourceFileFacet, SourceFileFacetParams, SupportedFacetType }, InitializedEcosystem, InitializedGithubRepo, InitializedRepo, SkootError }, }; @@ -50,8 +50,8 @@ pub struct LocalFacetService {} /// This includes things like initializing and managing source files, source bundles, and API bundles. /// It is the root service for all facets and handles which other services to delegate to. pub trait RootFacetService { - fn initialize(&self, params: FacetParams) -> impl std::future::Future> + Send; - fn initialize_all(&self, params: FacetSetParams) -> impl std::future::Future, SkootError>> + Send; + fn initialize(&self, params: FacetCreateParams) -> impl std::future::Future> + Send; + fn initialize_all(&self, params: FacetSetCreateParams) -> impl std::future::Future, SkootError>> + Send; } /// (DEPRECATED) The `SourceFileFacetService` trait provides an interface for initializing and managing a project's source @@ -80,7 +80,7 @@ pub trait SourceBundleFacetService { /// Returns an error if the source bundle facet can't be initialized. fn initialize( &self, - params: SourceBundleFacetParams, + params: SourceBundleFacetCreateParams, ) -> Result; } @@ -92,7 +92,7 @@ impl SourceBundleFacetService for LocalFacetService { /// Returns an error if the source bundle facet can't be initialized. fn initialize( &self, - params: SourceBundleFacetParams, + params: SourceBundleFacetCreateParams, ) -> Result { let source_service = LocalSourceService {}; let default_source_bundle_content_handler = DefaultSourceBundleContentHandler {}; @@ -130,11 +130,12 @@ impl SourceBundleFacetService for LocalFacetService { SupportedFacetType::Allstar => todo!(), SupportedFacetType::DefaultSourceCode => language_specific_source_bundle_content_handler.generate_content(¶ms)?, SupportedFacetType::VulnerabilityReporting => unimplemented!("VulnerabilityReporting is not implemented for source bundles"), + SupportedFacetType::Other => todo!(), }; for source_file_content in &source_bundle_content.source_files_content { info!( - "Writing file {} to {}", + "Starting to write file {} to {}", source_file_content.name, source_file_content.path ); source_service.write_file( @@ -145,9 +146,22 @@ impl SourceBundleFacetService for LocalFacetService { )?; } + let source_files: Vec = source_bundle_content.source_files_content.iter().map(|source_file_content| { + Ok::(SourceFile { + name: source_file_content.name.clone(), + path: source_file_content.path.clone(), + hash: source_service.hash_file( + ¶ms.common.source, + source_file_content.path.clone(), + source_file_content.name.clone(), + )?, + }) + }).collect::, _>>()?; + let source_bundle_facet = SourceBundleFacet { - source_files: source_bundle_content.source_files_content, + source_files: Some(source_files), facet_type: params.facet_type, + source_files_content: None }; Ok(source_bundle_facet) @@ -191,18 +205,18 @@ pub struct SourceBundleContent { } impl RootFacetService for LocalFacetService { - async fn initialize(&self, params: FacetParams) -> Result { + async fn initialize(&self, params: FacetCreateParams) -> Result { match params { - FacetParams::SourceFile(_params) => { + FacetCreateParams::SourceFile(_params) => { todo!("This has been removed in favor of SourceBundle") /*let source_file_facet = SourceFileFacetService::initialize(self, params)?; Ok(InitializedFacet::SourceFile(source_file_facet))*/ } - FacetParams::SourceBundle(params) => { + FacetCreateParams::SourceBundle(params) => { let source_bundle_facet = SourceBundleFacetService::initialize(self, params)?; Ok(InitializedFacet::SourceBundle(source_bundle_facet)) } - FacetParams::APIBundle(params) => { + FacetCreateParams::APIBundle(params) => { let api_bundle_facet = APIBundleFacetService::initialize(self, params).await?; Ok(InitializedFacet::APIBundle(api_bundle_facet)) }, @@ -211,7 +225,7 @@ impl RootFacetService for LocalFacetService { async fn initialize_all( &self, - params: FacetSetParams, + params: FacetSetCreateParams, ) -> Result, SkootError> { let futures = params .facets_params @@ -220,7 +234,6 @@ impl RootFacetService for LocalFacetService { let results = futures::future::try_join_all(futures).await?; Ok(results) - //.collect::, SkootError>>() } @@ -328,7 +341,7 @@ impl GithubAPIBundleHandler { trait SourceBundleContentGenerator { fn generate_content( &self, - params: &SourceBundleFacetParams, + params: &SourceBundleFacetCreateParams, ) -> Result; } @@ -339,7 +352,7 @@ struct DefaultSourceBundleContentHandler {} impl SourceBundleContentGenerator for DefaultSourceBundleContentHandler { fn generate_content( &self, - params: &SourceBundleFacetParams, + params: &SourceBundleFacetCreateParams, ) -> Result { match params.facet_type { SupportedFacetType::Readme => self.generate_readme_content(params), @@ -355,7 +368,7 @@ impl SourceBundleContentGenerator for DefaultSourceBundleContentHandler { impl DefaultSourceBundleContentHandler { fn generate_readme_content( &self, - params: &SourceBundleFacetParams, + params: &SourceBundleFacetCreateParams, ) -> Result { #[derive(Template)] #[template(path = "README.md", escape = "none")] @@ -381,7 +394,7 @@ impl DefaultSourceBundleContentHandler { // TODO: Support more than Apache 2.0 fn generate_license_content( &self, - params: &SourceBundleFacetParams, + params: &SourceBundleFacetCreateParams, ) -> Result { #[derive(Template)] #[template(path = "LICENSE", escape = "none")] @@ -409,7 +422,7 @@ impl DefaultSourceBundleContentHandler { // TODO: Create actual security policy fn generate_security_policy_content( &self, - _params: &SourceBundleFacetParams, + _params: &SourceBundleFacetCreateParams, ) -> Result { // TODO: Turn this into a real default security policy #[derive(Template)] @@ -431,7 +444,7 @@ impl DefaultSourceBundleContentHandler { fn generate_scorecard_content( &self, - _params: &SourceBundleFacetParams, + _params: &SourceBundleFacetCreateParams, ) -> Result { // TODO: This should serialize to yaml instead of just a file template #[derive(Template)] @@ -454,7 +467,7 @@ impl DefaultSourceBundleContentHandler { #[allow(clippy::too_many_lines)] fn generate_security_insights_content( &self, - params: &SourceBundleFacetParams, + params: &SourceBundleFacetCreateParams, ) -> Result { let insights = SecurityInsightsVersion100YamlSchema { contribution_policy: SecurityInsightsVersion100YamlSchemaContributionPolicy { @@ -566,7 +579,7 @@ impl DefaultSourceBundleContentHandler { fn generate_sast_content( &self, - _params: &SourceBundleFacetParams, + _params: &SourceBundleFacetCreateParams, ) -> Result { #[derive(Template)] #[template(path = "codeql.yml", escape = "none")] @@ -593,7 +606,7 @@ struct GoGithubSourceBundleContentHandler {} impl SourceBundleContentGenerator for GoGithubSourceBundleContentHandler { fn generate_content( &self, - params: &SourceBundleFacetParams, + params: &SourceBundleFacetCreateParams, ) -> Result { match params.facet_type { SupportedFacetType::Gitignore => self.generate_gitignore_content(params), @@ -617,7 +630,7 @@ impl SourceBundleContentGenerator for GoGithubSourceBundleContentHandler { impl GoGithubSourceBundleContentHandler { fn generate_gitignore_content( &self, - _params: &SourceBundleFacetParams, + _params: &SourceBundleFacetCreateParams, ) -> Result { #[derive(Template)] #[template(path = "go.gitignore", escape = "none")] @@ -640,7 +653,7 @@ impl GoGithubSourceBundleContentHandler { // Note: Content mostly taken from https://github.com/guacsec/guac/blob/f1703bd4ca3c0ec0fa55c5a3401d50578fb1680e/.github/workflows/release.yaml fn generate_slsa_build_content( &self, - params: &SourceBundleFacetParams, + params: &SourceBundleFacetCreateParams, ) -> Result { // TODO: This should really be a struct that serializes to yaml instead of just a file template #[derive(Template)] @@ -697,7 +710,7 @@ impl GoGithubSourceBundleContentHandler { fn generate_dependency_update_tool_content( &self, - _params: &SourceBundleFacetParams, + _params: &SourceBundleFacetCreateParams, ) -> Result { #[derive(Template)] #[template(path = "dependabot.yml", escape = "none")] @@ -722,7 +735,7 @@ impl GoGithubSourceBundleContentHandler { fn generate_fuzzing_content( &self, - params: &SourceBundleFacetParams, + params: &SourceBundleFacetCreateParams, ) -> Result { #[derive(Template)] #[template(path = "cifuzz.yml", escape = "none")] @@ -749,7 +762,7 @@ impl GoGithubSourceBundleContentHandler { fn generate_default_source_code_content( &self, - _params: &SourceBundleFacetParams, + _params: &SourceBundleFacetCreateParams, ) -> Result { #[derive(Template)] #[template(path = "main.go.tmpl", escape = "none")] @@ -782,11 +795,11 @@ impl FacetSetParamsGenerator { /// Returns an error if any of the facet set params can't be generated. pub fn generate_default( &self, - common_params: &CommonFacetParams, - ) -> Result> { + common_params: &CommonFacetCreateParams, + ) -> Result { let source_bundle_params = self.generate_default_source_bundle_facet_params(common_params)?; let api_bundle_params = self.generate_default_api_bundle(common_params)?; - let total_params = FacetSetParams { + let total_params = FacetSetCreateParams { facets_params: [ source_bundle_params.facets_params, api_bundle_params.facets_params, @@ -804,8 +817,8 @@ impl FacetSetParamsGenerator { /// Returns an error if the default set of API bundle facets can't be generated. pub fn generate_default_api_bundle( &self, - common_params: &CommonFacetParams, - ) -> Result { + common_params: &CommonFacetCreateParams, + ) -> Result { use SupportedFacetType::{BranchProtection, VulnerabilityReporting}; let supported_facets = [ //CodeReview, @@ -815,14 +828,14 @@ impl FacetSetParamsGenerator { let facets_params = supported_facets .iter() .map(|facet_type| { - FacetParams::APIBundle(APIBundleFacetParams { + FacetCreateParams::APIBundle(APIBundleFacetParams { common: common_params.clone(), facet_type: facet_type.clone(), }) }) - .collect::>(); + .collect::>(); - Ok(FacetSetParams { facets_params }) + Ok(FacetSetCreateParams { facets_params }) } // TODO: Come up with a better solution than hard coding the default facets @@ -833,8 +846,8 @@ impl FacetSetParamsGenerator { /// Returns an error if the default set of source bundle facets can't be generated. pub fn generate_default_source_bundle_facet_params( &self, - common_params: &CommonFacetParams, - ) -> Result { + common_params: &CommonFacetCreateParams, + ) -> Result { use SupportedFacetType::{ DefaultSourceCode, DependencyUpdateTool, Gitignore, License, Readme, SLSABuild, Scorecard, SecurityInsights, SecurityPolicy, SAST, @@ -867,13 +880,13 @@ impl FacetSetParamsGenerator { let facets_params = supported_facets .iter() .map(|facet_type| { - FacetParams::SourceBundle(SourceBundleFacetParams { + FacetCreateParams::SourceBundle(SourceBundleFacetCreateParams { common: common_params.clone(), facet_type: facet_type.clone(), }) }) - .collect::>(); + .collect::>(); - Ok(FacetSetParams { facets_params }) + Ok(FacetSetCreateParams { facets_params }) } } \ No newline at end of file diff --git a/skootrs-lib/src/service/project.rs b/skootrs-lib/src/service/project.rs index 72bac76..4d6e6f8 100644 --- a/skootrs-lib/src/service/project.rs +++ b/skootrs-lib/src/service/project.rs @@ -15,37 +15,61 @@ #![allow(clippy::module_name_repetitions)] -use std::error::Error; +use std::collections::HashMap; use crate::service::facet::{FacetSetParamsGenerator, RootFacetService}; + use skootrs_model::skootrs::{ - facet::CommonFacetParams, InitializedProject, InitializedSource, ProjectParams, + facet::{CommonFacetCreateParams, InitializedFacet, SourceFile}, + FacetGetParams, FacetMapKey, InitializedProject, InitializedSource, ProjectCreateParams, + ProjectGetParams, SkootError, }; -use super::{ - ecosystem::EcosystemService, - repo::RepoService, - source::SourceService, -}; -use tracing::debug; +use super::{ecosystem::EcosystemService, repo::RepoService, source::SourceService}; +use tracing::{debug, error, info}; /// The `ProjectService` trait provides an interface for initializing and managing a Skootrs project. pub trait ProjectService { /// Initializes a Skootrs project. - ///h + /// /// # Errors /// /// Returns an error if the project can't be initialized for any reason. fn initialize( &self, - params: ProjectParams, - ) -> impl std::future::Future>> + Send; + params: ProjectCreateParams, + ) -> impl std::future::Future> + Send; + + /// Gets an initialized project. + /// + /// # Errors + /// + /// Returns an error if the project can't be found or fetched. + fn get( + &self, + params: ProjectGetParams, + ) -> impl std::future::Future> + Send; + + /// Gets a facet along with its content from an initialized project. + /// + /// # Errors + /// + /// Returns an error if the facet can't be found or fetched. + fn get_facet_with_content( + &self, + params: FacetGetParams, + ) -> impl std::future::Future> + Send; } /// The `LocalProjectService` struct provides an implementation of the `ProjectService` trait for initializing /// and managing a Skootrs project on the local machine. #[derive(Debug)] -pub struct LocalProjectService { +pub struct LocalProjectService< + RS: RepoService, + ES: EcosystemService, + SS: SourceService, + FS: RootFacetService, +> { pub repo_service: RS, pub ecosystem_service: ES, pub source_service: SS, @@ -61,8 +85,8 @@ where { async fn initialize( &self, - params: ProjectParams, - ) -> Result> { + params: ProjectCreateParams, + ) -> Result { debug!("Starting repo initialization"); let initialized_repo = self .repo_service @@ -79,15 +103,15 @@ where debug!("Starting facet initialization"); // TODO: This is ugly and this should probably be configured somewhere better, preferably outside of code. let facet_set_params_generator = FacetSetParamsGenerator {}; - let common_params = CommonFacetParams { + let common_params = CommonFacetCreateParams { project_name: params.name.clone(), source: initialized_source.clone(), repo: initialized_repo.clone(), ecosystem: initialized_ecosystem.clone(), }; //let facet_set_params = facet_set_params_generator.generate_default(&common_params)?; - let source_facet_set_params = - facet_set_params_generator.generate_default_source_bundle_facet_params(&common_params)?; + let source_facet_set_params = facet_set_params_generator + .generate_default_source_bundle_facet_params(&common_params)?; let api_facet_set_params = facet_set_params_generator.generate_default_api_bundle(&common_params)?; let initialized_source_facets = self @@ -103,9 +127,14 @@ where .facet_service .initialize_all(api_facet_set_params) .await?; - let initialized_facets = [initialized_source_facets, initialized_api_facets].concat(); + // FIXME: Also add facet by name as well + let initialized_facets = [initialized_source_facets, initialized_api_facets] + .concat() + .into_iter() + .map(|f| (FacetMapKey::Type(f.facet_type()), f)) + .collect::>(); - debug!("Completed project initialization"); + info!("Completed project initialization"); Ok(InitializedProject { repo: initialized_repo, @@ -114,15 +143,97 @@ where facets: initialized_facets, }) } + + async fn get(&self, params: ProjectGetParams) -> Result { + let get_repo_params = skootrs_model::skootrs::InitializedRepoGetParams { + repo_url: params.project_url.clone(), + }; + debug!("Getting repo: {get_repo_params:?}"); + let repo = self.repo_service.get(get_repo_params).await?; + // TODO: Skootrs file path should be kept as a global constant somewhere. + let skootrs_file = self + .repo_service + .fetch_file_content(&repo, ".skootrs") + .await?; + debug!("Skootrs file: {skootrs_file}"); + let initialized_project: InitializedProject = serde_json::from_str(&skootrs_file)?; + Ok(initialized_project) + } + + async fn get_facet_with_content( + &self, + params: FacetGetParams, + ) -> Result { + let initialized_project = self + .get(ProjectGetParams { + project_url: params.project_url.clone(), + }) + .await?; + //let facet = initialized_project.facets.iter().find(|f| f.facet_type() == params.facet_type); + let facet = initialized_project + .facets + .get(¶ms.facet_map_key) + .ok_or(SkootError::from("Facet not found"))?; + + match facet { + InitializedFacet::SourceBundle(s) => { + if let Some(source_files) = s.source_files.clone() { + let source_files_content_futures = source_files.into_iter().map(|sf| async { + let path = std::path::Path::new(&sf.path).join(&sf.name); + // FIXME: This stripped path should probably be handled by the fetch facet content function + let stripped_path = path.strip_prefix("./").unwrap_or(&path); + + let content = self + .repo_service + .fetch_file_content(&initialized_project.repo, stripped_path) + .await; + match content { + Ok(c) => Ok((sf, c)), + Err(e) => { + error!( + "Error fetching file content for path: {stripped_path:#?}, error: {e}" + ); + Err(e) + } + } + }); + let source_files_content_results = + futures::future::join_all(source_files_content_futures) + .await + .into_iter() + .collect::, SkootError>>()?; + let source_files_content_map = source_files_content_results + .into_iter() + .collect::>(); + Ok(InitializedFacet::SourceBundle( + skootrs_model::skootrs::facet::SourceBundleFacet { + facet_type: skootrs_model::skootrs::facet::SupportedFacetType::Readme, + source_files: None, + source_files_content: Some(source_files_content_map), + }, + )) + } else { + Err(SkootError::from("No source files found")) + } + } + InitializedFacet::APIBundle(a) => Ok(InitializedFacet::APIBundle(a.clone())), + InitializedFacet::SourceFile(_) => Err(SkootError::from("Facet type not supported")), + } + } } #[cfg(test)] mod tests { + use std::path::Path; + use skootrs_model::skootrs::{ facet::{ - APIBundleFacet, APIContent, FacetParams, FacetSetParams, InitializedFacet, - SourceBundleFacet, SourceFileContent, SupportedFacetType, - }, EcosystemParams, GithubRepoParams, GithubUser, GoParams, InitializedEcosystem, InitializedGithubRepo, InitializedGo, InitializedMaven, InitializedRepo, RepoParams, SkootError, SourceParams + APIBundleFacet, APIContent, FacetCreateParams, FacetSetCreateParams, SourceBundleFacet, + SupportedFacetType, + }, + EcosystemInitializeParams, GithubRepoParams, GithubUser, GoParams, InitializedEcosystem, + InitializedGithubRepo, InitializedGo, InitializedMaven, InitializedRepo, RepoCreateParams, + SourceInitializeParams, }; use super::*; @@ -132,24 +243,23 @@ mod tests { struct MockFacetService; impl RepoService for MockRepoService { - fn initialize(&self, params: RepoParams) -> impl std::future::Future> + Send { - async { - let inner_params = match params { - RepoParams::Github(g) => g, - }; - - // Special case for testing error handling - if inner_params.name == "error" { - return Err("Error".into()) - } - - let initialized_repo = InitializedRepo::Github(InitializedGithubRepo { - name: inner_params.name, - organization: inner_params.organization, - }); - - Ok(initialized_repo) + async fn initialize( + &self, + params: RepoCreateParams, + ) -> Result { + let RepoCreateParams::Github(inner_params) = params; + + // Special case for testing error handling + if inner_params.name == "error" { + return Err("Error".into()); } + + let initialized_repo = InitializedRepo::Github(InitializedGithubRepo { + name: inner_params.name, + organization: inner_params.organization, + }); + + Ok(initialized_repo) } fn clone_local( @@ -157,9 +267,7 @@ mod tests { initialized_repo: InitializedRepo, path: String, ) -> Result { - let inner_repo = match initialized_repo { - InitializedRepo::Github(g) => g, - }; + let InitializedRepo::Github(inner_repo) = initialized_repo; if inner_repo.name == "error" { return Err("Error".into()); @@ -171,29 +279,66 @@ mod tests { Ok(initialized_source) } + + fn clone_local_or_pull( + &self, + initialized_repo: InitializedRepo, + path: String, + ) -> Result { + self.clone_local(initialized_repo, path) + } + + async fn get( + &self, + params: skootrs_model::skootrs::InitializedRepoGetParams, + ) -> Result { + let repo_url = params.repo_url.clone(); + if repo_url == "error" { + return Err("Error".into()); + } + + let initialized_repo = InitializedRepo::Github(InitializedGithubRepo { + name: "test".to_string(), + organization: GithubUser::User("testuser".to_string()), + }); + + Ok(initialized_repo) + } + + async fn fetch_file_content + Send>( + &self, + _initialized_repo: &InitializedRepo, + path: P, + ) -> Result { + if path.as_ref().to_str().unwrap() == "error" { + return Err("Error".into()); + } + + Ok("Worked".to_string()) + } } impl EcosystemService for MockEcosystemService { fn initialize( &self, - params: EcosystemParams, + params: EcosystemInitializeParams, _source: InitializedSource, ) -> Result { let initialized_ecosystem = match params { - EcosystemParams::Go(g) => { + EcosystemInitializeParams::Go(g) => { if g.host == "error" { return Err("Error".into()); } - InitializedEcosystem::Go(InitializedGo{ + InitializedEcosystem::Go(InitializedGo { name: g.name, host: g.host, }) } - EcosystemParams::Maven(m) => { + EcosystemInitializeParams::Maven(m) => { if m.group_id == "error" { return Err("Error".into()); } - InitializedEcosystem::Maven(InitializedMaven{ + InitializedEcosystem::Maven(InitializedMaven { group_id: m.group_id, artifact_id: m.artifact_id, }) @@ -207,7 +352,7 @@ mod tests { impl SourceService for MockSourceService { fn initialize( &self, - params: skootrs_model::skootrs::SourceParams, + params: skootrs_model::skootrs::SourceInitializeParams, initialized_repo: InitializedRepo, ) -> Result { if params.parent_path == "error" { @@ -227,7 +372,7 @@ mod tests { fn commit_and_push_changes( &self, - source: InitializedSource, + _source: InitializedSource, message: String, ) -> Result<(), SkootError> { if message == "error" { @@ -263,84 +408,100 @@ mod tests { Ok("Worked".to_string()) } + + fn hash_file>( + &self, + _source: &InitializedSource, + path: P, + _name: String, + ) -> Result { + if path.as_ref().to_str().unwrap() == "error" { + return Err("Error".into()); + } + + Ok("fakehash".to_string()) + } + + fn pull_updates(&self, source: InitializedSource) -> Result<(), SkootError> { + if source.path == "error" { + return Err("Error".into()); + } + + Ok(()) + } } impl RootFacetService for MockFacetService { - fn initialize( + async fn initialize( &self, - params: FacetParams, - ) -> impl std::future::Future> + Send - { - async { - match params { - FacetParams::SourceFile(_) => Err("Error".into()), - FacetParams::SourceBundle(s) => { - if s.common.project_name == "error" { - return Err("Error".into()); - } - let source_bundle_facet = SourceBundleFacet { - source_files: vec![SourceFileContent { - name: "README.md".to_string(), - path: "./".to_string(), - content: s.common.project_name.clone(), - }], - facet_type: SupportedFacetType::Readme, - }; - - Ok(InitializedFacet::SourceBundle(source_bundle_facet)) + params: FacetCreateParams, + ) -> Result { + match params { + FacetCreateParams::SourceFile(_) => Err("Error".into()), + FacetCreateParams::SourceBundle(s) => { + if s.common.project_name == "error" { + return Err("Error".into()); } - FacetParams::APIBundle(a) => { - if a.common.project_name == "error" { - return Err("Error".into()); - } - let api_bundle_facet = APIBundleFacet { - apis: vec![APIContent { - name: "test".to_string(), - url: "https://foo.bar/test".to_string(), - response: "worked".to_string(), - }], - facet_type: SupportedFacetType::BranchProtection, - }; - - Ok(InitializedFacet::APIBundle(api_bundle_facet)) + let source_bundle_facet = SourceBundleFacet { + source_files: Some(vec![SourceFile { + name: "README.md".to_string(), + path: "./".to_string(), + hash: "fakehash".to_string(), + }]), + facet_type: SupportedFacetType::Readme, + source_files_content: None, + }; + + Ok(InitializedFacet::SourceBundle(source_bundle_facet)) + } + FacetCreateParams::APIBundle(a) => { + if a.common.project_name == "error" { + return Err("Error".into()); } + let api_bundle_facet = APIBundleFacet { + apis: vec![APIContent { + name: "test".to_string(), + url: "https://foo.bar/test".to_string(), + response: "worked".to_string(), + }], + facet_type: SupportedFacetType::BranchProtection, + }; + + Ok(InitializedFacet::APIBundle(api_bundle_facet)) } } } - fn initialize_all( + async fn initialize_all( &self, - params: FacetSetParams, - ) -> impl std::future::Future, SkootError>> + Send - { - async { - let mut initialized_facets = Vec::new(); - for facet_params in params.facets_params { - let initialized_facet = self.initialize(facet_params).await?; - initialized_facets.push(initialized_facet); - } - - Ok(initialized_facets) + params: FacetSetCreateParams, + ) -> Result, SkootError> { + let mut initialized_facets = Vec::new(); + for facet_params in params.facets_params { + let initialized_facet = self.initialize(facet_params).await?; + initialized_facets.push(initialized_facet); } + + Ok(initialized_facets) } } #[tokio::test] async fn test_initialize_project() { - let project_params = ProjectParams { - name: "test".to_string(), - repo_params: RepoParams::Github(GithubRepoParams { + let project_params = ProjectCreateParams { + name: "test".to_string(), + repo_params: RepoCreateParams::Github(GithubRepoParams { name: "test".to_string(), - description: "foobar".to_string(), - organization: GithubUser::User("testuser".to_string()) - }), - ecosystem_params: EcosystemParams::Go(GoParams { - name: "test".to_string(), - host: "github.com".to_string() + description: "foobar".to_string(), + organization: GithubUser::User("testuser".to_string()), }), - source_params: SourceParams { - parent_path: "test".to_string() - } + ecosystem_params: EcosystemInitializeParams::Go(GoParams { + name: "test".to_string(), + host: "github.com".to_string(), + }), + source_params: SourceInitializeParams { + parent_path: "test".to_string(), + }, }; let local_project_service = LocalProjectService { @@ -362,8 +523,11 @@ mod tests { }; assert!(module.name == "test"); assert!(initialized_project.source.path == "test/test"); - // TODO: This just pulls in the default set of facets which has a length of 12. - // This should be more configurable. - assert_eq!(initialized_project.facets.len(), 12); + println!("{:#?}", initialized_project.facets); + + // TODO: This will always be equal to 2 because we are initializing two facets in the mock facet service + // and the `HashMap` for the facets will keep getting the same key. This is probably not a great way + // of handling that. + assert_eq!(initialized_project.facets.len(), 2); } } diff --git a/skootrs-lib/src/service/repo.rs b/skootrs-lib/src/service/repo.rs index ecc6680..9363381 100644 --- a/skootrs-lib/src/service/repo.rs +++ b/skootrs-lib/src/service/repo.rs @@ -16,12 +16,12 @@ #![allow(clippy::module_name_repetitions)] -use std::{error::Error, process::Command, str::FromStr, sync::Arc}; +use std::{process::Command, str::FromStr, sync::Arc}; use chrono::Utc; use tracing::{info, debug}; -use skootrs_model::{skootrs::{GithubRepoParams, GithubUser, InitializedGithubRepo, InitializedRepo, InitializedSource, RepoParams, SkootError}, cd_events::repo_created::{RepositoryCreatedEvent, RepositoryCreatedEventContext, RepositoryCreatedEventContextId, RepositoryCreatedEventContextVersion, RepositoryCreatedEventSubject, RepositoryCreatedEventSubjectContent, RepositoryCreatedEventSubjectContentName, RepositoryCreatedEventSubjectContentUrl, RepositoryCreatedEventSubjectId}}; +use skootrs_model::{cd_events::repo_created::{RepositoryCreatedEvent, RepositoryCreatedEventContext, RepositoryCreatedEventContextId, RepositoryCreatedEventContextVersion, RepositoryCreatedEventSubject, RepositoryCreatedEventSubjectContent, RepositoryCreatedEventSubjectContentName, RepositoryCreatedEventSubjectContentUrl, RepositoryCreatedEventSubjectId}, skootrs::{InitializedRepoGetParams, GithubRepoParams, GithubUser, InitializedGithubRepo, InitializedRepo, InitializedSource, RepoCreateParams, SkootError}}; /// The `RepoService` trait provides an interface for initializing and managing a project's source code /// repository. This repo is usually something like Github or Gitlab. @@ -32,7 +32,14 @@ pub trait RepoService { /// # Errors /// /// Returns an error if the source code repository can't be initialized. - fn initialize(&self, params: RepoParams) -> impl std::future::Future> + Send; + fn initialize(&self, params: RepoCreateParams) -> impl std::future::Future> + Send; + + /// Gets a project's source code repository metadata abstraction. + /// + /// # Errors + /// + /// Returns an error if the source code repository metadata can't be retrieved. + fn get(&self, params: InitializedRepoGetParams) -> impl std::future::Future> + Send; /// Clones a project's source code repository to the local machine. /// @@ -40,6 +47,21 @@ pub trait RepoService { /// /// Returns an error if the source code repository can't be cloned to the local machine. fn clone_local(&self, initialized_repo: InitializedRepo, path: String) -> Result; + + /// Clones a project's source code repository to the local machine, or pulls it if it already exists. + /// + /// # Errors + /// + /// Returns an error if the source code repository can't be cloned or if updates can't be pulled. + fn clone_local_or_pull(&self, initialized_repo: InitializedRepo, path: String) -> Result; + + /// Fectches an arbitrary file from the repository. This is useful for things like fetching a remote + /// Skootrs state file, or something like a remote SECURITY-INSIGHTS file kept in the repo. + /// + /// # Errors + /// + /// Returns an error if the file can't be fetched from the repository for any reason. + fn fetch_file_content + Send>(&self, initialized_repo: &InitializedRepo, path: P) -> impl std::future::Future> + std::marker::Send; } /// The `LocalRepoService` struct provides an implementation of the `RepoService` trait for initializing @@ -49,7 +71,7 @@ pub trait RepoService { pub struct LocalRepoService {} impl RepoService for LocalRepoService { - async fn initialize(&self, params: RepoParams) -> Result { + async fn initialize(&self, params: RepoCreateParams) -> Result { // TODO: The octocrab initialization should be done in a better place and be parameterized let o: octocrab::Octocrab = octocrab::Octocrab::builder() .personal_token( @@ -58,7 +80,7 @@ impl RepoService for LocalRepoService { .build()?; octocrab::initialise(o); match params { - RepoParams::Github(g) => { + RepoCreateParams::Github(g) => { let github_repo_handler = GithubRepoHandler { client: octocrab::instance(), }; @@ -67,13 +89,88 @@ impl RepoService for LocalRepoService { } } - fn clone_local(&self, initialized_repo: InitializedRepo, path: String) -> Result> { + fn clone_local(&self, initialized_repo: InitializedRepo, path: String) -> Result { match initialized_repo { InitializedRepo::Github(g) => { GithubRepoHandler::clone_local(&g, &path) }, } } + + fn clone_local_or_pull(&self, initialized_repo: InitializedRepo, path: String) -> Result { + // Check if path exists and is a git repo + let output = Command::new("git") + .arg("status") + .current_dir(&path) + .output()?; + + // If it is, pull updates + if output.status.success() { + let _output = Command::new("git") + .arg("pull") + .current_dir(&path) + .output()?; + Ok(InitializedSource { + path, + }) + } else { + // If it isn't, clone the repo + self.clone_local(initialized_repo, path) + } + } + + async fn get(&self, params: InitializedRepoGetParams) -> Result { + let parsed_url = url::Url::parse(¶ms.repo_url)?; + match parsed_url.host_str() { + Some("github.com") => { + let path = parsed_url.path(); + let parts: Vec<&str> = path.split('/').collect(); + let organization = parts[1]; + let name = parts[2]; + let exists = octocrab::instance().repos(organization, name).get().await.is_ok(); + if !exists { + return Err("Repo does not exist".into()); + } + Ok(InitializedRepo::Github(InitializedGithubRepo { + name: name.to_string(), + // FIXME: This will probably break in weird ways since repos from a user and organization are handled + // slightly different in the Github API. I am not sure yet what the best way to determine if a repo + // belongs to a user or organization is. + organization: GithubUser::User(organization.to_string()), + })) + }, + Some(_) => Err("Unsupported repo host".into()), + _ => Err("Invalid repo URL".into()), + } + } + + async fn fetch_file_content + Send>(&self, initialized_repo: &InitializedRepo, path: P) -> Result { + match &initialized_repo { + InitializedRepo::Github(g) => { + let path_str = path.as_ref().to_str().ok_or_else(|| SkootError::from("Failed to convert path to string"))?; + let content_items = octocrab::instance().repos( + g.organization.get_name(), g.name.clone() + ) + .get_content() + .path(path_str) + // TODO: Should this support multiple branches? + .r#ref("main") + .send() + .await?; + + let content = content_items + .items + .first() + .ok_or_else(|| SkootError::from(format!("Failed to get {} from {}", path_str, initialized_repo.full_url())))?; + + debug!("Content: {content:?}"); + let content_decoded = content.decoded_content().ok_or_else(|| SkootError::from(format!("Failed to decode content from {path_str}")))?; + debug!("Content Decoded: {content_decoded:?}"); + + Ok(content_decoded) + } + } + } } /// The `GithubRepoHandler` struct represents a handler for initializing and managing Github repos. diff --git a/skootrs-lib/src/service/source.rs b/skootrs-lib/src/service/source.rs index ed80028..989a165 100644 --- a/skootrs-lib/src/service/source.rs +++ b/skootrs-lib/src/service/source.rs @@ -15,11 +15,14 @@ #![allow(clippy::module_name_repetitions)] -use std::{error::Error, fs, path::Path, process::Command}; +use std::{fs, path::Path, process::Command}; +use sha2::Digest; use tracing::{debug, info}; -use skootrs_model::skootrs::{InitializedRepo, InitializedSource, SkootError, SourceParams}; +use skootrs_model::skootrs::{ + InitializedRepo, InitializedSource, SkootError, SourceInitializeParams, +}; use super::repo::{LocalRepoService, RepoService}; /// The `SourceService` trait provides an interface for and managing a project's source code. @@ -34,7 +37,7 @@ pub trait SourceService { /// Returns an error if the source code directory can't be initialized. fn initialize( &self, - params: SourceParams, + params: SourceInitializeParams, initialized_repo: InitializedRepo, ) -> Result; @@ -73,6 +76,25 @@ pub trait SourceService { path: P, name: String, ) -> Result; + + /// `hash_file` returns the SHA256 hash of a file. + /// + /// # Errors + /// + /// Returns an error if the file can't be opened and hashed. + fn hash_file>( + &self, + source: &InitializedSource, + path: P, + name: String, + ) -> Result; + + /// Pulls updates from the remote repo. + /// + /// # Errors + /// + /// Returns an error if the updates can't be pulled from the remote repo. + fn pull_updates(&self, source: InitializedSource) -> Result<(), SkootError>; } /// The `LocalSourceService` struct provides an implementation of the `SourceService` trait for initializing @@ -85,7 +107,7 @@ impl SourceService for LocalSourceService { /// otherwise returns an error. fn initialize( &self, - params: SourceParams, + params: SourceInitializeParams, initialized_repo: InitializedRepo, ) -> Result { let repo_service = LocalRepoService {}; @@ -96,7 +118,7 @@ impl SourceService for LocalSourceService { &self, source: InitializedSource, message: String, - ) -> Result<(), Box> { + ) -> Result<(), SkootError> { let _output = Command::new("git") .arg("add") .arg(".") @@ -148,12 +170,39 @@ impl SourceService for LocalSourceService { let contents = fs::read_to_string(full_path)?; Ok(contents) } + + fn hash_file>( + &self, + source: &InitializedSource, + path: P, + name: String, + ) -> Result { + let full_path: std::path::PathBuf = Path::new(&source.path).join(&path).join(name); + debug!("Hashing file {:?}", &full_path); + let mut contents = fs::File::open(&full_path)?; + let mut hasher = sha2::Sha256::new(); + std::io::copy(&mut contents, &mut hasher)?; + let hash = hasher.finalize(); + //let hash = "test".to_string(); + + debug!("Hashed file {:?} with hash: {:x}", &full_path, &hash); + Ok(format!("{hash:x}")) + } + + fn pull_updates(&self, source: InitializedSource) -> Result<(), SkootError> { + let _output = Command::new("git") + .arg("pull") + .current_dir(&source.path) + .output()?; + info!("Pulled updates for {}", source.path); + Ok(()) + } } #[cfg(test)] mod tests { use super::*; - use skootrs_model::skootrs::{GithubUser, InitializedGithubRepo, InitializedRepo, InitializedSource, SourceParams}; + use skootrs_model::skootrs::{GithubUser, InitializedGithubRepo}; use std::path::PathBuf; use tempdir::TempDir; @@ -162,18 +211,20 @@ mod tests { let source_service = LocalSourceService {}; let temp_dir = TempDir::new("test").unwrap(); let parent_path = temp_dir.path().to_str().unwrap(); - let params = SourceParams { + let params = SourceInitializeParams { parent_path: parent_path.to_string(), }; - let initialized_repo = InitializedRepo::Github( - InitializedGithubRepo { - name: "skootrs".to_string(), - organization: GithubUser::Organization("kusaridev".to_string()), + let initialized_repo = InitializedRepo::Github(InitializedGithubRepo { + name: "skootrs".to_string(), + organization: GithubUser::Organization("kusaridev".to_string()), }); let result = source_service.initialize(params, initialized_repo); assert!(result.is_ok()); let initialized_source = result.unwrap(); - assert_eq!(initialized_source.path, format!("{}/{}", parent_path, "skootrs")); + assert_eq!( + initialized_source.path, + format!("{}/{}", parent_path, "skootrs") + ); } #[test] @@ -188,7 +239,8 @@ mod tests { let contents = "File contents".as_bytes(); let result = source_service.write_file(initialized_source, path, name.clone(), contents); assert!(result.is_ok()); - let file_path = PathBuf::from(format!("{}/{}", temp_dir.path().to_str().unwrap(), path)).join(name); + let file_path = + PathBuf::from(format!("{}/{}", temp_dir.path().to_str().unwrap(), path)).join(name); assert!(file_path.exists()); let file_contents = fs::read_to_string(file_path).unwrap(); assert_eq!(file_contents, "File contents"); @@ -204,11 +256,15 @@ mod tests { let path = "subdirectory"; let name = "file.txt".to_string(); let contents = "File contents".as_bytes(); - let result = source_service.write_file(initialized_source.clone(), path, name.clone(), contents); + let result = + source_service.write_file(initialized_source.clone(), path, name.clone(), contents); assert!(result.is_ok()); - let file_path = PathBuf::from(format!("{}/{}", temp_dir.path().to_str().unwrap(), path)).join(name.clone()); + let file_path = PathBuf::from(format!("{}/{}", temp_dir.path().to_str().unwrap(), path)) + .join(name.clone()); assert!(file_path.exists()); - let file_contents = source_service.read_file(&initialized_source, path, name).unwrap(); + let file_contents = source_service + .read_file(&initialized_source, path, name) + .unwrap(); assert_eq!(file_contents, "File contents"); } } diff --git a/skootrs-model/Cargo.toml b/skootrs-model/Cargo.toml index 0f9abaf..0ce115a 100644 --- a/skootrs-model/Cargo.toml +++ b/skootrs-model/Cargo.toml @@ -13,6 +13,9 @@ utoipa = { version = "4.1.0" } chrono = { version = "0.4.31", features = ["serde"] } schemars = { version = "0.8.16", features = ["chrono", "url"] } regress = "0.7.1" +sha2 = "0.10.8" +url = "2.5.0" +strum = { version = "0.26.1", features = ["derive"] } [lints] workspace = true diff --git a/skootrs-model/src/cd_events/repo_created.rs b/skootrs-model/src/cd_events/repo_created.rs index 8cb6b7a..f7b0217 100644 --- a/skootrs-model/src/cd_events/repo_created.rs +++ b/skootrs-model/src/cd_events/repo_created.rs @@ -23,6 +23,7 @@ #![allow(clippy::return_self_not_must_use)] #![allow(clippy::default_trait_access)] #![allow(clippy::to_string_trait_impl)] +#![allow(missing_docs)] use serde::{Deserialize, Serialize}; use utoipa::ToSchema; @@ -51,7 +52,8 @@ impl From<&Self> for RepositoryCreatedEvent { } } impl RepositoryCreatedEvent { - #[must_use] pub fn builder() -> builder::RepositoryCreatedEvent { + #[must_use] + pub fn builder() -> builder::RepositoryCreatedEvent { builder::RepositoryCreatedEvent::default() } } @@ -71,7 +73,8 @@ impl From<&Self> for RepositoryCreatedEventContext { } } impl RepositoryCreatedEventContext { - #[must_use] pub fn builder() -> builder::RepositoryCreatedEventContext { + #[must_use] + pub fn builder() -> builder::RepositoryCreatedEventContext { builder::RepositoryCreatedEventContext::default() } } @@ -270,7 +273,8 @@ impl From<&Self> for RepositoryCreatedEventSubject { } } impl RepositoryCreatedEventSubject { - #[must_use] pub fn builder() -> builder::RepositoryCreatedEventSubject { + #[must_use] + pub fn builder() -> builder::RepositoryCreatedEventSubject { builder::RepositoryCreatedEventSubject::default() } } @@ -290,7 +294,8 @@ impl From<&Self> for RepositoryCreatedEventSubjectContent { } } impl RepositoryCreatedEventSubjectContent { - #[must_use] pub fn builder() -> builder::RepositoryCreatedEventSubjectContent { + #[must_use] + pub fn builder() -> builder::RepositoryCreatedEventSubjectContent { builder::RepositoryCreatedEventSubjectContent::default() } } @@ -553,9 +558,7 @@ pub mod builder { T::Error: std::fmt::Display, { self.custom_data_content_type = value.try_into().map_err(|e| { - format!( - "error converting supplied value for custom_data_content_type: {e}" - ) + format!("error converting supplied value for custom_data_content_type: {e}") }); self } diff --git a/skootrs-model/src/lib.rs b/skootrs-model/src/lib.rs index a5b40d7..1775e91 100644 --- a/skootrs-model/src/lib.rs +++ b/skootrs-model/src/lib.rs @@ -15,15 +15,18 @@ //! This is where all the models for the Skootrs project are defined. The models are just the data //! representing the abstractions around a project like its repository, source code, and facets. -//! +//! //! The models here need to be (de)serializable, i.e. implementing `serde::Serialize` and `serde::Deserialize` //! so that they can be easily used in RPC calls and other places where data needs to be sent over the wire. //! For example the REST API that is in the `skootrs-rest` crate. Currently for the sake of simplicity we don'T //! use much in the way of generics and trait objects because of issues with (de)serialization. -//! +//! //! All the models besides those that fall under `/skootrs` are considered external. In most cases they are //! code generated. The models in `/skootrs` are the core models for the Skootrs project and defined for the //! purpose of the project. -pub mod security_insights; +/// CD Events models. pub mod cd_events; -pub mod skootrs; \ No newline at end of file +/// Security Insights models. +pub mod security_insights; +/// Skootrs specific models. +pub mod skootrs; diff --git a/skootrs-model/src/security_insights/insights10.rs b/skootrs-model/src/security_insights/insights10.rs index c32902d..21285a9 100644 --- a/skootrs-model/src/security_insights/insights10.rs +++ b/skootrs-model/src/security_insights/insights10.rs @@ -21,6 +21,8 @@ #![allow(clippy::return_self_not_must_use)] #![allow(clippy::default_trait_access)] #![allow(clippy::unwrap_used)] +#![allow(missing_docs)] + use serde::{Deserialize, Serialize}; use utoipa::ToSchema; ///YAML schema for security-insights.yml @@ -43,32 +45,33 @@ pub struct SecurityInsightsVersion100YamlSchema { default, skip_serializing_if = "Option::is_none" )] - pub security_artifacts: Option< - SecurityInsightsVersion100YamlSchemaSecurityArtifacts, - >, + pub security_artifacts: Option, #[serde( rename = "security-assessments", default, skip_serializing_if = "Option::is_none" )] - pub security_assessments: Option< - Vec, - >, + pub security_assessments: + Option>, #[serde(rename = "security-contacts")] pub security_contacts: Vec, - #[serde(rename = "security-testing", default, skip_serializing_if = "Vec::is_empty")] + #[serde( + rename = "security-testing", + default, + skip_serializing_if = "Vec::is_empty" + )] pub security_testing: Vec, #[serde(rename = "vulnerability-reporting")] pub vulnerability_reporting: SecurityInsightsVersion100YamlSchemaVulnerabilityReporting, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchema { +impl From<&Self> for SecurityInsightsVersion100YamlSchema { fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchema { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchema { + #[must_use] + pub fn builder() -> builder::SecurityInsightsVersion100YamlSchema { builder::SecurityInsightsVersion100YamlSchema::default() } } @@ -87,9 +90,8 @@ pub struct SecurityInsightsVersion100YamlSchemaContributionPolicy { default, skip_serializing_if = "Option::is_none" )] - pub automated_tools_list: Option< - Vec, - >, + pub automated_tools_list: + Option>, ///Link to the project code of conduct. #[serde( rename = "code-of-conduct", @@ -105,14 +107,14 @@ pub struct SecurityInsightsVersion100YamlSchemaContributionPolicy { )] pub contributing_policy: Option, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaContributionPolicy { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaContributionPolicy { fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchemaContributionPolicy { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaContributionPolicy { + #[must_use] + pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaContributionPolicy { builder::SecurityInsightsVersion100YamlSchemaContributionPolicy::default() } } @@ -126,23 +128,21 @@ pub struct SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsL pub automated_tool: String, ///Short comment. #[serde(default, skip_serializing_if = "Option::is_none")] - pub comment: Option< - SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment, - >, + pub comment: + Option, ///Define sub-paths where the automated actions are allowed or denied. #[serde(default, skip_serializing_if = "Option::is_none")] pub path: Option>, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem { + fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem { + #[must_use] + pub fn builder( + ) -> builder::SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem { builder::SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem::default() } } @@ -158,7 +158,7 @@ impl SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListIte PartialEq, PartialOrd, Serialize, - schemars::JsonSchema + schemars::JsonSchema, )] pub enum SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemAction { #[serde(rename = "allowed")] @@ -166,18 +166,16 @@ pub enum SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsLis #[serde(rename = "denied")] Denied, } -impl From< - &Self, -> -for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemAction { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> + for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemAction +{ + fn from(value: &Self) -> Self { value.clone() } } impl ToString -for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemAction { + for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemAction +{ fn to_string(&self) -> String { match *self { Self::Allowed => "allowed".to_string(), @@ -186,7 +184,8 @@ for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem } } impl std::str::FromStr -for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemAction { + for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemAction +{ type Err = &'static str; fn from_str(value: &str) -> Result { match value { @@ -197,21 +196,24 @@ for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem } } impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemAction { + for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemAction +{ type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemAction { + for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemAction +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemAction { + for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemAction +{ type Error = &'static str; fn try_from(value: String) -> Result { value.parse() @@ -219,88 +221,84 @@ for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem } ///Short comment. #[derive( - Clone, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, - schemars::JsonSchema, - ToSchema + Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, schemars::JsonSchema, ToSchema, )] pub struct SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment( String, ); impl std::ops::Deref -for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment { + for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment +{ type Target = String; fn deref(&self) -> &String { &self.0 } } -impl From< - SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment, -> for String { +impl From + for String +{ fn from( value: SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment, ) -> Self { value.0 } } -impl From< - &Self, -> -for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> + for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment +{ + fn from(value: &Self) -> Self { value.clone() } } impl std::str::FromStr -for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment { + for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment +{ type Err = &'static str; fn from_str(value: &str) -> Result { - if regress::Regex::new("^(.|\\n){1,560}$").unwrap().find(value).is_none() { + if regress::Regex::new("^(.|\\n){1,560}$") + .unwrap() + .find(value) + .is_none() + { return Err("doesn't match pattern \"^(.|\\n){1,560}$\""); } Ok(Self(value.to_string())) } } impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment { + for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment +{ type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment { + for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment { + for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment +{ type Error = &'static str; fn try_from(value: String) -> Result { value.parse() } } impl<'de> serde::Deserialize<'de> -for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment { + for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment +{ fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { String::deserialize(deserializer)? .parse() - .map_err(|e: &'static str| { - ::custom(e.to_string()) - }) + .map_err(|e: &'static str| ::custom(e.to_string())) } } #[derive(Clone, Debug, Deserialize, Serialize, schemars::JsonSchema, ToSchema)] @@ -311,9 +309,8 @@ pub struct SecurityInsightsVersion100YamlSchemaDependencies { default, skip_serializing_if = "Option::is_none" )] - pub dependencies_lifecycle: Option< - SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle, - >, + pub dependencies_lifecycle: + Option, #[serde( rename = "dependencies-lists", default, @@ -325,9 +322,8 @@ pub struct SecurityInsightsVersion100YamlSchemaDependencies { default, skip_serializing_if = "Option::is_none" )] - pub env_dependencies_policy: Option< - SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy, - >, + pub env_dependencies_policy: + Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub sbom: Option>, ///Define if the project uses third-party packages. @@ -338,14 +334,14 @@ pub struct SecurityInsightsVersion100YamlSchemaDependencies { )] pub third_party_packages: Option, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaDependencies { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaDependencies { fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchemaDependencies { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaDependencies { + #[must_use] + pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaDependencies { builder::SecurityInsightsVersion100YamlSchemaDependencies::default() } } @@ -354,107 +350,102 @@ impl SecurityInsightsVersion100YamlSchemaDependencies { pub struct SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle { ///Summary about the dependencies lifecycle policy, third-party packages updating process, and deprecation process. Maximum length 560 chars. #[serde(default, skip_serializing_if = "Option::is_none")] - pub comment: Option< - SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment, - >, + pub comment: + Option, ///Link to the dependencies lifecycle policy. - #[serde(rename = "policy-url", default, skip_serializing_if = "Option::is_none")] + #[serde( + rename = "policy-url", + default, + skip_serializing_if = "Option::is_none" + )] pub policy_url: Option, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle { + fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle { + #[must_use] + pub fn builder( + ) -> builder::SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle { builder::SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle::default() } } ///Summary about the dependencies lifecycle policy, third-party packages updating process, and deprecation process. Maximum length 560 chars. #[derive( - Clone, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, - schemars::JsonSchema, - ToSchema + Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, schemars::JsonSchema, ToSchema, )] -pub struct SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment( - String, -); +pub struct SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment(String); impl std::ops::Deref -for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment { + for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment +{ type Target = String; fn deref(&self) -> &String { &self.0 } } -impl From -for String { +impl From for String { fn from( value: SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment, ) -> Self { value.0 } } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment { + fn from(value: &Self) -> Self { value.clone() } } impl std::str::FromStr -for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment { + for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment +{ type Err = &'static str; fn from_str(value: &str) -> Result { - if regress::Regex::new("^(.|\\n){1,560}$").unwrap().find(value).is_none() { + if regress::Regex::new("^(.|\\n){1,560}$") + .unwrap() + .find(value) + .is_none() + { return Err("doesn't match pattern \"^(.|\\n){1,560}$\""); } Ok(Self(value.to_string())) } } impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment { + for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment +{ type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment { + for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment { + for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment +{ type Error = &'static str; fn try_from(value: String) -> Result { value.parse() } } impl<'de> serde::Deserialize<'de> -for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment { + for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment +{ fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { String::deserialize(deserializer)? .parse() - .map_err(|e: &'static str| { - ::custom(e.to_string()) - }) + .map_err(|e: &'static str| ::custom(e.to_string())) } } #[derive(Clone, Debug, Deserialize, Serialize, schemars::JsonSchema, ToSchema)] @@ -462,217 +453,207 @@ for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment pub struct SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy { ///Summary about how third-party dependencies are adopted and consumed in the different environments (dev, test, prod). Maximum length 560 chars. #[serde(default, skip_serializing_if = "Option::is_none")] - pub comment: Option< - SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment, - >, + pub comment: + Option, ///Link to the enviroment dependencies policy. - #[serde(rename = "policy-url", default, skip_serializing_if = "Option::is_none")] + #[serde( + rename = "policy-url", + default, + skip_serializing_if = "Option::is_none" + )] pub policy_url: Option, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy { + fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy { + #[must_use] + pub fn builder( + ) -> builder::SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy { builder::SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy::default() } } ///Summary about how third-party dependencies are adopted and consumed in the different environments (dev, test, prod). Maximum length 560 chars. #[derive( - Clone, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, - schemars::JsonSchema, - ToSchema + Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, schemars::JsonSchema, ToSchema, )] -pub struct SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment( - String, -); +pub struct SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment(String); impl std::ops::Deref -for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment { + for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment +{ type Target = String; fn deref(&self) -> &String { &self.0 } } -impl From -for String { +impl From for String { fn from( value: SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment, ) -> Self { value.0 } } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment { + fn from(value: &Self) -> Self { value.clone() } } impl std::str::FromStr -for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment { + for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment +{ type Err = &'static str; fn from_str(value: &str) -> Result { - if regress::Regex::new("^(.|\\n){1,560}$").unwrap().find(value).is_none() { + if regress::Regex::new("^(.|\\n){1,560}$") + .unwrap() + .find(value) + .is_none() + { return Err("doesn't match pattern \"^(.|\\n){1,560}$\""); } Ok(Self(value.to_string())) } } impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment { + for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment +{ type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment { + for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment { + for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment +{ type Error = &'static str; fn try_from(value: String) -> Result { value.parse() } } impl<'de> serde::Deserialize<'de> -for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment { + for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment +{ fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { String::deserialize(deserializer)? .parse() - .map_err(|e: &'static str| { - ::custom(e.to_string()) - }) + .map_err(|e: &'static str| ::custom(e.to_string())) } } #[derive(Clone, Debug, Deserialize, Serialize, schemars::JsonSchema, ToSchema)] #[serde(deny_unknown_fields)] pub struct SecurityInsightsVersion100YamlSchemaDependenciesSbomItem { ///Description of how the SBOM is created. Maximum length 560 characters. - #[serde(rename = "sbom-creation", default, skip_serializing_if = "Option::is_none")] - pub sbom_creation: Option< - SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation, - >, + #[serde( + rename = "sbom-creation", + default, + skip_serializing_if = "Option::is_none" + )] + pub sbom_creation: Option, ///Link to the SBOM file. #[serde(rename = "sbom-file", default, skip_serializing_if = "Option::is_none")] pub sbom_file: Option, ///Name of the SBOM standard used. - #[serde(rename = "sbom-format", default, skip_serializing_if = "Option::is_none")] + #[serde( + rename = "sbom-format", + default, + skip_serializing_if = "Option::is_none" + )] pub sbom_format: Option, ///Link to the SBOM standard website or documentation. #[serde(rename = "sbom-url", default, skip_serializing_if = "Option::is_none")] pub sbom_url: Option, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaDependenciesSbomItem { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaDependenciesSbomItem { fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchemaDependenciesSbomItem { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaDependenciesSbomItem { + #[must_use] + pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaDependenciesSbomItem { builder::SecurityInsightsVersion100YamlSchemaDependenciesSbomItem::default() } } ///Description of how the SBOM is created. Maximum length 560 characters. #[derive( - Clone, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, - schemars::JsonSchema, - ToSchema + Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, schemars::JsonSchema, ToSchema, )] pub struct SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation(String); -impl std::ops::Deref -for SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation { +impl std::ops::Deref for SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation { type Target = String; fn deref(&self) -> &String { &self.0 } } -impl From -for String { - fn from( - value: SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation, - ) -> Self { +impl From for String { + fn from(value: SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation) -> Self { value.0 } } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation { + fn from(value: &Self) -> Self { value.clone() } } -impl std::str::FromStr -for SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation { +impl std::str::FromStr for SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation { type Err = &'static str; fn from_str(value: &str) -> Result { - if regress::Regex::new("^(.|\\n){1,560}$").unwrap().find(value).is_none() { + if regress::Regex::new("^(.|\\n){1,560}$") + .unwrap() + .find(value) + .is_none() + { return Err("doesn't match pattern \"^(.|\\n){1,560}$\""); } Ok(Self(value.to_string())) } } impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation { + for SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation +{ type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation { + for SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation { + for SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation +{ type Error = &'static str; fn try_from(value: String) -> Result { value.parse() } } impl<'de> serde::Deserialize<'de> -for SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation { + for SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation +{ fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { String::deserialize(deserializer)? .parse() - .map_err(|e: &'static str| { - ::custom(e.to_string()) - }) + .map_err(|e: &'static str| ::custom(e.to_string())) } } #[derive(Clone, Debug, Deserialize, Serialize, schemars::JsonSchema, ToSchema)] @@ -682,16 +663,28 @@ pub struct SecurityInsightsVersion100YamlSchemaHeader { #[serde(default, skip_serializing_if = "Option::is_none")] pub changelog: Option, ///The last commit to which the SECURITY-INSIGHTS.yml refers. - #[serde(rename = "commit-hash", default, skip_serializing_if = "Option::is_none")] + #[serde( + rename = "commit-hash", + default, + skip_serializing_if = "Option::is_none" + )] pub commit_hash: Option, ///Expiration date for the SECURITY-INSIGHTS.yml. At most a year later the `last-reviewed` date. #[serde(rename = "expiration-date")] pub expiration_date: chrono::DateTime, ///Last time the SECURITY-INSIGHTS.yml was reviewed. Updating this property requires updating the property `commit-hash`. - #[serde(rename = "last-reviewed", default, skip_serializing_if = "Option::is_none")] + #[serde( + rename = "last-reviewed", + default, + skip_serializing_if = "Option::is_none" + )] pub last_reviewed: Option>, ///Last time the SECURITY-INSIGHTS.yml was updated, excluding the properties `commit-hash` and `last-reviewed`. - #[serde(rename = "last-updated", default, skip_serializing_if = "Option::is_none")] + #[serde( + rename = "last-updated", + default, + skip_serializing_if = "Option::is_none" + )] pub last_updated: Option>, ///Link to the project license. #[serde(default, skip_serializing_if = "Option::is_none")] @@ -710,29 +703,20 @@ pub struct SecurityInsightsVersion100YamlSchemaHeader { #[serde(rename = "schema-version")] pub schema_version: SecurityInsightsVersion100YamlSchemaHeaderSchemaVersion, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaHeader { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaHeader { fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchemaHeader { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaHeader { + #[must_use] + pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaHeader { builder::SecurityInsightsVersion100YamlSchemaHeader::default() } } ///The last commit to which the SECURITY-INSIGHTS.yml refers. #[derive( - Clone, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, - schemars::JsonSchema, - ToSchema + Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, schemars::JsonSchema, ToSchema, )] pub struct SecurityInsightsVersion100YamlSchemaHeaderCommitHash(String); impl std::ops::Deref for SecurityInsightsVersion100YamlSchemaHeaderCommitHash { @@ -746,8 +730,7 @@ impl From for String { value.0 } } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaHeaderCommitHash { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaHeaderCommitHash { fn from(value: &Self) -> Self { value.clone() } @@ -755,44 +738,42 @@ for SecurityInsightsVersion100YamlSchemaHeaderCommitHash { impl std::str::FromStr for SecurityInsightsVersion100YamlSchemaHeaderCommitHash { type Err = &'static str; fn from_str(value: &str) -> Result { - if regress::Regex::new("^\\b[0-9a-f]{5,40}\\b$").unwrap().find(value).is_none() { + if regress::Regex::new("^\\b[0-9a-f]{5,40}\\b$") + .unwrap() + .find(value) + .is_none() + { return Err("doesn't match pattern \"^\\b[0-9a-f]{5,40}\\b$\""); } Ok(Self(value.to_string())) } } -impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaHeaderCommitHash { +impl std::convert::TryFrom<&str> for SecurityInsightsVersion100YamlSchemaHeaderCommitHash { type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } -impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaHeaderCommitHash { +impl std::convert::TryFrom<&String> for SecurityInsightsVersion100YamlSchemaHeaderCommitHash { type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } -impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaHeaderCommitHash { +impl std::convert::TryFrom for SecurityInsightsVersion100YamlSchemaHeaderCommitHash { type Error = &'static str; fn try_from(value: String) -> Result { value.parse() } } -impl<'de> serde::Deserialize<'de> -for SecurityInsightsVersion100YamlSchemaHeaderCommitHash { +impl<'de> serde::Deserialize<'de> for SecurityInsightsVersion100YamlSchemaHeaderCommitHash { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { String::deserialize(deserializer)? .parse() - .map_err(|e: &'static str| { - ::custom(e.to_string()) - }) + .map_err(|e: &'static str| ::custom(e.to_string())) } } ///Version of the SECURITY-INSIGHTS YAML Schema. @@ -807,14 +788,13 @@ for SecurityInsightsVersion100YamlSchemaHeaderCommitHash { PartialEq, PartialOrd, Serialize, - schemars::JsonSchema + schemars::JsonSchema, )] pub enum SecurityInsightsVersion100YamlSchemaHeaderSchemaVersion { #[serde(rename = "1.0.0")] _100, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaHeaderSchemaVersion { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaHeaderSchemaVersion { fn from(value: &Self) -> Self { value.clone() } @@ -835,22 +815,19 @@ impl std::str::FromStr for SecurityInsightsVersion100YamlSchemaHeaderSchemaVersi } } } -impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaHeaderSchemaVersion { +impl std::convert::TryFrom<&str> for SecurityInsightsVersion100YamlSchemaHeaderSchemaVersion { type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } -impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaHeaderSchemaVersion { +impl std::convert::TryFrom<&String> for SecurityInsightsVersion100YamlSchemaHeaderSchemaVersion { type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } -impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaHeaderSchemaVersion { +impl std::convert::TryFrom for SecurityInsightsVersion100YamlSchemaHeaderSchemaVersion { type Error = &'static str; fn try_from(value: String) -> Result { value.parse() @@ -870,7 +847,11 @@ pub struct SecurityInsightsVersion100YamlSchemaProjectLifecycle { )] pub core_maintainers: Option>, ///Link to the project release cycle. - #[serde(rename = "release-cycle", default, skip_serializing_if = "Option::is_none")] + #[serde( + rename = "release-cycle", + default, + skip_serializing_if = "Option::is_none" + )] pub release_cycle: Option, ///Shortly describe the release process. Maximum length 560 chars. #[serde( @@ -878,105 +859,92 @@ pub struct SecurityInsightsVersion100YamlSchemaProjectLifecycle { default, skip_serializing_if = "Option::is_none" )] - pub release_process: Option< - SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess, - >, + pub release_process: Option, ///Link to the project roadmap. #[serde(default, skip_serializing_if = "Option::is_none")] pub roadmap: Option, ///Define if the project is still active or not. pub status: SecurityInsightsVersion100YamlSchemaProjectLifecycleStatus, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaProjectLifecycle { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaProjectLifecycle { fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchemaProjectLifecycle { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaProjectLifecycle { + #[must_use] + pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaProjectLifecycle { builder::SecurityInsightsVersion100YamlSchemaProjectLifecycle::default() } } ///Shortly describe the release process. Maximum length 560 chars. #[derive( - Clone, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, - schemars::JsonSchema, - ToSchema + Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, schemars::JsonSchema, ToSchema, )] pub struct SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess(String); -impl std::ops::Deref -for SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess { +impl std::ops::Deref for SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess { type Target = String; fn deref(&self) -> &String { &self.0 } } -impl From -for String { - fn from( - value: SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess, - ) -> Self { +impl From for String { + fn from(value: SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess) -> Self { value.0 } } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess { + fn from(value: &Self) -> Self { value.clone() } } -impl std::str::FromStr -for SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess { +impl std::str::FromStr for SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess { type Err = &'static str; fn from_str(value: &str) -> Result { - if regress::Regex::new("^(.|\\n){1,560}$").unwrap().find(value).is_none() { + if regress::Regex::new("^(.|\\n){1,560}$") + .unwrap() + .find(value) + .is_none() + { return Err("doesn't match pattern \"^(.|\\n){1,560}$\""); } Ok(Self(value.to_string())) } } impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess { + for SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess +{ type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess { + for SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess { + for SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess +{ type Error = &'static str; fn try_from(value: String) -> Result { value.parse() } } impl<'de> serde::Deserialize<'de> -for SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess { + for SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess +{ fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { String::deserialize(deserializer)? .parse() - .map_err(|e: &'static str| { - ::custom(e.to_string()) - }) + .map_err(|e: &'static str| ::custom(e.to_string())) } } ///Define if the project is still active or not. @@ -991,7 +959,7 @@ for SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess { PartialEq, PartialOrd, Serialize, - schemars::JsonSchema + schemars::JsonSchema, )] pub enum SecurityInsightsVersion100YamlSchemaProjectLifecycleStatus { #[serde(rename = "active")] @@ -1011,8 +979,7 @@ pub enum SecurityInsightsVersion100YamlSchemaProjectLifecycleStatus { #[serde(rename = "moved")] Moved, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaProjectLifecycleStatus { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaProjectLifecycleStatus { fn from(value: &Self) -> Self { value.clone() } @@ -1047,22 +1014,19 @@ impl std::str::FromStr for SecurityInsightsVersion100YamlSchemaProjectLifecycleS } } } -impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaProjectLifecycleStatus { +impl std::convert::TryFrom<&str> for SecurityInsightsVersion100YamlSchemaProjectLifecycleStatus { type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } -impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaProjectLifecycleStatus { +impl std::convert::TryFrom<&String> for SecurityInsightsVersion100YamlSchemaProjectLifecycleStatus { type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } -impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaProjectLifecycleStatus { +impl std::convert::TryFrom for SecurityInsightsVersion100YamlSchemaProjectLifecycleStatus { type Error = &'static str; fn try_from(value: String) -> Result { value.parse() @@ -1071,29 +1035,34 @@ for SecurityInsightsVersion100YamlSchemaProjectLifecycleStatus { #[derive(Clone, Debug, Deserialize, Serialize, schemars::JsonSchema, ToSchema)] #[serde(deny_unknown_fields)] pub struct SecurityInsightsVersion100YamlSchemaSecurityArtifacts { - #[serde(rename = "other-artifacts", default, skip_serializing_if = "Vec::is_empty")] + #[serde( + rename = "other-artifacts", + default, + skip_serializing_if = "Vec::is_empty" + )] pub other_artifacts: Vec, #[serde( rename = "self-assessment", default, skip_serializing_if = "Option::is_none" )] - pub self_assessment: Option< - SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment, - >, - #[serde(rename = "threat-model", default, skip_serializing_if = "Option::is_none")] - pub threat_model: Option< - SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel, - >, + pub self_assessment: + Option, + #[serde( + rename = "threat-model", + default, + skip_serializing_if = "Option::is_none" + )] + pub threat_model: Option, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaSecurityArtifacts { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaSecurityArtifacts { fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchemaSecurityArtifacts { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaSecurityArtifacts { + #[must_use] + pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaSecurityArtifacts { builder::SecurityInsightsVersion100YamlSchemaSecurityArtifacts::default() } } @@ -1102,109 +1071,103 @@ impl SecurityInsightsVersion100YamlSchemaSecurityArtifacts { pub struct SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment { ///Additional context regarding the security self assessment or its status. Maximum length 560 chars. #[serde(default, skip_serializing_if = "Option::is_none")] - pub comment: Option< - SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment, - >, - #[serde(rename = "evidence-url", default, skip_serializing_if = "Option::is_none")] + pub comment: Option, + #[serde( + rename = "evidence-url", + default, + skip_serializing_if = "Option::is_none" + )] pub evidence_url: Option>, ///Define whether a security self assessment for the project has been created. A false value may be used to add comments regarding the status of the assessment. #[serde(rename = "self-assessment-created")] pub self_assessment_created: bool, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment { + fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment { + #[must_use] + pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment + { builder::SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment::default() } } ///Additional context regarding the security self assessment or its status. Maximum length 560 chars. #[derive( - Clone, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, - schemars::JsonSchema, - ToSchema + Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, schemars::JsonSchema, ToSchema, )] -pub struct SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment( - String, -); +pub struct SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment(String); impl std::ops::Deref -for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment { + for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment +{ type Target = String; fn deref(&self) -> &String { &self.0 } } -impl From -for String { +impl From for String { fn from( value: SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment, ) -> Self { value.0 } } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment { + fn from(value: &Self) -> Self { value.clone() } } impl std::str::FromStr -for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment { + for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment +{ type Err = &'static str; fn from_str(value: &str) -> Result { - if regress::Regex::new("^(.|\\n){1,560}$").unwrap().find(value).is_none() { + if regress::Regex::new("^(.|\\n){1,560}$") + .unwrap() + .find(value) + .is_none() + { return Err("doesn't match pattern \"^(.|\\n){1,560}$\""); } Ok(Self(value.to_string())) } } impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment { + for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment +{ type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment { + for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment { + for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment +{ type Error = &'static str; fn try_from(value: String) -> Result { value.parse() } } impl<'de> serde::Deserialize<'de> -for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment { + for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment +{ fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { String::deserialize(deserializer)? .parse() - .map_err(|e: &'static str| { - ::custom(e.to_string()) - }) + .map_err(|e: &'static str| ::custom(e.to_string())) } } #[derive(Clone, Debug, Deserialize, Serialize, schemars::JsonSchema, ToSchema)] @@ -1212,109 +1175,98 @@ for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment { pub struct SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel { ///Additional comment to describe the threat models, giving more context. Maximum length 560 chars. #[serde(default, skip_serializing_if = "Option::is_none")] - pub comment: Option< - SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment, - >, - #[serde(rename = "evidence-url", default, skip_serializing_if = "Option::is_none")] + pub comment: Option, + #[serde( + rename = "evidence-url", + default, + skip_serializing_if = "Option::is_none" + )] pub evidence_url: Option>, ///Define if the threat model for the project has been created. #[serde(rename = "threat-model-created")] pub threat_model_created: bool, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel { + fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel { + #[must_use] + pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel { builder::SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel::default() } } ///Additional comment to describe the threat models, giving more context. Maximum length 560 chars. #[derive( - Clone, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, - schemars::JsonSchema, - ToSchema + Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, schemars::JsonSchema, ToSchema, )] -pub struct SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment( - String, -); -impl std::ops::Deref -for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment { +pub struct SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment(String); +impl std::ops::Deref for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment { type Target = String; fn deref(&self) -> &String { &self.0 } } -impl From -for String { +impl From for String { fn from( value: SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment, ) -> Self { value.0 } } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment { + fn from(value: &Self) -> Self { value.clone() } } -impl std::str::FromStr -for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment { +impl std::str::FromStr for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment { type Err = &'static str; fn from_str(value: &str) -> Result { - if regress::Regex::new("^(.|\\n){1,560}$").unwrap().find(value).is_none() { + if regress::Regex::new("^(.|\\n){1,560}$") + .unwrap() + .find(value) + .is_none() + { return Err("doesn't match pattern \"^(.|\\n){1,560}$\""); } Ok(Self(value.to_string())) } } impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment { + for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment +{ type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment { + for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment { + for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment +{ type Error = &'static str; fn try_from(value: String) -> Result { value.parse() } } impl<'de> serde::Deserialize<'de> -for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment { + for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment +{ fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { String::deserialize(deserializer)? .parse() - .map_err(|e: &'static str| { - ::custom(e.to_string()) - }) + .map_err(|e: &'static str| ::custom(e.to_string())) } } #[derive(Clone, Debug, Deserialize, Serialize, schemars::JsonSchema, ToSchema)] @@ -1324,112 +1276,101 @@ pub struct SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem { #[serde(rename = "auditor-name")] pub auditor_name: String, ///Link to the security report provided by the auditor. - #[serde(rename = "auditor-report", default, skip_serializing_if = "Option::is_none")] + #[serde( + rename = "auditor-report", + default, + skip_serializing_if = "Option::is_none" + )] pub auditor_report: Option, ///Link to the auditor website. #[serde(rename = "auditor-url")] pub auditor_url: String, ///Additional comment to describe the report giving more context. Maximum length 560 chars. #[serde(default, skip_serializing_if = "Option::is_none")] - pub comment: Option< - SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment, - >, + pub comment: Option, ///Year of the report. #[serde(rename = "report-year")] pub report_year: i64, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem { + fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem { + #[must_use] + pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem { builder::SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem::default() } } ///Additional comment to describe the report giving more context. Maximum length 560 chars. #[derive( - Clone, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, - schemars::JsonSchema, - ToSchema + Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, schemars::JsonSchema, ToSchema, )] pub struct SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment(String); -impl std::ops::Deref -for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment { +impl std::ops::Deref for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment { type Target = String; fn deref(&self) -> &String { &self.0 } } -impl From -for String { - fn from( - value: SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment, - ) -> Self { +impl From for String { + fn from(value: SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment) -> Self { value.0 } } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment { + fn from(value: &Self) -> Self { value.clone() } } -impl std::str::FromStr -for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment { +impl std::str::FromStr for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment { type Err = &'static str; fn from_str(value: &str) -> Result { - if regress::Regex::new("^(.|\\n){1,560}$").unwrap().find(value).is_none() { + if regress::Regex::new("^(.|\\n){1,560}$") + .unwrap() + .find(value) + .is_none() + { return Err("doesn't match pattern \"^(.|\\n){1,560}$\""); } Ok(Self(value.to_string())) } } impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment { + for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment +{ type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment { + for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment { + for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment +{ type Error = &'static str; fn try_from(value: String) -> Result { value.parse() } } impl<'de> serde::Deserialize<'de> -for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment { + for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment +{ fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { String::deserialize(deserializer)? .parse() - .map_err(|e: &'static str| { - ::custom(e.to_string()) - }) + .map_err(|e: &'static str| ::custom(e.to_string())) } } #[derive(Clone, Debug, Deserialize, Serialize, schemars::JsonSchema, ToSchema)] @@ -1444,14 +1385,14 @@ pub struct SecurityInsightsVersion100YamlSchemaSecurityContactsItem { ///Security contact. pub value: SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaSecurityContactsItem { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaSecurityContactsItem { fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchemaSecurityContactsItem { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaSecurityContactsItem { + #[must_use] + pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaSecurityContactsItem { builder::SecurityInsightsVersion100YamlSchemaSecurityContactsItem::default() } } @@ -1467,7 +1408,7 @@ impl SecurityInsightsVersion100YamlSchemaSecurityContactsItem { PartialEq, PartialOrd, Serialize, - schemars::JsonSchema + schemars::JsonSchema, )] pub enum SecurityInsightsVersion100YamlSchemaSecurityContactsItemType { #[serde(rename = "email")] @@ -1477,11 +1418,8 @@ pub enum SecurityInsightsVersion100YamlSchemaSecurityContactsItemType { #[serde(rename = "url")] Url, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaSecurityContactsItemType { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaSecurityContactsItemType { + fn from(value: &Self) -> Self { value.clone() } } @@ -1505,22 +1443,23 @@ impl std::str::FromStr for SecurityInsightsVersion100YamlSchemaSecurityContactsI } } } -impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaSecurityContactsItemType { +impl std::convert::TryFrom<&str> for SecurityInsightsVersion100YamlSchemaSecurityContactsItemType { type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaSecurityContactsItemType { + for SecurityInsightsVersion100YamlSchemaSecurityContactsItemType +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaSecurityContactsItemType { + for SecurityInsightsVersion100YamlSchemaSecurityContactsItemType +{ type Error = &'static str; fn try_from(value: String) -> Result { value.parse() @@ -1528,16 +1467,7 @@ for SecurityInsightsVersion100YamlSchemaSecurityContactsItemType { } ///Security contact. #[derive( - Clone, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, - schemars::JsonSchema, - ToSchema + Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, schemars::JsonSchema, ToSchema, )] pub struct SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue(String); impl std::ops::Deref for SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue { @@ -1547,30 +1477,24 @@ impl std::ops::Deref for SecurityInsightsVersion100YamlSchemaSecurityContactsIte } } impl From for String { - fn from( - value: SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue, - ) -> Self { + fn from(value: SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue) -> Self { value.0 } } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue { + fn from(value: &Self) -> Self { value.clone() } } -impl std::str::FromStr -for SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue { +impl std::str::FromStr for SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue { type Err = &'static str; fn from_str(value: &str) -> Result { if regress::Regex::new( - "^[\\w+_.-]+@[\\w.-]+$|https?:\\/\\/|[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\\s\\./0-9]*$", - ) - .unwrap() - .find(value) - .is_none() + "^[\\w+_.-]+@[\\w.-]+$|https?:\\/\\/|[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\\s\\./0-9]*$", + ) + .unwrap() + .find(value) + .is_none() { return Err( "doesn't match pattern \"^[\\w+_.-]+@[\\w.-]+$|https?:\\/\\/|[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\\s\\./0-9]*$\"", @@ -1579,38 +1503,38 @@ for SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue { Ok(Self(value.to_string())) } } -impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue { +impl std::convert::TryFrom<&str> for SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue { type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue { + for SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue { + for SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue +{ type Error = &'static str; fn try_from(value: String) -> Result { value.parse() } } impl<'de> serde::Deserialize<'de> -for SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue { + for SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue +{ fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { String::deserialize(deserializer)? .parse() - .map_err(|e: &'static str| { - ::custom(e.to_string()) - }) + .map_err(|e: &'static str| ::custom(e.to_string())) } } #[derive(Clone, Debug, Deserialize, Serialize, schemars::JsonSchema, ToSchema)] @@ -1623,7 +1547,11 @@ pub struct SecurityInsightsVersion100YamlSchemaSecurityTestingItem { ///Name of the tool used to scan or analyze the project. #[serde(rename = "tool-name")] pub tool_name: String, - #[serde(rename = "tool-rulesets", default, skip_serializing_if = "Option::is_none")] + #[serde( + rename = "tool-rulesets", + default, + skip_serializing_if = "Option::is_none" + )] pub tool_rulesets: Option>, ///Type of security test: `sast`, `dast`, `iast`, `fuzzer` or `sca`. #[serde(rename = "tool-type")] @@ -1635,29 +1563,20 @@ pub struct SecurityInsightsVersion100YamlSchemaSecurityTestingItem { #[serde(rename = "tool-version")] pub tool_version: String, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaSecurityTestingItem { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaSecurityTestingItem { fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchemaSecurityTestingItem { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaSecurityTestingItem { + #[must_use] + pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaSecurityTestingItem { builder::SecurityInsightsVersion100YamlSchemaSecurityTestingItem::default() } } ///Additional comment to describe the used tool, giving more context. Maximum length 560 chars. #[derive( - Clone, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, - schemars::JsonSchema, - ToSchema + Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, schemars::JsonSchema, ToSchema, )] pub struct SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment(String); impl std::ops::Deref for SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment { @@ -1667,62 +1586,62 @@ impl std::ops::Deref for SecurityInsightsVersion100YamlSchemaSecurityTestingItem } } impl From for String { - fn from( - value: SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment, - ) -> Self { + fn from(value: SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment) -> Self { value.0 } } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment { + fn from(value: &Self) -> Self { value.clone() } } -impl std::str::FromStr -for SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment { +impl std::str::FromStr for SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment { type Err = &'static str; fn from_str(value: &str) -> Result { - if regress::Regex::new("^(.|\\n){1,560}$").unwrap().find(value).is_none() { + if regress::Regex::new("^(.|\\n){1,560}$") + .unwrap() + .find(value) + .is_none() + { return Err("doesn't match pattern \"^(.|\\n){1,560}$\""); } Ok(Self(value.to_string())) } } impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment { + for SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment +{ type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment { + for SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment { + for SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment +{ type Error = &'static str; fn try_from(value: String) -> Result { value.parse() } } impl<'de> serde::Deserialize<'de> -for SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment { + for SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment +{ fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { String::deserialize(deserializer)? .parse() - .map_err(|e: &'static str| { - ::custom(e.to_string()) - }) + .map_err(|e: &'static str| ::custom(e.to_string())) } } #[derive(Clone, Debug, Deserialize, Serialize, schemars::JsonSchema, ToSchema)] @@ -1737,16 +1656,15 @@ pub struct SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration { ///Define if the security test is part of the CI. pub ci: bool, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration { + fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration { + #[must_use] + pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration + { builder::SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration::default() } } @@ -1762,7 +1680,7 @@ impl SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration { PartialEq, PartialOrd, Serialize, - schemars::JsonSchema + schemars::JsonSchema, )] pub enum SecurityInsightsVersion100YamlSchemaSecurityTestingItemToolType { #[serde(rename = "sast")] @@ -1776,11 +1694,8 @@ pub enum SecurityInsightsVersion100YamlSchemaSecurityTestingItemToolType { #[serde(rename = "sca")] Sca, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaSecurityTestingItemToolType { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaSecurityTestingItemToolType { + fn from(value: &Self) -> Self { value.clone() } } @@ -1795,8 +1710,7 @@ impl ToString for SecurityInsightsVersion100YamlSchemaSecurityTestingItemToolTyp } } } -impl std::str::FromStr -for SecurityInsightsVersion100YamlSchemaSecurityTestingItemToolType { +impl std::str::FromStr for SecurityInsightsVersion100YamlSchemaSecurityTestingItemToolType { type Err = &'static str; fn from_str(value: &str) -> Result { match value { @@ -1810,21 +1724,24 @@ for SecurityInsightsVersion100YamlSchemaSecurityTestingItemToolType { } } impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaSecurityTestingItemToolType { + for SecurityInsightsVersion100YamlSchemaSecurityTestingItemToolType +{ type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaSecurityTestingItemToolType { + for SecurityInsightsVersion100YamlSchemaSecurityTestingItemToolType +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaSecurityTestingItemToolType { + for SecurityInsightsVersion100YamlSchemaSecurityTestingItemToolType +{ type Error = &'static str; fn try_from(value: String) -> Result { value.parse() @@ -1844,31 +1761,33 @@ pub struct SecurityInsightsVersion100YamlSchemaVulnerabilityReporting { )] pub bug_bounty_available: Option, ///Link to the bug bounty program. - #[serde(rename = "bug-bounty-url", default, skip_serializing_if = "Option::is_none")] + #[serde( + rename = "bug-bounty-url", + default, + skip_serializing_if = "Option::is_none" + )] pub bug_bounty_url: Option, ///Additional comment to describe the in-scope list, out-scope list, preferred contact method, or other context. Maximum length 560 chars. #[serde(default, skip_serializing_if = "Option::is_none")] - pub comment: Option< - SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment, - >, + pub comment: Option, ///E-mail contact to report vulnerabilities or other related information. - #[serde(rename = "email-contact", default, skip_serializing_if = "Option::is_none")] + #[serde( + rename = "email-contact", + default, + skip_serializing_if = "Option::is_none" + )] pub email_contact: Option, ///In-scope vulnerability categories, according to OWASP Top 10 2021. It is recommended to specify a better in-scope list in the security policy. #[serde(rename = "in-scope", default, skip_serializing_if = "Option::is_none")] - pub in_scope: Option< - Vec, - >, + pub in_scope: + Option>, ///Out-of-scope vulnerability categories, according to OWASP Top 10 2021. It is recommended to specify a better out-of-scope list in the security policy. #[serde(rename = "out-scope", default, skip_serializing_if = "Option::is_none")] - pub out_scope: Option< - Vec, - >, + pub out_scope: + Option>, ///PGP Public Key. #[serde(rename = "pgp-key", default, skip_serializing_if = "Option::is_none")] - pub pgp_key: Option< - SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey, - >, + pub pgp_key: Option, ///Link to the security policy. #[serde( rename = "security-policy", @@ -1877,95 +1796,85 @@ pub struct SecurityInsightsVersion100YamlSchemaVulnerabilityReporting { )] pub security_policy: Option, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaVulnerabilityReporting { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaVulnerabilityReporting { fn from(value: &Self) -> Self { value.clone() } } impl SecurityInsightsVersion100YamlSchemaVulnerabilityReporting { - #[must_use] pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaVulnerabilityReporting { + #[must_use] + pub fn builder() -> builder::SecurityInsightsVersion100YamlSchemaVulnerabilityReporting { builder::SecurityInsightsVersion100YamlSchemaVulnerabilityReporting::default() } } ///Additional comment to describe the in-scope list, out-scope list, preferred contact method, or other context. Maximum length 560 chars. #[derive( - Clone, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, - schemars::JsonSchema, - ToSchema + Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, schemars::JsonSchema, ToSchema, )] pub struct SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment(String); -impl std::ops::Deref -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment { +impl std::ops::Deref for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment { type Target = String; fn deref(&self) -> &String { &self.0 } } impl From for String { - fn from( - value: SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment, - ) -> Self { + fn from(value: SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment) -> Self { value.0 } } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment { + fn from(value: &Self) -> Self { value.clone() } } -impl std::str::FromStr -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment { +impl std::str::FromStr for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment { type Err = &'static str; fn from_str(value: &str) -> Result { - if regress::Regex::new("^(.|\\n){1,560}$").unwrap().find(value).is_none() { + if regress::Regex::new("^(.|\\n){1,560}$") + .unwrap() + .find(value) + .is_none() + { return Err("doesn't match pattern \"^(.|\\n){1,560}$\""); } Ok(Self(value.to_string())) } } impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment { + for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment +{ type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment { + for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment { + for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment +{ type Error = &'static str; fn try_from(value: String) -> Result { value.parse() } } impl<'de> serde::Deserialize<'de> -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment { + for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment +{ fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { String::deserialize(deserializer)? .parse() - .map_err(|e: &'static str| { - ::custom(e.to_string()) - }) + .map_err(|e: &'static str| ::custom(e.to_string())) } } #[derive( @@ -1979,7 +1888,7 @@ for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment { PartialEq, PartialOrd, Serialize, - schemars::JsonSchema + schemars::JsonSchema, )] pub enum SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInScopeItem { #[serde(rename = "broken access control")] @@ -2005,11 +1914,8 @@ pub enum SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInScopeItem { #[serde(rename = "other")] Other, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInScopeItem { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInScopeItem { + fn from(value: &Self) -> Self { value.clone() } } @@ -2038,8 +1944,7 @@ impl ToString for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInSc } } } -impl std::str::FromStr -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInScopeItem { +impl std::str::FromStr for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInScopeItem { type Err = &'static str; fn from_str(value: &str) -> Result { match value { @@ -2048,15 +1953,11 @@ for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInScopeItem { "injection" => Ok(Self::Injection), "insecure design" => Ok(Self::InsecureDesign), "security misconfiguration" => Ok(Self::SecurityMisconfiguration), - "vulnerable and outdated components" => { - Ok(Self::VulnerableAndOutdatedComponents) - } + "vulnerable and outdated components" => Ok(Self::VulnerableAndOutdatedComponents), "identification and authentication failures" => { Ok(Self::IdentificationAndAuthenticationFailures) } - "software and data integrity failures" => { - Ok(Self::SoftwareAndDataIntegrityFailures) - } + "software and data integrity failures" => Ok(Self::SoftwareAndDataIntegrityFailures), "security logging and monitoring failures" => { Ok(Self::SecurityLoggingAndMonitoringFailures) } @@ -2067,21 +1968,24 @@ for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInScopeItem { } } impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInScopeItem { + for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInScopeItem +{ type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInScopeItem { + for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInScopeItem +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInScopeItem { + for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInScopeItem +{ type Error = &'static str; fn try_from(value: String) -> Result { value.parse() @@ -2098,7 +2002,7 @@ for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInScopeItem { PartialEq, PartialOrd, Serialize, - schemars::JsonSchema + schemars::JsonSchema, )] pub enum SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem { #[serde(rename = "broken access control")] @@ -2124,16 +2028,12 @@ pub enum SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem #[serde(rename = "other")] Other, } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem { + fn from(value: &Self) -> Self { value.clone() } } -impl ToString -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem { +impl ToString for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem { fn to_string(&self) -> String { match *self { Self::BrokenAccessControl => "broken access control".to_string(), @@ -2158,8 +2058,7 @@ for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem { } } } -impl std::str::FromStr -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem { +impl std::str::FromStr for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem { type Err = &'static str; fn from_str(value: &str) -> Result { match value { @@ -2168,15 +2067,11 @@ for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem { "injection" => Ok(Self::Injection), "insecure design" => Ok(Self::InsecureDesign), "security misconfiguration" => Ok(Self::SecurityMisconfiguration), - "vulnerable and outdated components" => { - Ok(Self::VulnerableAndOutdatedComponents) - } + "vulnerable and outdated components" => Ok(Self::VulnerableAndOutdatedComponents), "identification and authentication failures" => { Ok(Self::IdentificationAndAuthenticationFailures) } - "software and data integrity failures" => { - Ok(Self::SoftwareAndDataIntegrityFailures) - } + "software and data integrity failures" => Ok(Self::SoftwareAndDataIntegrityFailures), "security logging and monitoring failures" => { Ok(Self::SecurityLoggingAndMonitoringFailures) } @@ -2187,64 +2082,51 @@ for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem { } } impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem { + for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem +{ type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem { + for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem { + for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem +{ type Error = &'static str; fn try_from(value: String) -> Result { - value.parse() - } -} -///PGP Public Key. -#[derive( - Clone, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, - schemars::JsonSchema, - ToSchema + value.parse() + } +} +///PGP Public Key. +#[derive( + Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, schemars::JsonSchema, ToSchema, )] pub struct SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey(String); -impl std::ops::Deref -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey { +impl std::ops::Deref for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey { type Target = String; fn deref(&self) -> &String { &self.0 } } impl From for String { - fn from( - value: SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey, - ) -> Self { + fn from(value: SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey) -> Self { value.0 } } -impl From<&Self> -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey { - fn from( - value: &Self, - ) -> Self { +impl From<&Self> for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey { + fn from(value: &Self) -> Self { value.clone() } } -impl std::str::FromStr -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey { +impl std::str::FromStr for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey { type Err = &'static str; fn from_str(value: &str) -> Result { if regress::Regex::new( @@ -2262,103 +2144,81 @@ for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey { } } impl std::convert::TryFrom<&str> -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey { + for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey +{ type Error = &'static str; fn try_from(value: &str) -> Result { value.parse() } } impl std::convert::TryFrom<&String> -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey { + for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey +{ type Error = &'static str; fn try_from(value: &String) -> Result { value.parse() } } impl std::convert::TryFrom -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey { + for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey +{ type Error = &'static str; fn try_from(value: String) -> Result { value.parse() } } impl<'de> serde::Deserialize<'de> -for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey { + for SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey +{ fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { String::deserialize(deserializer)? .parse() - .map_err(|e: &'static str| { - ::custom(e.to_string()) - }) + .map_err(|e: &'static str| ::custom(e.to_string())) } } pub mod builder { #[derive(Clone, Debug)] pub struct SecurityInsightsVersion100YamlSchema { - contribution_policy: Result< - super::SecurityInsightsVersion100YamlSchemaContributionPolicy, - String, - >, - dependencies: Result< - Option, - String, - >, + contribution_policy: + Result, + dependencies: + Result, String>, distribution_points: Result, String>, documentation: Result>, String>, header: Result, - project_lifecycle: Result< - super::SecurityInsightsVersion100YamlSchemaProjectLifecycle, - String, - >, - security_artifacts: Result< - Option, - String, - >, + project_lifecycle: + Result, + security_artifacts: + Result, String>, security_assessments: Result< - Option< - Vec, - >, - String, - >, - security_contacts: Result< - Vec, - String, - >, - security_testing: Result< - Vec, - String, - >, - vulnerability_reporting: Result< - super::SecurityInsightsVersion100YamlSchemaVulnerabilityReporting, + Option>, String, >, + security_contacts: + Result, String>, + security_testing: + Result, String>, + vulnerability_reporting: + Result, } impl Default for SecurityInsightsVersion100YamlSchema { fn default() -> Self { Self { - contribution_policy: Err( - "no value supplied for contribution_policy".to_string(), - ), + contribution_policy: Err("no value supplied for contribution_policy".to_string()), dependencies: Ok(Default::default()), - distribution_points: Err( - "no value supplied for distribution_points".to_string(), - ), + distribution_points: Err("no value supplied for distribution_points".to_string()), documentation: Ok(Default::default()), header: Err("no value supplied for header".to_string()), - project_lifecycle: Err( - "no value supplied for project_lifecycle".to_string(), - ), + project_lifecycle: Err("no value supplied for project_lifecycle".to_string()), security_artifacts: Ok(Default::default()), security_assessments: Ok(Default::default()), - security_contacts: Err( - "no value supplied for security_contacts".to_string(), - ), + security_contacts: Err("no value supplied for security_contacts".to_string()), security_testing: Ok(Default::default()), vulnerability_reporting: Err( - "no value supplied for vulnerability_reporting".to_string(), + "no value supplied for vulnerability_reporting".to_string() ), } } @@ -2366,19 +2226,12 @@ pub mod builder { impl SecurityInsightsVersion100YamlSchema { pub fn contribution_policy(mut self, value: T) -> Self where - T: std::convert::TryInto< - super::SecurityInsightsVersion100YamlSchemaContributionPolicy, - >, + T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .contribution_policy = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for contribution_policy: {e}" - ) - }); + self.contribution_policy = value.try_into().map_err(|e| { + format!("error converting supplied value for contribution_policy: {e}") + }); self } pub fn dependencies(mut self, value: T) -> Self @@ -2388,12 +2241,9 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .dependencies = value + self.dependencies = value .try_into() - .map_err(|e| { - format!("error converting supplied value for dependencies: {e}") - }); + .map_err(|e| format!("error converting supplied value for dependencies: {e}")); self } pub fn distribution_points(mut self, value: T) -> Self @@ -2401,14 +2251,9 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .distribution_points = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for distribution_points: {e}" - ) - }); + self.distribution_points = value.try_into().map_err(|e| { + format!("error converting supplied value for distribution_points: {e}") + }); self } pub fn documentation(mut self, value: T) -> Self @@ -2416,12 +2261,9 @@ pub mod builder { T: std::convert::TryInto>>, T::Error: std::fmt::Display, { - self - .documentation = value + self.documentation = value .try_into() - .map_err(|e| { - format!("error converting supplied value for documentation: {e}") - }); + .map_err(|e| format!("error converting supplied value for documentation: {e}")); self } pub fn header(mut self, value: T) -> Self @@ -2429,29 +2271,19 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .header = value + self.header = value .try_into() - .map_err(|e| { - format!("error converting supplied value for header: {e}") - }); + .map_err(|e| format!("error converting supplied value for header: {e}")); self } pub fn project_lifecycle(mut self, value: T) -> Self where - T: std::convert::TryInto< - super::SecurityInsightsVersion100YamlSchemaProjectLifecycle, - >, + T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .project_lifecycle = value + self.project_lifecycle = value .try_into() - .map_err(|e| { - format!( - "error converting supplied value for project_lifecycle: {e}" - ) - }); + .map_err(|e| format!("error converting supplied value for project_lifecycle: {e}")); self } pub fn security_artifacts(mut self, value: T) -> Self @@ -2461,35 +2293,21 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .security_artifacts = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for security_artifacts: {e}" - ) - }); + self.security_artifacts = value.try_into().map_err(|e| { + format!("error converting supplied value for security_artifacts: {e}") + }); self } pub fn security_assessments(mut self, value: T) -> Self where T: std::convert::TryInto< - Option< - Vec< - super::SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem, - >, - >, + Option>, >, T::Error: std::fmt::Display, { - self - .security_assessments = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for security_assessments: {e}" - ) - }); + self.security_assessments = value.try_into().map_err(|e| { + format!("error converting supplied value for security_assessments: {e}") + }); self } pub fn security_contacts(mut self, value: T) -> Self @@ -2499,14 +2317,9 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .security_contacts = value + self.security_contacts = value .try_into() - .map_err(|e| { - format!( - "error converting supplied value for security_contacts: {e}" - ) - }); + .map_err(|e| format!("error converting supplied value for security_contacts: {e}")); self } pub fn security_testing(mut self, value: T) -> Self @@ -2516,14 +2329,9 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .security_testing = value + self.security_testing = value .try_into() - .map_err(|e| { - format!( - "error converting supplied value for security_testing: {e}" - ) - }); + .map_err(|e| format!("error converting supplied value for security_testing: {e}")); self } pub fn vulnerability_reporting(mut self, value: T) -> Self @@ -2533,23 +2341,17 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .vulnerability_reporting = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for vulnerability_reporting: {e}" - ) - }); + self.vulnerability_reporting = value.try_into().map_err(|e| { + format!("error converting supplied value for vulnerability_reporting: {e}") + }); self } } impl std::convert::TryFrom - for super::SecurityInsightsVersion100YamlSchema { + for super::SecurityInsightsVersion100YamlSchema + { type Error = String; - fn try_from( - value: SecurityInsightsVersion100YamlSchema, - ) -> Result { + fn try_from(value: SecurityInsightsVersion100YamlSchema) -> Result { Ok(Self { contribution_policy: value.contribution_policy?, dependencies: value.dependencies?, @@ -2565,8 +2367,7 @@ pub mod builder { }) } } - impl From - for SecurityInsightsVersion100YamlSchema { + impl From for SecurityInsightsVersion100YamlSchema { fn from(value: super::SecurityInsightsVersion100YamlSchema) -> Self { Self { contribution_policy: Ok(value.contribution_policy), @@ -2605,7 +2406,7 @@ pub mod builder { "no value supplied for accepts_automated_pull_requests".to_string(), ), accepts_pull_requests: Err( - "no value supplied for accepts_pull_requests".to_string(), + "no value supplied for accepts_pull_requests".to_string() ), automated_tools_list: Ok(Default::default()), code_of_conduct: Ok(Default::default()), @@ -2619,14 +2420,9 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .accepts_automated_pull_requests = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for accepts_automated_pull_requests: {e}" - ) - }); + self.accepts_automated_pull_requests = value.try_into().map_err(|e| { + format!("error converting supplied value for accepts_automated_pull_requests: {e}") + }); self } pub fn accepts_pull_requests(mut self, value: T) -> Self @@ -2634,14 +2430,9 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .accepts_pull_requests = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for accepts_pull_requests: {e}" - ) - }); + self.accepts_pull_requests = value.try_into().map_err(|e| { + format!("error converting supplied value for accepts_pull_requests: {e}") + }); self } pub fn automated_tools_list(mut self, value: T) -> Self @@ -2655,14 +2446,9 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .automated_tools_list = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for automated_tools_list: {e}" - ) - }); + self.automated_tools_list = value.try_into().map_err(|e| { + format!("error converting supplied value for automated_tools_list: {e}") + }); self } pub fn code_of_conduct(mut self, value: T) -> Self @@ -2670,12 +2456,9 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .code_of_conduct = value + self.code_of_conduct = value .try_into() - .map_err(|e| { - format!("error converting supplied value for code_of_conduct: {e}") - }); + .map_err(|e| format!("error converting supplied value for code_of_conduct: {e}")); self } pub fn contributing_policy(mut self, value: T) -> Self @@ -2683,19 +2466,15 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .contributing_policy = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for contributing_policy: {e}" - ) - }); + self.contributing_policy = value.try_into().map_err(|e| { + format!("error converting supplied value for contributing_policy: {e}") + }); self } } impl std::convert::TryFrom - for super::SecurityInsightsVersion100YamlSchemaContributionPolicy { + for super::SecurityInsightsVersion100YamlSchemaContributionPolicy + { type Error = String; fn try_from( value: SecurityInsightsVersion100YamlSchemaContributionPolicy, @@ -2710,14 +2489,11 @@ pub mod builder { } } impl From - for SecurityInsightsVersion100YamlSchemaContributionPolicy { - fn from( - value: super::SecurityInsightsVersion100YamlSchemaContributionPolicy, - ) -> Self { + for SecurityInsightsVersion100YamlSchemaContributionPolicy + { + fn from(value: super::SecurityInsightsVersion100YamlSchemaContributionPolicy) -> Self { Self { - accepts_automated_pull_requests: Ok( - value.accepts_automated_pull_requests, - ), + accepts_automated_pull_requests: Ok(value.accepts_automated_pull_requests), accepts_pull_requests: Ok(value.accepts_pull_requests), automated_tools_list: Ok(value.automated_tools_list), code_of_conduct: Ok(value.code_of_conduct), @@ -2740,8 +2516,7 @@ pub mod builder { >, path: Result>, String>, } - impl Default - for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem { + impl Default for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem { fn default() -> Self { Self { action: Err("no value supplied for action".to_string()), @@ -2759,12 +2534,9 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .action = value + self.action = value .try_into() - .map_err(|e| { - format!("error converting supplied value for action: {e}") - }); + .map_err(|e| format!("error converting supplied value for action: {e}")); self } pub fn automated_tool(mut self, value: T) -> Self @@ -2772,12 +2544,9 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .automated_tool = value + self.automated_tool = value .try_into() - .map_err(|e| { - format!("error converting supplied value for automated_tool: {e}") - }); + .map_err(|e| format!("error converting supplied value for automated_tool: {e}")); self } pub fn comment(mut self, value: T) -> Self @@ -2789,12 +2558,9 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .comment = value + self.comment = value .try_into() - .map_err(|e| { - format!("error converting supplied value for comment: {e}") - }); + .map_err(|e| format!("error converting supplied value for comment: {e}")); self } pub fn path(mut self, value: T) -> Self @@ -2802,17 +2568,17 @@ pub mod builder { T: std::convert::TryInto>>, T::Error: std::fmt::Display, { - self - .path = value + self.path = value .try_into() .map_err(|e| format!("error converting supplied value for path: {e}")); self } } - impl std::convert::TryFrom< - SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem, - > - for super::SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem { + impl + std::convert::TryFrom< + SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem, + > for super::SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem + { type Error = String; fn try_from( value: SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem, @@ -2825,9 +2591,9 @@ pub mod builder { }) } } - impl From< - super::SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem, - > for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem { + impl From + for SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem + { fn from( value: super::SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem, ) -> Self { @@ -2842,16 +2608,12 @@ pub mod builder { #[derive(Clone, Debug)] pub struct SecurityInsightsVersion100YamlSchemaDependencies { dependencies_lifecycle: Result< - Option< - super::SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle, - >, + Option, String, >, dependencies_lists: Result, String>, env_dependencies_policy: Result< - Option< - super::SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy, - >, + Option, String, >, sbom: Result< @@ -2881,14 +2643,9 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .dependencies_lifecycle = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for dependencies_lifecycle: {e}" - ) - }); + self.dependencies_lifecycle = value.try_into().map_err(|e| { + format!("error converting supplied value for dependencies_lifecycle: {e}") + }); self } pub fn dependencies_lists(mut self, value: T) -> Self @@ -2896,14 +2653,9 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .dependencies_lists = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for dependencies_lists: {e}" - ) - }); + self.dependencies_lists = value.try_into().map_err(|e| { + format!("error converting supplied value for dependencies_lists: {e}") + }); self } pub fn env_dependencies_policy(mut self, value: T) -> Self @@ -2915,27 +2667,19 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .env_dependencies_policy = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for env_dependencies_policy: {e}" - ) - }); + self.env_dependencies_policy = value.try_into().map_err(|e| { + format!("error converting supplied value for env_dependencies_policy: {e}") + }); self } pub fn sbom(mut self, value: T) -> Self where T: std::convert::TryInto< - Option< - Vec, - >, + Option>, >, T::Error: std::fmt::Display, { - self - .sbom = value + self.sbom = value .try_into() .map_err(|e| format!("error converting supplied value for sbom: {e}")); self @@ -2945,19 +2689,15 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .third_party_packages = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for third_party_packages: {e}" - ) - }); + self.third_party_packages = value.try_into().map_err(|e| { + format!("error converting supplied value for third_party_packages: {e}") + }); self } } impl std::convert::TryFrom - for super::SecurityInsightsVersion100YamlSchemaDependencies { + for super::SecurityInsightsVersion100YamlSchemaDependencies + { type Error = String; fn try_from( value: SecurityInsightsVersion100YamlSchemaDependencies, @@ -2972,7 +2712,8 @@ pub mod builder { } } impl From - for SecurityInsightsVersion100YamlSchemaDependencies { + for SecurityInsightsVersion100YamlSchemaDependencies + { fn from(value: super::SecurityInsightsVersion100YamlSchemaDependencies) -> Self { Self { dependencies_lifecycle: Ok(value.dependencies_lifecycle), @@ -2993,8 +2734,7 @@ pub mod builder { >, policy_url: Result, String>, } - impl Default - for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle { + impl Default for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle { fn default() -> Self { Self { comment: Ok(Default::default()), @@ -3012,12 +2752,9 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .comment = value + self.comment = value .try_into() - .map_err(|e| { - format!("error converting supplied value for comment: {e}") - }); + .map_err(|e| format!("error converting supplied value for comment: {e}")); self } pub fn policy_url(mut self, value: T) -> Self @@ -3025,18 +2762,16 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .policy_url = value + self.policy_url = value .try_into() - .map_err(|e| { - format!("error converting supplied value for policy_url: {e}") - }); + .map_err(|e| format!("error converting supplied value for policy_url: {e}")); self } } - impl std::convert::TryFrom< - SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle, - > for super::SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle { + impl + std::convert::TryFrom + for super::SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle + { type Error = String; fn try_from( value: SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle, @@ -3047,9 +2782,9 @@ pub mod builder { }) } } - impl From< - super::SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle, - > for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle { + impl From + for SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle + { fn from( value: super::SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle, ) -> Self { @@ -3069,8 +2804,7 @@ pub mod builder { >, policy_url: Result, String>, } - impl Default - for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy { + impl Default for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy { fn default() -> Self { Self { comment: Ok(Default::default()), @@ -3088,12 +2822,9 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .comment = value + self.comment = value .try_into() - .map_err(|e| { - format!("error converting supplied value for comment: {e}") - }); + .map_err(|e| format!("error converting supplied value for comment: {e}")); self } pub fn policy_url(mut self, value: T) -> Self @@ -3101,18 +2832,16 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .policy_url = value + self.policy_url = value .try_into() - .map_err(|e| { - format!("error converting supplied value for policy_url: {e}") - }); + .map_err(|e| format!("error converting supplied value for policy_url: {e}")); self } } - impl std::convert::TryFrom< - SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy, - > for super::SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy { + impl + std::convert::TryFrom + for super::SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy + { type Error = String; fn try_from( value: SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy, @@ -3123,9 +2852,9 @@ pub mod builder { }) } } - impl From< - super::SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy, - > for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy { + impl From + for SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy + { fn from( value: super::SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy, ) -> Self { @@ -3138,9 +2867,7 @@ pub mod builder { #[derive(Clone, Debug)] pub struct SecurityInsightsVersion100YamlSchemaDependenciesSbomItem { sbom_creation: Result< - Option< - super::SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation, - >, + Option, String, >, sbom_file: Result, String>, @@ -3161,18 +2888,13 @@ pub mod builder { pub fn sbom_creation(mut self, value: T) -> Self where T: std::convert::TryInto< - Option< - super::SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation, - >, + Option, >, T::Error: std::fmt::Display, { - self - .sbom_creation = value + self.sbom_creation = value .try_into() - .map_err(|e| { - format!("error converting supplied value for sbom_creation: {e}") - }); + .map_err(|e| format!("error converting supplied value for sbom_creation: {e}")); self } pub fn sbom_file(mut self, value: T) -> Self @@ -3180,12 +2902,9 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .sbom_file = value + self.sbom_file = value .try_into() - .map_err(|e| { - format!("error converting supplied value for sbom_file: {e}") - }); + .map_err(|e| format!("error converting supplied value for sbom_file: {e}")); self } pub fn sbom_format(mut self, value: T) -> Self @@ -3193,12 +2912,9 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .sbom_format = value + self.sbom_format = value .try_into() - .map_err(|e| { - format!("error converting supplied value for sbom_format: {e}") - }); + .map_err(|e| format!("error converting supplied value for sbom_format: {e}")); self } pub fn sbom_url(mut self, value: T) -> Self @@ -3206,17 +2922,15 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .sbom_url = value + self.sbom_url = value .try_into() - .map_err(|e| { - format!("error converting supplied value for sbom_url: {e}") - }); + .map_err(|e| format!("error converting supplied value for sbom_url: {e}")); self } } impl std::convert::TryFrom - for super::SecurityInsightsVersion100YamlSchemaDependenciesSbomItem { + for super::SecurityInsightsVersion100YamlSchemaDependenciesSbomItem + { type Error = String; fn try_from( value: SecurityInsightsVersion100YamlSchemaDependenciesSbomItem, @@ -3230,10 +2944,9 @@ pub mod builder { } } impl From - for SecurityInsightsVersion100YamlSchemaDependenciesSbomItem { - fn from( - value: super::SecurityInsightsVersion100YamlSchemaDependenciesSbomItem, - ) -> Self { + for SecurityInsightsVersion100YamlSchemaDependenciesSbomItem + { + fn from(value: super::SecurityInsightsVersion100YamlSchemaDependenciesSbomItem) -> Self { Self { sbom_creation: Ok(value.sbom_creation), sbom_file: Ok(value.sbom_file), @@ -3245,29 +2958,23 @@ pub mod builder { #[derive(Clone, Debug)] pub struct SecurityInsightsVersion100YamlSchemaHeader { changelog: Result, String>, - commit_hash: Result< - Option, - String, - >, + commit_hash: + Result, String>, expiration_date: Result, String>, last_reviewed: Result>, String>, last_updated: Result>, String>, license: Result, String>, project_release: Result, String>, project_url: Result, - schema_version: Result< - super::SecurityInsightsVersion100YamlSchemaHeaderSchemaVersion, - String, - >, + schema_version: + Result, } impl Default for SecurityInsightsVersion100YamlSchemaHeader { fn default() -> Self { Self { changelog: Ok(Default::default()), commit_hash: Ok(Default::default()), - expiration_date: Err( - "no value supplied for expiration_date".to_string(), - ), + expiration_date: Err("no value supplied for expiration_date".to_string()), last_reviewed: Ok(Default::default()), last_updated: Ok(Default::default()), license: Ok(Default::default()), @@ -3283,12 +2990,9 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .changelog = value + self.changelog = value .try_into() - .map_err(|e| { - format!("error converting supplied value for changelog: {e}") - }); + .map_err(|e| format!("error converting supplied value for changelog: {e}")); self } pub fn commit_hash(mut self, value: T) -> Self @@ -3298,12 +3002,9 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .commit_hash = value + self.commit_hash = value .try_into() - .map_err(|e| { - format!("error converting supplied value for commit_hash: {e}") - }); + .map_err(|e| format!("error converting supplied value for commit_hash: {e}")); self } pub fn expiration_date(mut self, value: T) -> Self @@ -3311,12 +3012,9 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .expiration_date = value + self.expiration_date = value .try_into() - .map_err(|e| { - format!("error converting supplied value for expiration_date: {e}") - }); + .map_err(|e| format!("error converting supplied value for expiration_date: {e}")); self } pub fn last_reviewed(mut self, value: T) -> Self @@ -3324,12 +3022,9 @@ pub mod builder { T: std::convert::TryInto>>, T::Error: std::fmt::Display, { - self - .last_reviewed = value + self.last_reviewed = value .try_into() - .map_err(|e| { - format!("error converting supplied value for last_reviewed: {e}") - }); + .map_err(|e| format!("error converting supplied value for last_reviewed: {e}")); self } pub fn last_updated(mut self, value: T) -> Self @@ -3337,12 +3032,9 @@ pub mod builder { T: std::convert::TryInto>>, T::Error: std::fmt::Display, { - self - .last_updated = value + self.last_updated = value .try_into() - .map_err(|e| { - format!("error converting supplied value for last_updated: {e}") - }); + .map_err(|e| format!("error converting supplied value for last_updated: {e}")); self } pub fn license(mut self, value: T) -> Self @@ -3350,12 +3042,9 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .license = value + self.license = value .try_into() - .map_err(|e| { - format!("error converting supplied value for license: {e}") - }); + .map_err(|e| format!("error converting supplied value for license: {e}")); self } pub fn project_release(mut self, value: T) -> Self @@ -3363,12 +3052,9 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .project_release = value + self.project_release = value .try_into() - .map_err(|e| { - format!("error converting supplied value for project_release: {e}") - }); + .map_err(|e| format!("error converting supplied value for project_release: {e}")); self } pub fn project_url(mut self, value: T) -> Self @@ -3376,12 +3062,9 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .project_url = value + self.project_url = value .try_into() - .map_err(|e| { - format!("error converting supplied value for project_url: {e}") - }); + .map_err(|e| format!("error converting supplied value for project_url: {e}")); self } pub fn schema_version(mut self, value: T) -> Self @@ -3391,21 +3074,17 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .schema_version = value + self.schema_version = value .try_into() - .map_err(|e| { - format!("error converting supplied value for schema_version: {e}") - }); + .map_err(|e| format!("error converting supplied value for schema_version: {e}")); self } } impl std::convert::TryFrom - for super::SecurityInsightsVersion100YamlSchemaHeader { + for super::SecurityInsightsVersion100YamlSchemaHeader + { type Error = String; - fn try_from( - value: SecurityInsightsVersion100YamlSchemaHeader, - ) -> Result { + fn try_from(value: SecurityInsightsVersion100YamlSchemaHeader) -> Result { Ok(Self { changelog: value.changelog?, commit_hash: value.commit_hash?, @@ -3420,7 +3099,8 @@ pub mod builder { } } impl From - for SecurityInsightsVersion100YamlSchemaHeader { + for SecurityInsightsVersion100YamlSchemaHeader + { fn from(value: super::SecurityInsightsVersion100YamlSchemaHeader) -> Self { Self { changelog: Ok(value.changelog), @@ -3441,16 +3121,11 @@ pub mod builder { core_maintainers: Result>, String>, release_cycle: Result, String>, release_process: Result< - Option< - super::SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess, - >, + Option, String, >, roadmap: Result, String>, - status: Result< - super::SecurityInsightsVersion100YamlSchemaProjectLifecycleStatus, - String, - >, + status: Result, } impl Default for SecurityInsightsVersion100YamlSchemaProjectLifecycle { fn default() -> Self { @@ -3470,12 +3145,9 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .bug_fixes_only = value + self.bug_fixes_only = value .try_into() - .map_err(|e| { - format!("error converting supplied value for bug_fixes_only: {e}") - }); + .map_err(|e| format!("error converting supplied value for bug_fixes_only: {e}")); self } pub fn core_maintainers(mut self, value: T) -> Self @@ -3483,14 +3155,9 @@ pub mod builder { T: std::convert::TryInto>>, T::Error: std::fmt::Display, { - self - .core_maintainers = value + self.core_maintainers = value .try_into() - .map_err(|e| { - format!( - "error converting supplied value for core_maintainers: {e}" - ) - }); + .map_err(|e| format!("error converting supplied value for core_maintainers: {e}")); self } pub fn release_cycle(mut self, value: T) -> Self @@ -3498,29 +3165,21 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .release_cycle = value + self.release_cycle = value .try_into() - .map_err(|e| { - format!("error converting supplied value for release_cycle: {e}") - }); + .map_err(|e| format!("error converting supplied value for release_cycle: {e}")); self } pub fn release_process(mut self, value: T) -> Self where T: std::convert::TryInto< - Option< - super::SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess, - >, + Option, >, T::Error: std::fmt::Display, { - self - .release_process = value + self.release_process = value .try_into() - .map_err(|e| { - format!("error converting supplied value for release_process: {e}") - }); + .map_err(|e| format!("error converting supplied value for release_process: {e}")); self } pub fn roadmap(mut self, value: T) -> Self @@ -3528,12 +3187,9 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .roadmap = value + self.roadmap = value .try_into() - .map_err(|e| { - format!("error converting supplied value for roadmap: {e}") - }); + .map_err(|e| format!("error converting supplied value for roadmap: {e}")); self } pub fn status(mut self, value: T) -> Self @@ -3543,17 +3199,15 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .status = value + self.status = value .try_into() - .map_err(|e| { - format!("error converting supplied value for status: {e}") - }); + .map_err(|e| format!("error converting supplied value for status: {e}")); self } } impl std::convert::TryFrom - for super::SecurityInsightsVersion100YamlSchemaProjectLifecycle { + for super::SecurityInsightsVersion100YamlSchemaProjectLifecycle + { type Error = String; fn try_from( value: SecurityInsightsVersion100YamlSchemaProjectLifecycle, @@ -3569,10 +3223,9 @@ pub mod builder { } } impl From - for SecurityInsightsVersion100YamlSchemaProjectLifecycle { - fn from( - value: super::SecurityInsightsVersion100YamlSchemaProjectLifecycle, - ) -> Self { + for SecurityInsightsVersion100YamlSchemaProjectLifecycle + { + fn from(value: super::SecurityInsightsVersion100YamlSchemaProjectLifecycle) -> Self { Self { bug_fixes_only: Ok(value.bug_fixes_only), core_maintainers: Ok(value.core_maintainers), @@ -3587,15 +3240,11 @@ pub mod builder { pub struct SecurityInsightsVersion100YamlSchemaSecurityArtifacts { other_artifacts: Result, String>, self_assessment: Result< - Option< - super::SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment, - >, + Option, String, >, threat_model: Result< - Option< - super::SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel, - >, + Option, String, >, } @@ -3614,51 +3263,39 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .other_artifacts = value + self.other_artifacts = value .try_into() - .map_err(|e| { - format!("error converting supplied value for other_artifacts: {e}") - }); + .map_err(|e| format!("error converting supplied value for other_artifacts: {e}")); self } pub fn self_assessment(mut self, value: T) -> Self where T: std::convert::TryInto< - Option< - super::SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment, - >, + Option, >, T::Error: std::fmt::Display, { - self - .self_assessment = value + self.self_assessment = value .try_into() - .map_err(|e| { - format!("error converting supplied value for self_assessment: {e}") - }); + .map_err(|e| format!("error converting supplied value for self_assessment: {e}")); self } pub fn threat_model(mut self, value: T) -> Self where T: std::convert::TryInto< - Option< - super::SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel, - >, + Option, >, T::Error: std::fmt::Display, { - self - .threat_model = value + self.threat_model = value .try_into() - .map_err(|e| { - format!("error converting supplied value for threat_model: {e}") - }); + .map_err(|e| format!("error converting supplied value for threat_model: {e}")); self } } impl std::convert::TryFrom - for super::SecurityInsightsVersion100YamlSchemaSecurityArtifacts { + for super::SecurityInsightsVersion100YamlSchemaSecurityArtifacts + { type Error = String; fn try_from( value: SecurityInsightsVersion100YamlSchemaSecurityArtifacts, @@ -3671,10 +3308,9 @@ pub mod builder { } } impl From - for SecurityInsightsVersion100YamlSchemaSecurityArtifacts { - fn from( - value: super::SecurityInsightsVersion100YamlSchemaSecurityArtifacts, - ) -> Self { + for SecurityInsightsVersion100YamlSchemaSecurityArtifacts + { + fn from(value: super::SecurityInsightsVersion100YamlSchemaSecurityArtifacts) -> Self { Self { other_artifacts: Ok(value.other_artifacts), self_assessment: Ok(value.self_assessment), @@ -3693,14 +3329,13 @@ pub mod builder { evidence_url: Result>, String>, self_assessment_created: Result, } - impl Default - for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment { + impl Default for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment { fn default() -> Self { Self { comment: Ok(Default::default()), evidence_url: Ok(Default::default()), self_assessment_created: Err( - "no value supplied for self_assessment_created".to_string(), + "no value supplied for self_assessment_created".to_string() ), } } @@ -3715,12 +3350,9 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .comment = value + self.comment = value .try_into() - .map_err(|e| { - format!("error converting supplied value for comment: {e}") - }); + .map_err(|e| format!("error converting supplied value for comment: {e}")); self } pub fn evidence_url(mut self, value: T) -> Self @@ -3728,12 +3360,9 @@ pub mod builder { T: std::convert::TryInto>>, T::Error: std::fmt::Display, { - self - .evidence_url = value + self.evidence_url = value .try_into() - .map_err(|e| { - format!("error converting supplied value for evidence_url: {e}") - }); + .map_err(|e| format!("error converting supplied value for evidence_url: {e}")); self } pub fn self_assessment_created(mut self, value: T) -> Self @@ -3741,20 +3370,15 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .self_assessment_created = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for self_assessment_created: {e}" - ) - }); + self.self_assessment_created = value.try_into().map_err(|e| { + format!("error converting supplied value for self_assessment_created: {e}") + }); self } } - impl std::convert::TryFrom< - SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment, - > for super::SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment { + impl std::convert::TryFrom + for super::SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment + { type Error = String; fn try_from( value: SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment, @@ -3767,7 +3391,8 @@ pub mod builder { } } impl From - for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment { + for SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment + { fn from( value: super::SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment, ) -> Self { @@ -3781,9 +3406,7 @@ pub mod builder { #[derive(Clone, Debug)] pub struct SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel { comment: Result< - Option< - super::SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment, - >, + Option, String, >, evidence_url: Result>, String>, @@ -3794,9 +3417,7 @@ pub mod builder { Self { comment: Ok(Default::default()), evidence_url: Ok(Default::default()), - threat_model_created: Err( - "no value supplied for threat_model_created".to_string(), - ), + threat_model_created: Err("no value supplied for threat_model_created".to_string()), } } } @@ -3810,12 +3431,9 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .comment = value + self.comment = value .try_into() - .map_err(|e| { - format!("error converting supplied value for comment: {e}") - }); + .map_err(|e| format!("error converting supplied value for comment: {e}")); self } pub fn evidence_url(mut self, value: T) -> Self @@ -3823,12 +3441,9 @@ pub mod builder { T: std::convert::TryInto>>, T::Error: std::fmt::Display, { - self - .evidence_url = value + self.evidence_url = value .try_into() - .map_err(|e| { - format!("error converting supplied value for evidence_url: {e}") - }); + .map_err(|e| format!("error converting supplied value for evidence_url: {e}")); self } pub fn threat_model_created(mut self, value: T) -> Self @@ -3836,20 +3451,15 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .threat_model_created = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for threat_model_created: {e}" - ) - }); + self.threat_model_created = value.try_into().map_err(|e| { + format!("error converting supplied value for threat_model_created: {e}") + }); self } } - impl std::convert::TryFrom< - SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel, - > for super::SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel { + impl std::convert::TryFrom + for super::SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel + { type Error = String; fn try_from( value: SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel, @@ -3862,7 +3472,8 @@ pub mod builder { } } impl From - for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel { + for SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel + { fn from( value: super::SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel, ) -> Self { @@ -3879,9 +3490,7 @@ pub mod builder { auditor_report: Result, String>, auditor_url: Result, comment: Result< - Option< - super::SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment, - >, + Option, String, >, report_year: Result, @@ -3903,12 +3512,9 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .auditor_name = value + self.auditor_name = value .try_into() - .map_err(|e| { - format!("error converting supplied value for auditor_name: {e}") - }); + .map_err(|e| format!("error converting supplied value for auditor_name: {e}")); self } pub fn auditor_report(mut self, value: T) -> Self @@ -3916,12 +3522,9 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .auditor_report = value + self.auditor_report = value .try_into() - .map_err(|e| { - format!("error converting supplied value for auditor_report: {e}") - }); + .map_err(|e| format!("error converting supplied value for auditor_report: {e}")); self } pub fn auditor_url(mut self, value: T) -> Self @@ -3929,29 +3532,21 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .auditor_url = value + self.auditor_url = value .try_into() - .map_err(|e| { - format!("error converting supplied value for auditor_url: {e}") - }); + .map_err(|e| format!("error converting supplied value for auditor_url: {e}")); self } pub fn comment(mut self, value: T) -> Self where T: std::convert::TryInto< - Option< - super::SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment, - >, + Option, >, T::Error: std::fmt::Display, { - self - .comment = value + self.comment = value .try_into() - .map_err(|e| { - format!("error converting supplied value for comment: {e}") - }); + .map_err(|e| format!("error converting supplied value for comment: {e}")); self } pub fn report_year(mut self, value: T) -> Self @@ -3959,18 +3554,15 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .report_year = value + self.report_year = value .try_into() - .map_err(|e| { - format!("error converting supplied value for report_year: {e}") - }); + .map_err(|e| format!("error converting supplied value for report_year: {e}")); self } } - impl std::convert::TryFrom< - SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem, - > for super::SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem { + impl std::convert::TryFrom + for super::SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem + { type Error = String; fn try_from( value: SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem, @@ -3985,10 +3577,9 @@ pub mod builder { } } impl From - for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem { - fn from( - value: super::SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem, - ) -> Self { + for SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem + { + fn from(value: super::SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem) -> Self { Self { auditor_name: Ok(value.auditor_name), auditor_report: Ok(value.auditor_report), @@ -4001,14 +3592,8 @@ pub mod builder { #[derive(Clone, Debug)] pub struct SecurityInsightsVersion100YamlSchemaSecurityContactsItem { primary: Result, String>, - type_: Result< - super::SecurityInsightsVersion100YamlSchemaSecurityContactsItemType, - String, - >, - value: Result< - super::SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue, - String, - >, + type_: Result, + value: Result, } impl Default for SecurityInsightsVersion100YamlSchemaSecurityContactsItem { fn default() -> Self { @@ -4025,12 +3610,9 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .primary = value + self.primary = value .try_into() - .map_err(|e| { - format!("error converting supplied value for primary: {e}") - }); + .map_err(|e| format!("error converting supplied value for primary: {e}")); self } pub fn type_(mut self, value: T) -> Self @@ -4040,12 +3622,9 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .type_ = value + self.type_ = value .try_into() - .map_err(|e| { - format!("error converting supplied value for type_: {e}") - }); + .map_err(|e| format!("error converting supplied value for type_: {e}")); self } pub fn value(mut self, value: T) -> Self @@ -4055,17 +3634,15 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .value = value + self.value = value .try_into() - .map_err(|e| { - format!("error converting supplied value for value: {e}") - }); + .map_err(|e| format!("error converting supplied value for value: {e}")); self } } impl std::convert::TryFrom - for super::SecurityInsightsVersion100YamlSchemaSecurityContactsItem { + for super::SecurityInsightsVersion100YamlSchemaSecurityContactsItem + { type Error = String; fn try_from( value: SecurityInsightsVersion100YamlSchemaSecurityContactsItem, @@ -4078,10 +3655,9 @@ pub mod builder { } } impl From - for SecurityInsightsVersion100YamlSchemaSecurityContactsItem { - fn from( - value: super::SecurityInsightsVersion100YamlSchemaSecurityContactsItem, - ) -> Self { + for SecurityInsightsVersion100YamlSchemaSecurityContactsItem + { + fn from(value: super::SecurityInsightsVersion100YamlSchemaSecurityContactsItem) -> Self { Self { primary: Ok(value.primary), type_: Ok(value.type_), @@ -4092,9 +3668,7 @@ pub mod builder { #[derive(Clone, Debug)] pub struct SecurityInsightsVersion100YamlSchemaSecurityTestingItem { comment: Result< - Option< - super::SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment, - >, + Option, String, >, integration: Result< @@ -4103,10 +3677,8 @@ pub mod builder { >, tool_name: Result, tool_rulesets: Result>, String>, - tool_type: Result< - super::SecurityInsightsVersion100YamlSchemaSecurityTestingItemToolType, - String, - >, + tool_type: + Result, tool_url: Result, String>, tool_version: Result, } @@ -4127,18 +3699,13 @@ pub mod builder { pub fn comment(mut self, value: T) -> Self where T: std::convert::TryInto< - Option< - super::SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment, - >, + Option, >, T::Error: std::fmt::Display, { - self - .comment = value + self.comment = value .try_into() - .map_err(|e| { - format!("error converting supplied value for comment: {e}") - }); + .map_err(|e| format!("error converting supplied value for comment: {e}")); self } pub fn integration(mut self, value: T) -> Self @@ -4148,12 +3715,9 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .integration = value + self.integration = value .try_into() - .map_err(|e| { - format!("error converting supplied value for integration: {e}") - }); + .map_err(|e| format!("error converting supplied value for integration: {e}")); self } pub fn tool_name(mut self, value: T) -> Self @@ -4161,12 +3725,9 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .tool_name = value + self.tool_name = value .try_into() - .map_err(|e| { - format!("error converting supplied value for tool_name: {e}") - }); + .map_err(|e| format!("error converting supplied value for tool_name: {e}")); self } pub fn tool_rulesets(mut self, value: T) -> Self @@ -4174,12 +3735,9 @@ pub mod builder { T: std::convert::TryInto>>, T::Error: std::fmt::Display, { - self - .tool_rulesets = value + self.tool_rulesets = value .try_into() - .map_err(|e| { - format!("error converting supplied value for tool_rulesets: {e}") - }); + .map_err(|e| format!("error converting supplied value for tool_rulesets: {e}")); self } pub fn tool_type(mut self, value: T) -> Self @@ -4189,12 +3747,9 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .tool_type = value + self.tool_type = value .try_into() - .map_err(|e| { - format!("error converting supplied value for tool_type: {e}") - }); + .map_err(|e| format!("error converting supplied value for tool_type: {e}")); self } pub fn tool_url(mut self, value: T) -> Self @@ -4202,12 +3757,9 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .tool_url = value + self.tool_url = value .try_into() - .map_err(|e| { - format!("error converting supplied value for tool_url: {e}") - }); + .map_err(|e| format!("error converting supplied value for tool_url: {e}")); self } pub fn tool_version(mut self, value: T) -> Self @@ -4215,17 +3767,15 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .tool_version = value + self.tool_version = value .try_into() - .map_err(|e| { - format!("error converting supplied value for tool_version: {e}") - }); + .map_err(|e| format!("error converting supplied value for tool_version: {e}")); self } } impl std::convert::TryFrom - for super::SecurityInsightsVersion100YamlSchemaSecurityTestingItem { + for super::SecurityInsightsVersion100YamlSchemaSecurityTestingItem + { type Error = String; fn try_from( value: SecurityInsightsVersion100YamlSchemaSecurityTestingItem, @@ -4242,10 +3792,9 @@ pub mod builder { } } impl From - for SecurityInsightsVersion100YamlSchemaSecurityTestingItem { - fn from( - value: super::SecurityInsightsVersion100YamlSchemaSecurityTestingItem, - ) -> Self { + for SecurityInsightsVersion100YamlSchemaSecurityTestingItem + { + fn from(value: super::SecurityInsightsVersion100YamlSchemaSecurityTestingItem) -> Self { Self { comment: Ok(value.comment), integration: Ok(value.integration), @@ -4278,12 +3827,9 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .ad_hoc = value + self.ad_hoc = value .try_into() - .map_err(|e| { - format!("error converting supplied value for ad_hoc: {e}") - }); + .map_err(|e| format!("error converting supplied value for ad_hoc: {e}")); self } pub fn before_release(mut self, value: T) -> Self @@ -4291,12 +3837,9 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .before_release = value + self.before_release = value .try_into() - .map_err(|e| { - format!("error converting supplied value for before_release: {e}") - }); + .map_err(|e| format!("error converting supplied value for before_release: {e}")); self } pub fn ci(mut self, value: T) -> Self @@ -4304,16 +3847,15 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .ci = value + self.ci = value .try_into() .map_err(|e| format!("error converting supplied value for ci: {e}")); self } } - impl std::convert::TryFrom< - SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration, - > for super::SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration { + impl std::convert::TryFrom + for super::SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration + { type Error = String; fn try_from( value: SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration, @@ -4326,7 +3868,8 @@ pub mod builder { } } impl From - for SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration { + for SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration + { fn from( value: super::SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration, ) -> Self { @@ -4343,32 +3886,24 @@ pub mod builder { bug_bounty_available: Result, String>, bug_bounty_url: Result, String>, comment: Result< - Option< - super::SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment, - >, + Option, String, >, email_contact: Result, String>, in_scope: Result< Option< - Vec< - super::SecurityInsightsVersion100YamlSchemaVulnerabilityReportingInScopeItem, - >, + Vec, >, String, >, out_scope: Result< Option< - Vec< - super::SecurityInsightsVersion100YamlSchemaVulnerabilityReportingOutScopeItem, - >, + Vec, >, String, >, pgp_key: Result< - Option< - super::SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey, - >, + Option, String, >, security_policy: Result, String>, @@ -4396,14 +3931,9 @@ pub mod builder { T: std::convert::TryInto, T::Error: std::fmt::Display, { - self - .accepts_vulnerability_reports = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for accepts_vulnerability_reports: {e}" - ) - }); + self.accepts_vulnerability_reports = value.try_into().map_err(|e| { + format!("error converting supplied value for accepts_vulnerability_reports: {e}") + }); self } pub fn bug_bounty_available(mut self, value: T) -> Self @@ -4411,14 +3941,9 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .bug_bounty_available = value - .try_into() - .map_err(|e| { - format!( - "error converting supplied value for bug_bounty_available: {e}" - ) - }); + self.bug_bounty_available = value.try_into().map_err(|e| { + format!("error converting supplied value for bug_bounty_available: {e}") + }); self } pub fn bug_bounty_url(mut self, value: T) -> Self @@ -4426,29 +3951,21 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .bug_bounty_url = value + self.bug_bounty_url = value .try_into() - .map_err(|e| { - format!("error converting supplied value for bug_bounty_url: {e}") - }); + .map_err(|e| format!("error converting supplied value for bug_bounty_url: {e}")); self } pub fn comment(mut self, value: T) -> Self where T: std::convert::TryInto< - Option< - super::SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment, - >, + Option, >, T::Error: std::fmt::Display, { - self - .comment = value + self.comment = value .try_into() - .map_err(|e| { - format!("error converting supplied value for comment: {e}") - }); + .map_err(|e| format!("error converting supplied value for comment: {e}")); self } pub fn email_contact(mut self, value: T) -> Self @@ -4456,12 +3973,9 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .email_contact = value + self.email_contact = value .try_into() - .map_err(|e| { - format!("error converting supplied value for email_contact: {e}") - }); + .map_err(|e| format!("error converting supplied value for email_contact: {e}")); self } pub fn in_scope(mut self, value: T) -> Self @@ -4475,12 +3989,9 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .in_scope = value + self.in_scope = value .try_into() - .map_err(|e| { - format!("error converting supplied value for in_scope: {e}") - }); + .map_err(|e| format!("error converting supplied value for in_scope: {e}")); self } pub fn out_scope(mut self, value: T) -> Self @@ -4494,29 +4005,21 @@ pub mod builder { >, T::Error: std::fmt::Display, { - self - .out_scope = value + self.out_scope = value .try_into() - .map_err(|e| { - format!("error converting supplied value for out_scope: {e}") - }); + .map_err(|e| format!("error converting supplied value for out_scope: {e}")); self } pub fn pgp_key(mut self, value: T) -> Self where T: std::convert::TryInto< - Option< - super::SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey, - >, + Option, >, T::Error: std::fmt::Display, { - self - .pgp_key = value + self.pgp_key = value .try_into() - .map_err(|e| { - format!("error converting supplied value for pgp_key: {e}") - }); + .map_err(|e| format!("error converting supplied value for pgp_key: {e}")); self } pub fn security_policy(mut self, value: T) -> Self @@ -4524,18 +4027,15 @@ pub mod builder { T: std::convert::TryInto>, T::Error: std::fmt::Display, { - self - .security_policy = value + self.security_policy = value .try_into() - .map_err(|e| { - format!("error converting supplied value for security_policy: {e}") - }); + .map_err(|e| format!("error converting supplied value for security_policy: {e}")); self } } - impl std::convert::TryFrom< - SecurityInsightsVersion100YamlSchemaVulnerabilityReporting, - > for super::SecurityInsightsVersion100YamlSchemaVulnerabilityReporting { + impl std::convert::TryFrom + for super::SecurityInsightsVersion100YamlSchemaVulnerabilityReporting + { type Error = String; fn try_from( value: SecurityInsightsVersion100YamlSchemaVulnerabilityReporting, @@ -4554,10 +4054,9 @@ pub mod builder { } } impl From - for SecurityInsightsVersion100YamlSchemaVulnerabilityReporting { - fn from( - value: super::SecurityInsightsVersion100YamlSchemaVulnerabilityReporting, - ) -> Self { + for SecurityInsightsVersion100YamlSchemaVulnerabilityReporting + { + fn from(value: super::SecurityInsightsVersion100YamlSchemaVulnerabilityReporting) -> Self { Self { accepts_vulnerability_reports: Ok(value.accepts_vulnerability_reports), bug_bounty_available: Ok(value.bug_bounty_available), @@ -4571,4 +4070,4 @@ pub mod builder { } } } -} \ No newline at end of file +} diff --git a/skootrs-model/src/skootrs/facet.rs b/skootrs-model/src/skootrs/facet.rs index 192587b..2cb5c98 100644 --- a/skootrs-model/src/skootrs/facet.rs +++ b/skootrs-model/src/skootrs/facet.rs @@ -20,13 +20,15 @@ #![allow(clippy::module_name_repetitions)] -use std::fmt; +use std::{collections::HashMap, fmt}; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; +use strum::VariantNames; #[cfg(feature = "openapi")] use utoipa::ToSchema; -use super::{InitializedSource, InitializedRepo, InitializedEcosystem}; +use super::{InitializedEcosystem, InitializedRepo, InitializedSource}; +use strum::EnumString; /// Represents a facet that has been initialized. This is an enum of /// the various supported facets like API based, and Source file bundle @@ -34,18 +36,36 @@ use super::{InitializedSource, InitializedRepo, InitializedEcosystem}; #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] pub enum InitializedFacet { + /// (DEPRECATED) A facet that is based on a single source file. SourceFile(SourceFileFacet), + /// A facet that is based on a bundle of source files. SourceBundle(SourceBundleFacet), + /// A facet that is based on one or more API calls. APIBundle(APIBundleFacet), } +impl InitializedFacet { + /// Helper function to get the facet type of the inner facet. + #[must_use] + pub fn facet_type(&self) -> SupportedFacetType { + match self { + Self::SourceFile(facet) => facet.facet_type.clone(), + Self::SourceBundle(facet) => facet.facet_type.clone(), + Self::APIBundle(facet) => facet.facet_type.clone(), + } + } +} + /// Represents the parameters for creating a facet. This should mirror the /// `InitializedFacet` enum. #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] -pub enum FacetParams { +pub enum FacetCreateParams { + /// (DEPRECATED) Params for creating a `SourceFileFacet`. SourceFile(SourceFileFacetParams), - SourceBundle(SourceBundleFacetParams), + /// Params for creating a `SourceBundleFacet`. + SourceBundle(SourceBundleFacetCreateParams), + /// Params for creating a `APIBundleFacet`. APIBundle(APIBundleFacetParams), } @@ -56,8 +76,9 @@ pub enum FacetParams { /// boilerplate code. #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] -pub struct FacetSetParams { - pub facets_params: Vec, +pub struct FacetSetCreateParams { + /// The parameters for each `InitializedFacet` that should be created. + pub facets_params: Vec, } /// Represents the common parameters that are shared across all facets. @@ -65,20 +86,27 @@ pub struct FacetSetParams { /// source, repo, and ecosystem. #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] -pub struct CommonFacetParams { +pub struct CommonFacetCreateParams { + /// The name of the project the facet is being created for. pub project_name: String, + /// The source of the project the facet is being created for. pub source: InitializedSource, + /// The repo of the project the facet is being created for. pub repo: InitializedRepo, + /// The ecosystem of the project the facet is being created for. pub ecosystem: InitializedEcosystem, } -/// (DEPRECATED) Represents a source file facet which is a facet that +/// (DEPRECATED) Represents a source file facet which is a facet that /// is based on a single source file. #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] pub struct SourceFileFacet { + /// The name of the source file. pub name: String, + /// The path of the source file. pub path: String, + /// The type of facet this is. pub facet_type: SupportedFacetType, } @@ -86,7 +114,9 @@ pub struct SourceFileFacet { #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] pub struct SourceFileFacetParams { - pub common: CommonFacetParams, + /// The common parameters for the facet being created. + pub common: CommonFacetCreateParams, + /// The type of facet that is being created. pub facet_type: SupportedFacetType, } @@ -94,12 +124,49 @@ pub struct SourceFileFacetParams { #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] pub struct SourceFileContent { + /// The name of the source file. pub name: String, + /// The path of the source file. pub path: String, // TODO: Since the content can change out of band of Skootrs // should we even store the content in the database? + /// The `String` content of the source file as a normal UTF8 string. pub content: String, - // TODO: Add a hash of the content to verify it hasn't changed +} + +/// Represents a source file. +#[derive(Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq)] +#[cfg_attr(feature = "openapi", derive(ToSchema))] +#[serde(try_from = "String", into = "String")] +pub struct SourceFile { + /// The name of the source file. + pub name: String, + /// The path of the source file. + pub path: String, + /// The hash of the source file. + pub hash: String, +} + +impl TryFrom for SourceFile { + type Error = String; + + fn try_from(value: String) -> Result { + let parts: Vec<&str> = value.split(':').collect(); + if parts.len() != 3 { + return Err(format!("Invalid source file string: {value}")); + } + Ok(Self { + name: parts[0].to_string(), + path: parts[1].to_string(), + hash: parts[2].to_string(), + }) + } +} + +impl From for String { + fn from(value: SourceFile) -> Self { + format!("{}:{}:{}", value.name, value.path, value.hash) + } } /// Represents a source bundle facet which is a facet that is based @@ -109,16 +176,23 @@ pub struct SourceFileContent { #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] pub struct SourceBundleFacet { - pub source_files: Vec, + /// The source files that make up the facet. + #[serde(skip_serializing_if = "Option::is_none")] + pub source_files: Option>, + /// The type of facet this is. pub facet_type: SupportedFacetType, + /// The content of the source files that make up the facet. This is a map of the source file to the content of the source file. + #[serde(skip_serializing_if = "Option::is_none")] + pub source_files_content: Option>, } - /// Represents the parameters for creating a source bundle facet. #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] -pub struct SourceBundleFacetParams { - pub common: CommonFacetParams, +pub struct SourceBundleFacetCreateParams { + /// The common parameters for the facet being created. + pub common: CommonFacetCreateParams, + /// The type of facet that is being created. pub facet_type: SupportedFacetType, } @@ -127,18 +201,20 @@ pub struct SourceBundleFacetParams { #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] pub struct APIContent { + /// The name of the API call. pub name: String, + /// The URL of the API call. pub url: String, // TODO: The response can be multiple things like a response code, // a JSON response, or something else. Should we store this as a // more comples type. + /// The response of the API call as a `String`. pub response: String, // TODO: Include the request as well. This could be useful for // audits, as well as for evaluating when the API facet might // need to be changed if an API call upstream changes. } - /// Represents an API bundle facet which is a facet that is based on /// an api call. This can be a single API call, or a collection of /// related API calls that represent a single facet. For example, a @@ -147,7 +223,9 @@ pub struct APIContent { #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] pub struct APIBundleFacet { + /// The API calls that make up the facet. pub apis: Vec, + /// The type of facet this is. pub facet_type: SupportedFacetType, } @@ -155,41 +233,91 @@ pub struct APIBundleFacet { #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] pub struct APIBundleFacetParams { - pub common: CommonFacetParams, + /// The common parameters for the facet being created. + pub common: CommonFacetCreateParams, + /// The type of facet that is being created. pub facet_type: SupportedFacetType, } /// Represents the supported facet types. This is an enum of the /// various supported facets like README, SECURITY.md, as well as /// API calls like enabling branch protection on GitHub. -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +#[derive( + Serialize, Deserialize, Clone, Debug, PartialEq, Eq, VariantNames, EnumString, Hash, Default, +)] #[cfg_attr(feature = "openapi", derive(ToSchema))] pub enum SupportedFacetType { + /// A facet type for a README file. Readme, + + /// A facet type for a SECURITY-INSIGHTS.yml file. SecurityInsights, + + /// A facet type that supports building the project via SLSA. SLSABuild, + + /// A facet type that supports generation of SBOMs in the project. SBOMGenerator, + + /// A facet type for the project's license. License, + + /// A facet type that shows static code analysis (SCA) is run on the project. StaticCodeAnalysis, + + /// A facet type for the project's gitignore file. Gitignore, + + /// A facet type showing that branch protection has been enabled on the project. BranchProtection, + + /// A facet type showing that code review is enabled on the project. CodeReview, + + /// A facet type showing that a tool for updating dependencies has been enabled on the project. DependencyUpdateTool, + + /// A facet type showing that a tool for fuzzing has been enabled on the project. Fuzzing, + + /// A facet type showing that the project publishes its packages. PublishPackages, + + /// A facet type showing that the project pins its dependencies. PinnedDependencies, + + /// A facet type showing that the project runs a Static Application Security Testing (SAST) tool. SAST, + + /// A facet type for the project's security policy. SecurityPolicy, + + /// A facet type showing that the project runs a vulnerability scanner. VulnerabilityScanner, + + /// A facet type showing that the project has configuration for forwarding security metadata to GUAC. GUACForwardingConfig, + + /// A facet type showing that the project has `OpenSSF Allstar` running against it. Allstar, + + /// A facet type showing that the project is running `OpenSSF Scorecard`. Scorecard, + + /// A facet type showing for the project's default source code. This should be something simple to just show that the project can build with + /// trivial source code and all the other facets enabled. DefaultSourceCode, + + /// A facet type showing that the project has a mechanism for reporting vulnerabilities. VulnerabilityReporting, + + /// A catch all facet type for other facets that don't fit into the above categories. + #[default] + Other, } impl fmt::Display for SupportedFacetType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } -} \ No newline at end of file +} diff --git a/skootrs-model/src/skootrs/mod.rs b/skootrs-model/src/skootrs/mod.rs index 8b250a1..6c92544 100644 --- a/skootrs-model/src/skootrs/mod.rs +++ b/skootrs-model/src/skootrs/mod.rs @@ -15,92 +15,264 @@ pub mod facet; -use std::error::Error; - -use serde::{Serialize, Deserialize}; +use std::{ + collections::{HashMap, HashSet}, + error::Error, + fmt, + str::FromStr, +}; + +use serde::{Deserialize, Serialize}; +use strum::{EnumString, VariantNames}; +use url::Host; use utoipa::ToSchema; -use self::facet::InitializedFacet; +use self::facet::{InitializedFacet, SupportedFacetType}; +/// A helper type for the error type used throughout Skootrs. This is a `Box`. pub type SkootError = Box; /// The general structure of the models here is the struct names take the form: /// `Params` reflecting the parameters for something to be created or initilized, like the parameters /// to create a repo or project. -/// +/// /// `Initialized` models the data and state for a created or initialized thing, like a repo created inside of Github. /// This module is purely focused on the data for skootrs, and not for performing any of the operations. In order to make /// it easy for (de)serialization, the structs and impls only contain the logic for the data, and not for the operations, /// which falls under service. // TODO: These categories of structs should be moved to their own modules. /// Consts for the supported ecosystems, repos, etc. for convenient use by things like the CLI. -pub const SUPPORTED_ECOSYSTEMS: [&str; 2] = [ - "Go", - "Maven" -]; +pub const SUPPORTED_ECOSYSTEMS: [&str; 2] = ["Go", "Maven"]; + +/// The set of supported ecosystems. +#[derive(Serialize, Deserialize, Clone, Debug, EnumString, VariantNames, Default)] +#[cfg_attr(feature = "openapi", derive(ToSchema))] +pub enum SupportedEcosystems { + /// The Go ecosystem + #[default] + Go, + /// The Maven ecosystem + Maven, +} // TODO: These should be their own structs, but they're currently not any different from the params structs. -/// Represents a project that has been initialized. This is the data and state of a project that has been +/// Represents a project that has been initialized. This is the data and state of a project that has been /// created. #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] pub struct InitializedProject { + /// The metadata associated with an Skootrs initilialized source repository. pub repo: InitializedRepo, + /// The metadata associated with an Skootrs initilialized ecosystem. pub ecosystem: InitializedEcosystem, + /// The metadata associated with an Skootrs initilialized source location. pub source: InitializedSource, - pub facets: Vec, + /// The facets associated with the project. + pub facets: HashMap, +} + +impl InitializedProject { + /// Returns the set of keys for the facet `HashMap` + #[must_use] + pub fn facet_key_set(&self) -> HashSet { + self.facets.keys().cloned().collect() + } +} + +/// A helper enum for how a facet can be pulled from a `HashMap` +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "openapi", derive(ToSchema))] +#[serde(try_from = "String", into = "String")] +pub enum FacetMapKey { + /// A map key based on the name of a facet. Useful for filtering based on the name of a facet. + Name(String), + /// A map key based on the type of a facet. Useful for filtering based on the type of facet. + Type(SupportedFacetType), +} + +impl TryFrom for FacetMapKey { + type Error = SkootError; + + fn try_from(value: String) -> Result { + let parts: Vec<&str> = value.split(": ").collect(); + if parts.len() != 2 { + return Err("Invalid facet map key".into()); + } + match parts.first() { + Some(&"Name") => Ok(Self::Name(parts[1].to_string())), + Some(&"Type") => Ok(Self::Type(parts[1].parse()?)), + _ => Err("Invalid facet map key".into()), + } + } +} + +impl From for String { + fn from(val: FacetMapKey) -> Self { + match val { + FacetMapKey::Name(x) => format!("Name: {x}"), + FacetMapKey::Type(x) => format!("Type: {x}"), + } + } } -/// Represents the parameters for creating a project. +impl FromStr for FacetMapKey { + type Err = SkootError; + + fn from_str(s: &str) -> Result { + let parts: Vec<&str> = s.split(": ").collect(); + if parts.len() != 2 { + return Err("Invalid facet map key".into()); + } + match parts.first() { + Some(&"Name") => Ok(Self::Name(parts[1].to_string())), + Some(&"Type") => Ok(Self::Type(parts[1].parse()?)), + _ => Err("Invalid facet map key".into()), + } + } +} + +// TODO: This seems redundant with From for String. +// I am not sure why this can't be automatically derived +impl fmt::Display for FacetMapKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + String::from(self.clone()).fmt(f)?; + Ok(()) + } +} + +/// The parameters for creating a project. #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] -pub struct ProjectParams { +pub struct ProjectCreateParams { + /// The name of the project to be created. pub name: String, - pub repo_params: RepoParams, - pub ecosystem_params: EcosystemParams, - pub source_params: SourceParams, + /// The parameters for creating the repository for the project. + pub repo_params: RepoCreateParams, + /// The parameters for initializing the ecosystem for the project. + pub ecosystem_params: EcosystemInitializeParams, + /// The parameters for initializing the source code for the project. + pub source_params: SourceInitializeParams, +} + +/// The parameters for getting an existing Skootrs project. +#[derive(Serialize, Deserialize, Clone, Debug)] +#[cfg_attr(feature = "openapi", derive(ToSchema))] +pub struct ProjectGetParams { + /// The URL of the Skootrs project to get. + pub project_url: String, +} + +/// 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 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 set of supported output types +#[derive(Serialize, Deserialize, Clone, Debug)] +#[cfg_attr(feature = "openapi", derive(ToSchema))] +pub enum ProjectOutputType { + /// An output type for getting an SBOM from a project. + SBOM, + /// An output type for getting a custom output from a project. + Custom(String), +} + +/// The parameters for getting a facet from a project. +#[derive(Serialize, Deserialize, Clone, Debug)] +#[cfg_attr(feature = "openapi", derive(ToSchema))] +pub struct FacetGetParams { + /// The URL of the Skootrs project to get the facet from. + pub project_url: String, + /// The key of the facet to get from the project. + pub facet_map_key: FacetMapKey, } /// Represents an initialized repository along with its host. #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] pub enum InitializedRepo { - Github(InitializedGithubRepo) + /// An initialized Github repository. + Github(InitializedGithubRepo), } impl InitializedRepo { /// Returns the host URL of the repo. - #[must_use] pub fn host_url(&self) -> String { + #[must_use] + pub fn host_url(&self) -> String { match self { Self::Github(x) => x.host_url(), } } /// Returns the full URL to the repo. - #[must_use] pub fn full_url(&self) -> String { + #[must_use] + pub fn full_url(&self) -> String { match self { Self::Github(x) => x.full_url(), } } } +impl TryFrom for InitializedRepo { + type Error = SkootError; + + fn try_from(value: String) -> Result { + let parts = url::Url::parse(&value)?; + let path_segments = parts + .path_segments() + .map_or(Vec::new(), Iterator::collect::>); + if path_segments.len() != 2 { + return Err(format!("Invalid repo URL: {value}").into()); + } + + let organization = *path_segments + .first() + .ok_or(format!("Invalid repo URL: {value}"))?; + let name = *path_segments + .get(1) + .ok_or(format!("Invalid repo URL: {value}"))?; + match parts.host() { + Some(Host::Domain("github.com")) => { + Ok(Self::Github(InitializedGithubRepo { + name: name.to_string(), + // FIXME: This will have issues if this isn't a user repo and in fact an organization user. + organization: GithubUser::User(organization.into()), + })) + } + _ => Err("Unsupported repo host".into()), + } + } +} + /// Represents an initialized Github repository. #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] pub struct InitializedGithubRepo { + /// The name of the Github repository. pub name: String, + /// The organization the Github repository belongs to. pub organization: GithubUser, } impl InitializedGithubRepo { /// Returns the host URL of github. - #[must_use] pub fn host_url(&self) -> String { + #[must_use] + pub fn host_url(&self) -> String { "https://github.com".into() } /// Returns the full URL to the github repo. - #[must_use] pub fn full_url(&self) -> String { + #[must_use] + pub fn full_url(&self) -> String { format!( "{}/{}/{}", self.host_url(), @@ -115,23 +287,35 @@ impl InitializedGithubRepo { #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] pub enum InitializedEcosystem { + /// An initialized Go ecosystem for `InitializedSource`. Go(InitializedGo), - Maven(InitializedMaven) + /// An initialized Maven ecosystem `InitializedSource`. + Maven(InitializedMaven), } -/// Represents the parameters for creating a repository. +/// The parameters for creating a repository. #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] -pub enum RepoParams { - Github(GithubRepoParams) +pub enum RepoCreateParams { + /// The parameters for creating a Github repository. + Github(GithubRepoParams), } -/// Represents the parameters for initializing an ecosystem. +/// The parameters for initializing an ecosystem. #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] -pub enum EcosystemParams { +pub enum EcosystemInitializeParams { + /// The parameters for initializing a Go ecosystem for `InitializedSource`. Go(GoParams), - Maven(MavenParams) + /// The parameters for initializing a Maven ecosystem for `InitializedSource`. + Maven(MavenParams), +} + +/// The parameter for getting an initialized repository +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct InitializedRepoGetParams { + /// The URL of the repository that Skootrs has previously initialized and you want to get. + pub repo_url: String, } /// Represents a Github user which is really just whether or not a repo belongs to a user or organization. @@ -140,16 +324,18 @@ pub enum EcosystemParams { #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] pub enum GithubUser { + /// A Github user, i.e. not an organization. User(String), + /// A Github organization, i.e. not a user. Organization(String), } impl GithubUser { /// Returns the name of the user or organization. - #[must_use] pub fn get_name(&self) -> String { + #[must_use] + pub fn get_name(&self) -> String { match self { - Self::User(x) | - Self::Organization(x) => x.to_string(), + Self::User(x) | Self::Organization(x) => x.to_string(), } } } @@ -158,17 +344,24 @@ impl GithubUser { #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] pub struct GithubRepoParams { + /// The name of the Github repository. pub name: String, + /// The description of the Github repository. pub description: String, + /// The organization the Github repository belongs to. pub organization: GithubUser, } impl GithubRepoParams { - #[must_use] pub fn host_url(&self) -> String { + /// Helper for returning the github host. + #[must_use] + pub fn host_url(&self) -> String { "https://github.com".into() } - #[must_use] pub fn full_url(&self) -> String { + /// Helper for returning the full URL to the github repo. + #[must_use] + pub fn full_url(&self) -> String { format!( "{}/{}/{}", self.host_url(), @@ -181,13 +374,15 @@ impl GithubRepoParams { /// Represents the parameters for initializing a source code repository. #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] -pub struct SourceParams { +pub struct SourceInitializeParams { + /// The parent path of the source code repository. pub parent_path: String, } -impl SourceParams { +impl SourceInitializeParams { /// Returns the full path to the source code repository with the given name. - #[must_use] pub fn path(&self, name: &str) -> String { + #[must_use] + pub fn path(&self, name: &str) -> String { format!("{}/{}", self.parent_path, name) } } @@ -195,7 +390,8 @@ impl SourceParams { /// Struct representing a working copy of source code. #[derive(Serialize, Deserialize, Debug, Clone, ToSchema)] pub struct InitializedSource { - pub path: String + /// The path to the source code repository. + pub path: String, } /// Represents the Maven ecosystem. @@ -230,7 +426,8 @@ pub struct InitializedGo { impl InitializedGo { /// Returns the module name in the format "{host}/{name}". - #[must_use] pub fn module(&self) -> String { + #[must_use] + pub fn module(&self) -> String { format!("{}/{}", self.host, self.name) } } @@ -247,7 +444,8 @@ pub struct InitializedMaven { impl GoParams { /// Returns the module name in the format "{host}/{name}". - #[must_use] pub fn module(&self) -> String { + #[must_use] + pub fn module(&self) -> String { format!("{}/{}", self.host, self.name) } } @@ -255,14 +453,28 @@ impl GoParams { /// A set of configuration options for Skootrs. #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr(feature = "openapi", derive(ToSchema))] -pub struct SkootrsConfig { +pub struct Config { + /// The local path to cached projects. This is used by `LocalProjectService` for performing operations locally. pub local_project_path: String, } -impl Default for SkootrsConfig { +impl Default for Config { fn default() -> Self { Self { - local_project_path: "/tmp".into() + local_project_path: "/tmp".into(), } } -} \ No newline at end of file +} + +#[cfg(test)] +mod tests { + #![allow(clippy::unwrap_used)] + use super::*; + #[test] + fn test_initialized_repo_try_from() { + let repo: InitializedRepo = + InitializedRepo::try_from("https://github.com/kusaridev/skootrs".to_string()).unwrap(); + assert_eq!(repo.host_url(), "https://github.com"); + assert_eq!(repo.full_url(), "https://github.com/kusaridev/skootrs"); + } +} diff --git a/skootrs-rest/src/server/project.rs b/skootrs-rest/src/server/project.rs index c450f17..0617315 100644 --- a/skootrs-rest/src/server/project.rs +++ b/skootrs-rest/src/server/project.rs @@ -18,7 +18,7 @@ use serde::{Serialize, Deserialize}; use skootrs_statestore::SurrealProjectStateStore; use utoipa::ToSchema; -use skootrs_model::skootrs::ProjectParams; +use skootrs_model::skootrs::ProjectCreateParams; use skootrs_lib::service::{ecosystem::LocalEcosystemService, facet::LocalFacetService, project::{LocalProjectService, ProjectService}, repo::LocalRepoService, source::LocalSourceService}; /// An Error response for the REST API @@ -69,7 +69,7 @@ pub(super) fn configure(store: Data) -> impl FnOnce(&m (status = 409, description = "Project unable to be created", body = ErrorResponse, example = json!(ErrorResponse::InitializationError("Unable to create repo".into()))) ) )] -pub(super) async fn create_project(params: Json, project_store: Data) -> Result { +pub(super) async fn create_project(params: Json, project_store: Data) -> Result { // TODO: This should be initialized elsewhere let project_service = LocalProjectService { repo_service: LocalRepoService {}, diff --git a/skootrs-rest/src/server/rest.rs b/skootrs-rest/src/server/rest.rs index 03ccf3e..32f49fb 100644 --- a/skootrs-rest/src/server/rest.rs +++ b/skootrs-rest/src/server/rest.rs @@ -24,8 +24,8 @@ use utoipa_redoc::{Redoc, Servable}; use utoipa_swagger_ui::SwaggerUi; use crate::server::project::ErrorResponse; -use skootrs_model::{skootrs::{InitializedProject, ProjectParams, InitializedRepo, InitializedGithubRepo, InitializedEcosystem, RepoParams, EcosystemParams, GithubUser, GithubRepoParams, SourceParams, InitializedSource, MavenParams, GoParams, InitializedGo, InitializedMaven, facet::{CommonFacetParams, SourceFileFacet, SourceFileFacetParams, InitializedFacet, FacetParams, SupportedFacetType}}, cd_events::repo_created::{RepositoryCreatedEvent, RepositoryCreatedEventContext, RepositoryCreatedEventContextId, RepositoryCreatedEventContextVersion, RepositoryCreatedEventSubject, RepositoryCreatedEventSubjectContent, RepositoryCreatedEventSubjectContentUrl, RepositoryCreatedEventSubjectId}, security_insights::insights10::{SecurityInsightsVersion100YamlSchema, SecurityInsightsVersion100YamlSchemaContributionPolicy, SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem, SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment, SecurityInsightsVersion100YamlSchemaDependencies, SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle, SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment, SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy, SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment, SecurityInsightsVersion100YamlSchemaDependenciesSbomItem, SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation, SecurityInsightsVersion100YamlSchemaHeader, SecurityInsightsVersion100YamlSchemaHeaderCommitHash, SecurityInsightsVersion100YamlSchemaProjectLifecycle, SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess, SecurityInsightsVersion100YamlSchemaSecurityArtifacts, SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment, SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment, SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel, SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment, SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem, SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment, SecurityInsightsVersion100YamlSchemaSecurityContactsItem, SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue, SecurityInsightsVersion100YamlSchemaSecurityTestingItem, SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment, SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration, SecurityInsightsVersion100YamlSchemaVulnerabilityReporting, SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment, SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey}}; -use skootrs_model::skootrs::facet::{SourceBundleFacet, SourceBundleFacetParams, APIBundleFacet, APIBundleFacetParams, SourceFileContent, APIContent}; +use skootrs_model::{skootrs::{InitializedProject, ProjectCreateParams, InitializedRepo, InitializedGithubRepo, InitializedEcosystem, RepoCreateParams, EcosystemInitializeParams, GithubUser, GithubRepoParams, SourceInitializeParams, InitializedSource, MavenParams, GoParams, InitializedGo, InitializedMaven, facet::{CommonFacetCreateParams, SourceFileFacet, SourceFileFacetParams, InitializedFacet, FacetCreateParams, SupportedFacetType}}, cd_events::repo_created::{RepositoryCreatedEvent, RepositoryCreatedEventContext, RepositoryCreatedEventContextId, RepositoryCreatedEventContextVersion, RepositoryCreatedEventSubject, RepositoryCreatedEventSubjectContent, RepositoryCreatedEventSubjectContentUrl, RepositoryCreatedEventSubjectId}, security_insights::insights10::{SecurityInsightsVersion100YamlSchema, SecurityInsightsVersion100YamlSchemaContributionPolicy, SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItem, SecurityInsightsVersion100YamlSchemaContributionPolicyAutomatedToolsListItemComment, SecurityInsightsVersion100YamlSchemaDependencies, SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycle, SecurityInsightsVersion100YamlSchemaDependenciesDependenciesLifecycleComment, SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicy, SecurityInsightsVersion100YamlSchemaDependenciesEnvDependenciesPolicyComment, SecurityInsightsVersion100YamlSchemaDependenciesSbomItem, SecurityInsightsVersion100YamlSchemaDependenciesSbomItemSbomCreation, SecurityInsightsVersion100YamlSchemaHeader, SecurityInsightsVersion100YamlSchemaHeaderCommitHash, SecurityInsightsVersion100YamlSchemaProjectLifecycle, SecurityInsightsVersion100YamlSchemaProjectLifecycleReleaseProcess, SecurityInsightsVersion100YamlSchemaSecurityArtifacts, SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessment, SecurityInsightsVersion100YamlSchemaSecurityArtifactsSelfAssessmentComment, SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModel, SecurityInsightsVersion100YamlSchemaSecurityArtifactsThreatModelComment, SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItem, SecurityInsightsVersion100YamlSchemaSecurityAssessmentsItemComment, SecurityInsightsVersion100YamlSchemaSecurityContactsItem, SecurityInsightsVersion100YamlSchemaSecurityContactsItemValue, SecurityInsightsVersion100YamlSchemaSecurityTestingItem, SecurityInsightsVersion100YamlSchemaSecurityTestingItemComment, SecurityInsightsVersion100YamlSchemaSecurityTestingItemIntegration, SecurityInsightsVersion100YamlSchemaVulnerabilityReporting, SecurityInsightsVersion100YamlSchemaVulnerabilityReportingComment, SecurityInsightsVersion100YamlSchemaVulnerabilityReportingPgpKey}}; +use skootrs_model::skootrs::facet::{SourceBundleFacet, SourceBundleFacetCreateParams, APIBundleFacet, APIBundleFacetParams, SourceFileContent, APIContent}; /// Run the Skootrs REST API server. #[actix_web::main] @@ -43,30 +43,30 @@ pub async fn run_server() -> std::io::Result<()> { // Skootrs Model schemas InitializedProject, - ProjectParams, + ProjectCreateParams, InitializedRepo, InitializedGithubRepo, InitializedEcosystem, - RepoParams, - EcosystemParams, + RepoCreateParams, + EcosystemInitializeParams, GithubUser, GithubRepoParams, - SourceParams, + SourceInitializeParams, InitializedSource, MavenParams, GoParams, InitializedGo, InitializedMaven, // Facet Schemas - CommonFacetParams, + CommonFacetCreateParams, SourceFileFacet, SourceFileFacetParams, InitializedFacet, - FacetParams, + FacetCreateParams, SupportedFacetType, InitializedProject, SourceBundleFacet, - SourceBundleFacetParams, + SourceBundleFacetCreateParams, APIBundleFacet, APIBundleFacetParams, SourceFileContent, diff --git a/skootrs-statestore/Cargo.toml b/skootrs-statestore/Cargo.toml index 4aa1fa6..5d7b6df 100644 --- a/skootrs-statestore/Cargo.toml +++ b/skootrs-statestore/Cargo.toml @@ -8,4 +8,5 @@ edition = "2021" [dependencies] surrealdb = { version = "1.1.1", features = ["kv-rocksdb"] } skootrs-lib = { path = "../skootrs-lib" } -skootrs-model = { path = "../skootrs-model" } \ No newline at end of file +skootrs-model = { path = "../skootrs-model" } +serde_json = "1.0.114" diff --git a/skootrs-statestore/src/lib.rs b/skootrs-statestore/src/lib.rs index 9f31dfb..01f601b 100644 --- a/skootrs-statestore/src/lib.rs +++ b/skootrs-statestore/src/lib.rs @@ -16,14 +16,23 @@ //! This is the crate where the statestore where the management of `Skootrs` project state is defined. //! The statestore currently supports an in memory `SurrealDB` instance that writes to a file. -use surrealdb::{engine::local::{Db, RocksDb}, Surreal}; +use std::collections::HashSet; -use skootrs_model::skootrs::{InitializedProject, SkootError}; +use skootrs_lib::service::{ + repo::{LocalRepoService, RepoService}, + source::{LocalSourceService, SourceService}, +}; +use surrealdb::{ + engine::local::{Db, RocksDb}, + Surreal, +}; + +use skootrs_model::skootrs::{InitializedProject, InitializedRepo, InitializedSource, SkootError}; /// The `SurrealDB` state store for Skootrs projects. #[derive(Debug)] pub struct SurrealProjectStateStore { - pub db: Surreal + pub db: Surreal, } /// The functionality for the `SurrealDB` state store for Skootrs projects. @@ -36,18 +45,20 @@ impl SurrealProjectStateStore { pub async fn new() -> Result { let db = Surreal::new::("state.db").await?; db.use_ns("kusaridev").use_db("skootrs").await?; - Ok(Self { - db - }) + Ok(Self { db }) } - /// Store a new project in the state store. + /// Store a new project in the state store. /// /// # Errors /// /// Returns an error if the project can't be stored in the state store. - pub async fn create(&self, project: InitializedProject) -> Result, SkootError> { - let created = self.db + pub async fn create( + &self, + project: InitializedProject, + ) -> Result, SkootError> { + let created = self + .db .create(("project", project.repo.full_url())) .content(project) .await?; @@ -60,9 +71,7 @@ impl SurrealProjectStateStore { /// /// Returns an error if the project can't be fetched from the state store. pub async fn select(&self, repo_url: String) -> Result, SkootError> { - let record = self.db - .select(("project", repo_url)) - .await?; + let record = self.db.select(("project", repo_url)).await?; Ok(record) } @@ -72,9 +81,158 @@ impl SurrealProjectStateStore { /// /// Returns an error if all the projects can't be dumped from the state store. pub async fn select_all(&self) -> Result, SkootError> { - let records = self.db - .select("project") - .await?; + let records = self.db.select("project").await?; Ok(records) } } + +pub trait ProjectStateStore { + fn create( + &self, + project: InitializedProject, + ) -> impl std::future::Future> + Send; + fn read( + &self, + ) -> impl std::future::Future, SkootError>> + Send; + fn update( + &self, + project: InitializedProject, + ) -> impl std::future::Future> + Send; +} + +pub struct GitProjectStateStore { + // TODO: This should be a git repo type of some sort + pub source: InitializedSource, + pub source_service: S, +} + +impl ProjectStateStore for GitProjectStateStore { + async fn create(&self, project: InitializedProject) -> Result<(), SkootError> { + self.source_service.write_file( + self.source.clone(), + "./", + ".skootrs".to_string(), + serde_json::to_string(&project)?, + )?; + self.source_service.commit_and_push_changes( + self.source.clone(), + "Updated skootrs project state".to_string(), + )?; + Ok(()) + } + + async fn read(&self) -> Result, SkootError> { + let project = self + .source_service + .read_file(&self.source, "./", ".skootrs".to_string())?; + Ok(Some(serde_json::from_str(&project).unwrap())) + } + + fn update( + &self, + project: InitializedProject, + ) -> impl std::future::Future> + Send { + self.create(project) + } +} + +pub trait ProjectReferenceCache { + fn list(&self) + -> impl std::future::Future, SkootError>> + Send; + fn get( + &mut self, + repo_url: String, + ) -> impl std::future::Future> + Send; + fn set( + &mut self, + repo_url: String, + ) -> impl std::future::Future> + Send; +} + +pub struct InMemoryProjectReferenceCache { + pub save_path: String, + pub cache: HashSet, + pub local_source_service: LocalSourceService, + pub local_repo_service: LocalRepoService, + pub clone_path: String, +} + +impl ProjectReferenceCache for InMemoryProjectReferenceCache { + async fn list(&self) -> Result, SkootError> { + Ok(self.cache.clone()) + } + + async fn get(&mut self, repo_url: String) -> Result { + let repo = InitializedRepo::try_from(repo_url)?; + /*let local_clone = self + .local_repo_service + .clone_local(repo, self.clone_path.clone())?; + let project = + self.local_source_service + .read_file(&local_clone, "./", ".skootrs".to_string())?;*/ + let project = self + .local_repo_service + .fetch_file_content(&repo, ".skootrs") + .await?; + let initialized_project: InitializedProject = serde_json::from_str(&project)?; + Ok(initialized_project) + } + + async fn set(&mut self, repo_url: String) -> Result<(), SkootError> { + self.cache.insert(repo_url); + self.save()?; + Ok(()) + } +} + +impl InMemoryProjectReferenceCache { + /// Create a new `InMemoryProjectReferenceCache` instance. The `save_path` is the path to the file where the cache will be saved. + #[must_use] + pub fn new(save_path: String) -> Self { + Self { + save_path, + cache: HashSet::new(), + local_source_service: LocalSourceService {}, + local_repo_service: LocalRepoService {}, + clone_path: "/tmp".to_string(), + } + } + + /// Load the cache from the file at `save_path` or create a new cache if the file does not exist. + /// + /// # Errors + /// + /// Returns an error if the cache can't be loaded or created. + pub fn load_or_create(path: &str) -> Result { + let mut cache = Self::new(path.to_string()); + Ok(if cache.load().is_ok() { + cache + } else { + cache.save()?; + cache + }) + } + + /// Load the cache from the file at `save_path`. + /// + /// # Errors + /// + /// Returns an error if the cache can't be loaded. + pub fn load(&mut self) -> Result<(), SkootError> { + let deserialized_cache: HashSet = + serde_json::from_str(&std::fs::read_to_string(&self.save_path)?)?; + self.cache = deserialized_cache; + Ok(()) + } + + /// Save the cache to the file at `save_path` in the struct. + /// + /// # Errors + /// + /// Returns an error if the cache can't be saved. + pub fn save(&self) -> Result<(), SkootError> { + let serialized_cache = serde_json::to_string(&self.cache)?; + std::fs::write(&self.save_path, serialized_cache)?; + Ok(()) + } +}