diff --git a/Cargo.lock b/Cargo.lock index 883303c2..8d972388 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2541,9 +2541,9 @@ dependencies = [ [[package]] name = "tame-index" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d8d8b231dac2161abc5ac5abc07115fa29886f1defa6eae2bfcca40d6d61560" +checksum = "ab9ccd31f158301d01e0bd1d3e2b1c3f2ad209f0301b4121d3ccb508aae5237d" dependencies = [ "bytes", "camino", @@ -2721,9 +2721,9 @@ dependencies = [ [[package]] name = "toml-span" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32c5896fa509a428e0ffcb1e37c7954f183a507784cd2999cb76c3b7544bf52d" +checksum = "369db38ce6d1fc320a54ea3f032d07c07a232ca19c40e287246aff06d57c2abe" dependencies = [ "codespan-reporting", "serde", diff --git a/Cargo.toml b/Cargo.toml index 8613f697..d475edd6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -111,7 +111,7 @@ time = { version = "0.3", default-features = false, features = [ "macros", ] } # Deserialization of configuration files and crate manifests -toml-span = { version = "0.1.0", features = ["reporting"] } +toml-span = { version = "0.2", features = ["reporting"] } # Small fast hash crate twox-hash = { version = "1.5", default-features = false } # Url parsing/manipulation @@ -138,7 +138,7 @@ fs_extra = "1.3" insta = { version = "1.21", features = ["json"] } tame-index = { version = "0.9", features = ["local-builder"] } time = { version = "0.3", features = ["serde"] } -toml-span = { version = "0.1.0", features = ["serde"] } +toml-span = { version = "0.2", features = ["serde"] } # We use this for creating fake crate directories for crawling license files on disk tempfile = "3.1.0" diff --git a/deny.toml b/deny.toml index d1006505..9f815755 100644 --- a/deny.toml +++ b/deny.toml @@ -11,14 +11,9 @@ targets = [ all-features = true [advisories] -vulnerability = "deny" -unmaintained = "deny" -notice = "deny" -unsound = "deny" +version = 2 ignore = [ - # rmp-serde used by askalono for the cache files, these are always utf-8 so - # the advisory is not relevant - "RUSTSEC-2022-0092", + { id = "RUSTSEC-2022-0092", reason = "askalono always provides valid utf-8 files from a cache, this is not relevant" }, ] [bans] @@ -44,9 +39,7 @@ unknown-registry = "deny" unknown-git = "deny" [licenses] -unlicensed = "deny" -allow-osi-fsf-free = "neither" -copyleft = "deny" +version = 2 # We want really high confidence when inferring licenses from text confidence-threshold = 0.93 allow = [ diff --git a/src/advisories/cfg.rs b/src/advisories/cfg.rs index 8df2e3d2..16124ead 100644 --- a/src/advisories/cfg.rs +++ b/src/advisories/cfg.rs @@ -64,30 +64,34 @@ impl PartialEq for IgnoreId { impl Eq for IgnoreId {} -pub struct Config { - /// Path to the root directory where advisory databases are stored (default: $CARGO_HOME/advisory-dbs) - pub db_path: Option, - /// List of urls to git repositories of different advisory databases. - pub db_urls: Vec>, +#[cfg_attr(test, derive(serde::Serialize))] +pub(crate) struct Deprecated { /// How to handle crates that have a security vulnerability pub vulnerability: LintLevel, /// How to handle crates that have been marked as unmaintained in an advisory database pub unmaintained: LintLevel, /// How to handle crates that have been marked as unsound in an advisory database pub unsound: LintLevel, - /// How to handle crates that have been yanked from eg crates.io - pub yanked: Spanned, /// How to handle crates that have been marked with a notice in the advisory database pub notice: LintLevel, - /// Ignore advisories for the given IDs - ignore: Vec>, - /// Ignore yanked crates - pub ignore_yanked: Vec>>, /// CVSS Qualitative Severity Rating Scale threshold to alert at. /// /// Vulnerabilities with explicit CVSS info which have a severity below /// this threshold will be ignored. pub severity_threshold: Option, +} + +pub struct Config { + /// Path to the root directory where advisory databases are stored (default: $CARGO_HOME/advisory-dbs) + pub db_path: Option, + /// List of urls to git repositories of different advisory databases. + pub db_urls: Vec>, + /// How to handle crates that have been yanked from eg crates.io + pub yanked: Spanned, + /// Ignore advisories for the given IDs + ignore: Vec>, + /// Ignore yanked crates + pub ignore_yanked: Vec>>, /// Use the git executable to fetch advisory database rather than gitoxide pub git_fetch_with_cli: Option, /// If set to true, the local crates indices are not checked for yanked crates @@ -100,7 +104,8 @@ pub struct Config { /// use the '.' separator instead of ',' which is used by some locales and /// supported in the RFC3339 format, but not by this implementation pub maximum_db_staleness: Spanned, - deprecated: Vec, + deprecated: Option, + deprecated_spans: Vec, } impl Default for Config { @@ -110,16 +115,12 @@ impl Default for Config { db_urls: Vec::new(), ignore: Vec::new(), ignore_yanked: Vec::new(), - vulnerability: LintLevel::Deny, - unmaintained: LintLevel::Warn, - unsound: LintLevel::Warn, yanked: Spanned::new(LintLevel::Warn), - notice: LintLevel::Warn, - severity_threshold: None, git_fetch_with_cli: None, disable_yank_checking: false, maximum_db_staleness: Spanned::new(Duration::seconds_f64(NINETY_DAYS)), - deprecated: Vec::new(), + deprecated: None, + deprecated_spans: Vec::new(), } } } @@ -130,6 +131,8 @@ impl<'de> Deserialize<'de> for Config { fn deserialize(value: &mut Value<'de>) -> Result { let mut th = TableHelper::new(value)?; + let version = th.optional("version").unwrap_or(1); + let db_path = th.optional::("db-path").map(PathBuf::from); let db_urls = if let Some((_, mut urls)) = th.take("db-urls") { let mut u = Vec::new(); @@ -158,15 +161,14 @@ impl<'de> Deserialize<'de> for Config { let mut fdeps = Vec::new(); - let vulnerability = - deprecated(&mut th, "vulnerability", &mut fdeps).unwrap_or(LintLevel::Deny); - let unmaintained = - deprecated(&mut th, "unmaintained", &mut fdeps).unwrap_or(LintLevel::Warn); - let unsound = deprecated(&mut th, "unsound", &mut fdeps).unwrap_or(LintLevel::Warn); + let vulnerability = deprecated(&mut th, "vulnerability", &mut fdeps); + let unmaintained = deprecated(&mut th, "unmaintained", &mut fdeps); + let unsound = deprecated(&mut th, "unsound", &mut fdeps); + let notice = deprecated(&mut th, "notice", &mut fdeps); + let yanked = th .optional_s("yanked") .unwrap_or(Spanned::new(LintLevel::Warn)); - let notice = deprecated(&mut th, "notice", &mut fdeps).unwrap_or(LintLevel::Warn); let (ignore, ignore_yanked) = if let Some((_, mut ignore)) = th.take("ignore") { let mut u = Vec::new(); let mut y = Vec::new(); @@ -303,21 +305,29 @@ impl<'de> Deserialize<'de> for Config { let maximum_db_staleness = maximum_db_staleness .unwrap_or_else(|| Spanned::new(Duration::seconds_f64(NINETY_DAYS))); + let deprecated = if version <= 1 { + Some(Deprecated { + vulnerability: vulnerability.unwrap_or(LintLevel::Deny), + unmaintained: unmaintained.unwrap_or(LintLevel::Warn), + unsound: unsound.unwrap_or(LintLevel::Warn), + notice: notice.unwrap_or(LintLevel::Warn), + severity_threshold, + }) + } else { + None + }; + Ok(Self { db_path, db_urls, - vulnerability, - unmaintained, - unsound, yanked, - notice, ignore, ignore_yanked, - severity_threshold, git_fetch_with_cli, disable_yank_checking, maximum_db_staleness, - deprecated: fdeps, + deprecated, + deprecated_spans: fdeps, }) } } @@ -349,7 +359,7 @@ impl crate::cfg::UnvalidatedConfig for Config { // Output any deprecations, we'll remove the fields at the same time we // remove all the logic they drive - for dep in self.deprecated { + for dep in self.deprecated_spans { ctx.push( Deprecated { reason: DeprecationReason::WillBeRemoved(Some( @@ -376,12 +386,8 @@ impl crate::cfg::UnvalidatedConfig for Config { file_id: ctx.cfg_id, }) .collect(), - vulnerability: self.vulnerability, - unmaintained: self.unmaintained, - unsound: self.unsound, + deprecated: self.deprecated, yanked: self.yanked, - notice: self.notice, - severity_threshold: self.severity_threshold, git_fetch_with_cli: self.git_fetch_with_cli.unwrap_or_default(), disable_yank_checking: self.disable_yank_checking, maximum_db_staleness: self.maximum_db_staleness, @@ -396,12 +402,8 @@ pub struct ValidConfig { pub db_urls: Vec>, pub(crate) ignore: Vec, pub(crate) ignore_yanked: Vec, - pub vulnerability: LintLevel, - pub unmaintained: LintLevel, - pub unsound: LintLevel, + pub(crate) deprecated: Option, pub yanked: Spanned, - pub notice: LintLevel, - pub severity_threshold: Option, pub git_fetch_with_cli: bool, pub disable_yank_checking: bool, pub maximum_db_staleness: Spanned, diff --git a/src/advisories/diags.rs b/src/advisories/diags.rs index e0a5f74c..ac1aaccf 100644 --- a/src/advisories/diags.rs +++ b/src/advisories/diags.rs @@ -89,26 +89,18 @@ impl<'a> crate::CheckCtx<'a, super::cfg::ValidConfig> { let mut pack = Pack::with_kid(Check::Advisories, krate.id.clone()); let (severity, ty) = { - let (lint_level, ty) = match &advisory.informational { - // Everything that isn't an informational advisory is a vulnerability - None => (self.cfg.vulnerability, AdvisoryType::Vulnerability), - Some(info) => match info { - // Security notices for a crate which are published on https://rustsec.org - // but don't represent a vulnerability in a crate itself. - Informational::Notice => (self.cfg.notice, AdvisoryType::Notice), + let adv_ty = advisory.informational.as_ref().map_or(AdvisoryType::Vulnerability, |info| { + match info { // Crate is unmaintained / abandoned - Informational::Unmaintained => { - (self.cfg.unmaintained, AdvisoryType::Unmaintained) + Informational::Unmaintained => AdvisoryType::Unmaintained, + Informational::Unsound => AdvisoryType::Unsound, + Informational::Notice => AdvisoryType::Notice, + Informational::Other(other) => { + unreachable!("rustsec only returns Informational::Other({other}) advisories if we ask, and there are none at the moment to ask for"); } - Informational::Unsound => (self.cfg.unsound, AdvisoryType::Unsound), - // Other types of informational advisories: left open-ended to add - // more of them in the future. - Informational::Other(_) => { - unreachable!("rustsec only returns these if we ask, and there are none at the moment to ask for"); - } - _ => unreachable!("unknown advisory type encountered"), - }, - }; + _ => unreachable!("non_exhaustive enums are the worst"), + } + }); // Ok, we found a crate whose version lies within the range of an // advisory, but the user might have decided to ignore it @@ -132,22 +124,29 @@ impl<'a> crate::CheckCtx<'a, super::cfg::ValidConfig> { ); LintLevel::Allow - } else if let Some(severity_threshold) = self.cfg.severity_threshold { - if let Some(advisory_severity) = advisory.cvss.as_ref().map(|cvss| cvss.severity()) - { - if advisory_severity < severity_threshold { - LintLevel::Allow - } else { - lint_level + } else if let Some(deprecated) = &self.cfg.deprecated { + 'll: { + if let (Some(st), Some(sev)) = ( + deprecated.severity_threshold, + advisory.cvss.as_ref().map(|c| c.severity()), + ) { + if sev < st { + break 'll LintLevel::Allow; + } + } + + match adv_ty { + AdvisoryType::Vulnerability => deprecated.vulnerability, + AdvisoryType::Unmaintained => deprecated.unmaintained, + AdvisoryType::Unsound => deprecated.unsound, + AdvisoryType::Notice => deprecated.notice, } - } else { - lint_level } } else { - lint_level + LintLevel::Deny }; - (lint_level.into(), ty) + (lint_level.into(), adv_ty) }; let mut notes = get_notes_from_advisory(advisory); diff --git a/src/advisories/snapshots/cargo_deny__advisories__cfg__test__deserializes_advisories_cfg-2.snap b/src/advisories/snapshots/cargo_deny__advisories__cfg__test__deserializes_advisories_cfg-2.snap index 77e728ba..e87b97a4 100644 --- a/src/advisories/snapshots/cargo_deny__advisories__cfg__test__deserializes_advisories_cfg-2.snap +++ b/src/advisories/snapshots/cargo_deny__advisories__cfg__test__deserializes_advisories_cfg-2.snap @@ -32,12 +32,14 @@ expression: validated "use-instead": null } ], - "vulnerability": "deny", - "unmaintained": "warn", - "unsound": "warn", + "deprecated": { + "vulnerability": "deny", + "unmaintained": "warn", + "unsound": "warn", + "notice": "warn", + "severity_threshold": "medium" + }, "yanked": "warn", - "notice": "warn", - "severity_threshold": "medium", "git_fetch_with_cli": false, "disable_yank_checking": false, "maximum_db_staleness": [ diff --git a/src/licenses.rs b/src/licenses.rs index c107c24e..f01bd5ce 100644 --- a/src/licenses.rs +++ b/src/licenses.rs @@ -52,6 +52,7 @@ fn evaluate_expression( ExplicitException, IsCopyleft, Default, + NotExplicitlyAllowed, } let mut reasons = smallvec::SmallVec::<[(Reason, bool); 8]>::new(); @@ -115,82 +116,86 @@ fn evaluate_expression( } } - // 4. If the license isn't explicitly allowed, it still may - // be allowed by the blanket "OSI Approved" or "FSF Free/Libre" - // allowances - if let spdx::LicenseItem::Spdx { id, .. } = req.license { - if id.is_copyleft() { - match cfg.copyleft { - LintLevel::Allow => { - allow!(IsCopyleft); - } - LintLevel::Warn => { - warnings += 1; - allow!(IsCopyleft); - } - LintLevel::Deny => { - deny!(IsCopyleft); + if let Some(dep_cfg) = &cfg.deprecated { + // 4. If the license isn't explicitly allowed, it still may + // be allowed by the blanket "OSI Approved" or "FSF Free/Libre" + // allowances + if let spdx::LicenseItem::Spdx { id, .. } = req.license { + if id.is_copyleft() { + match dep_cfg.copyleft { + LintLevel::Allow => { + allow!(IsCopyleft); + } + LintLevel::Warn => { + warnings += 1; + allow!(IsCopyleft); + } + LintLevel::Deny => { + deny!(IsCopyleft); + } } } - } - match cfg.allow_osi_fsf_free { - BlanketAgreement::Neither => {} - BlanketAgreement::Either => { - if id.is_osi_approved() { - allow!(IsOsiApproved); - } else if id.is_fsf_free_libre() { - allow!(IsFsfFree); - } - } - BlanketAgreement::Both => { - if id.is_fsf_free_libre() && id.is_osi_approved() { - allow!(IsBothFreeAndOsi); + match dep_cfg.allow_osi_fsf_free { + BlanketAgreement::Neither => {} + BlanketAgreement::Either => { + if id.is_osi_approved() { + allow!(IsOsiApproved); + } else if id.is_fsf_free_libre() { + allow!(IsFsfFree); + } } - } - BlanketAgreement::Osi => { - if id.is_osi_approved() { - allow!(IsOsiApproved); + BlanketAgreement::Both => { + if id.is_fsf_free_libre() && id.is_osi_approved() { + allow!(IsBothFreeAndOsi); + } } - } - BlanketAgreement::Fsf => { - if id.is_fsf_free_libre() { - allow!(IsFsfFree); + BlanketAgreement::Osi => { + if id.is_osi_approved() { + allow!(IsOsiApproved); + } } - } - BlanketAgreement::OsiOnly => { - if id.is_osi_approved() { + BlanketAgreement::Fsf => { if id.is_fsf_free_libre() { - deny!(IsFsfFree); - } else { - allow!(IsOsiApproved); + allow!(IsFsfFree); } } - } - BlanketAgreement::FsfOnly => { - if id.is_fsf_free_libre() { + BlanketAgreement::OsiOnly => { if id.is_osi_approved() { - deny!(IsOsiApproved); - } else { - allow!(IsFsfFree); + if id.is_fsf_free_libre() { + deny!(IsFsfFree); + } else { + allow!(IsOsiApproved); + } + } + } + BlanketAgreement::FsfOnly => { + if id.is_fsf_free_libre() { + if id.is_osi_approved() { + deny!(IsOsiApproved); + } else { + allow!(IsFsfFree); + } } } } } - } - // 5. Whelp, this license just won't do! - match cfg.default { - LintLevel::Deny => { - deny!(Default); - } - LintLevel::Warn => { - warnings += 1; - allow!(Default); - } - LintLevel::Allow => { - allow!(Default); + // 5. Whelp, this license just won't do! + match dep_cfg.default { + LintLevel::Deny => { + deny!(Default); + } + LintLevel::Warn => { + warnings += 1; + allow!(Default); + } + LintLevel::Allow => { + allow!(Default); + } } + } else { + deny!(NotExplicitlyAllowed); } }); @@ -241,10 +246,15 @@ fn evaluate_expression( "license is OSI approved https://opensource.org/licenses", Reason::ExplicitAllowance => "license is explicitly allowed", Reason::ExplicitException => "license is explicitly allowed via an exception", + Reason::NotExplicitlyAllowed => "license was not explicitly allowed", Reason::IsBothFreeAndOsi => "license is FSF AND OSI approved", Reason::IsCopyleft => "license is considered copyleft", Reason::Default => { - match cfg.default { + match cfg + .deprecated + .as_ref() + .map_or(LintLevel::Deny, |d| d.default) + { LintLevel::Deny => "not explicitly allowed", LintLevel::Warn => "warned by default", LintLevel::Allow => "allowed by default", @@ -315,7 +325,12 @@ pub fn check( )); } LicenseInfo::Unlicensed => { - let severity = match ctx.cfg.unlicensed { + let severity = match ctx + .cfg + .deprecated + .as_ref() + .map_or(LintLevel::Deny, |d| d.unlicensed) + { LintLevel::Allow => Severity::Note, LintLevel::Warn => Severity::Warning, LintLevel::Deny => Severity::Error, diff --git a/src/licenses/cfg.rs b/src/licenses/cfg.rs index 62e0e0df..1599421a 100644 --- a/src/licenses/cfg.rs +++ b/src/licenses/cfg.rs @@ -1,26 +1,5 @@ #![cfg_attr(docsrs, doc(include = "../../docs/licenses/cfg.md"))] -//! If a `[license]` configuration section, cargo-deny will use the default -//! configuration. -//! -//! ``` -//! use cargo_deny::{LintLevel, licenses::cfg::Config}; -//! -//! let dc = Config::default(); -//! -//! assert_eq!(dc.unlicensed, LintLevel::Deny); -//! assert_eq!( -//! dc.allow_osi_fsf_free, -//! cargo_deny::licenses::cfg::BlanketAgreement::Neither -//! ); -//! assert_eq!(dc.copyleft, LintLevel::Warn); -//! assert_eq!(dc.confidence_threshold, 0.8); -//! assert!(dc.deny.is_empty()); -//! assert!(dc.allow.is_empty()); -//! assert!(dc.clarify.is_empty()); -//! assert!(dc.exceptions.is_empty()); -//! ``` - use crate::{ cfg::{deprecated, PackageSpec, ValidationContext}, diag::{Diagnostic, FileId, Label}, @@ -215,9 +194,8 @@ impl serde::Serialize for Licensee { } } -/// Top level configuration for the a license check -pub struct Config { - pub private: Private, +#[cfg_attr(test, derive(serde::Serialize))] +pub(crate) struct Deprecated { /// Determines what happens when license information cannot be determined /// for a crate pub unlicensed: LintLevel, @@ -229,11 +207,16 @@ pub struct Config { /// Determines what happens when a license doesn't match any previous /// predicates pub default: LintLevel, + /// Licenses that will be rejected in a license expression + pub deny: Vec, +} + +/// Top level configuration for the a license check +pub struct Config { + pub private: Private, /// The minimum confidence threshold we allow when determining the license /// in a text file, on a 0.0 (none) to 1.0 (maximum) scale pub confidence_threshold: f32, - /// Licenses that will be rejected in a license expression - pub deny: Vec, /// Licenses that will be allowed in a license expression pub allow: Vec, /// Determines the response to licenses in th `allow`ed list which do not @@ -248,25 +231,22 @@ pub struct Config { /// If true, performs license checks for dev-dependencies for workspace /// crates as well pub include_dev: bool, - deprecated: Vec, + deprecated: Option, + deprecated_spans: Vec, } impl Default for Config { fn default() -> Self { Self { private: Private::default(), - unlicensed: LintLevel::Deny, - allow_osi_fsf_free: BlanketAgreement::default(), - copyleft: LintLevel::Warn, - default: LintLevel::Deny, unused_allowed_license: LintLevel::Warn, confidence_threshold: DEFAULT_CONFIDENCE_THRESHOLD, - deny: Vec::new(), allow: Vec::new(), clarify: Vec::new(), exceptions: Vec::new(), include_dev: false, - deprecated: Vec::new(), + deprecated: None, + deprecated_spans: Vec::new(), } } } @@ -275,6 +255,8 @@ impl<'de> Deserialize<'de> for Config { fn deserialize(value: &mut Value<'de>) -> Result { let mut th = TableHelper::new(value)?; + let version = th.optional("version").unwrap_or(1); + let mut fdeps = Vec::new(); let private = th.optional("private").unwrap_or_default(); @@ -297,20 +279,28 @@ impl<'de> Deserialize<'de> for Config { th.finalize(None)?; + let deprecated = if version <= 1 { + Some(Deprecated { + unlicensed, + allow_osi_fsf_free, + copyleft, + default, + deny, + }) + } else { + None + }; + Ok(Self { private, - unlicensed, - allow_osi_fsf_free, - copyleft, - default, confidence_threshold, - deny, allow, unused_allowed_license, clarify, exceptions, include_dev, - deprecated: fdeps, + deprecated, + deprecated_spans: fdeps, }) } } @@ -345,7 +335,11 @@ impl crate::cfg::UnvalidatedConfig for Config { } } - let mut denied = self.deny; + let mut deprecated = self.deprecated; + + let mut denied = deprecated + .as_mut() + .map_or(Vec::new(), |d| std::mem::take(&mut d.deny)); let mut allowed = self.allow; denied.par_sort(); @@ -408,7 +402,7 @@ impl crate::cfg::UnvalidatedConfig for Config { // Output any deprecations, we'll remove the fields at the same time we // remove all the logic they drive - for dep in self.deprecated { + for dep in self.deprecated_spans { ctx.push( Deprecated { reason: DeprecationReason::WillBeRemoved(Some( @@ -424,17 +418,14 @@ impl crate::cfg::UnvalidatedConfig for Config { ValidConfig { file_id: ctx.cfg_id, private: self.private, - unlicensed: self.unlicensed, - copyleft: self.copyleft, - default: self.default, unused_allowed_license: self.unused_allowed_license, - allow_osi_fsf_free: self.allow_osi_fsf_free, confidence_threshold: self.confidence_threshold, clarifications, exceptions, denied, allowed, ignore_sources, + deprecated, include_dev: self.include_dev, } } @@ -523,17 +514,14 @@ pub struct ValidException { pub struct ValidConfig { pub file_id: FileId, pub private: Private, - pub unlicensed: LintLevel, - pub copyleft: LintLevel, pub unused_allowed_license: LintLevel, - pub allow_osi_fsf_free: BlanketAgreement, - pub default: LintLevel, pub confidence_threshold: f32, pub denied: Vec, pub allowed: Vec, pub clarifications: Vec, pub exceptions: Vec, pub ignore_sources: Vec, + pub(crate) deprecated: Option, pub include_dev: bool, } diff --git a/src/licenses/snapshots/cargo_deny__licenses__cfg__test__deserializes_licenses_cfg-2.snap b/src/licenses/snapshots/cargo_deny__licenses__cfg__test__deserializes_licenses_cfg-2.snap index b59d7789..3f1abe8e 100644 --- a/src/licenses/snapshots/cargo_deny__licenses__cfg__test__deserializes_licenses_cfg-2.snap +++ b/src/licenses/snapshots/cargo_deny__licenses__cfg__test__deserializes_licenses_cfg-2.snap @@ -11,11 +11,7 @@ expression: validated "sekrets" ] }, - "unlicensed": "warn", - "copyleft": "deny", "unused_allowed_license": "warn", - "allow_osi_fsf_free": "Both", - "default": "warn", "confidence_threshold": 0.95, "denied": [ "BSD-2-Clause", @@ -53,5 +49,12 @@ expression: validated } ], "ignore_sources": [], + "deprecated": { + "unlicensed": "warn", + "allow_osi_fsf_free": "Both", + "copyleft": "deny", + "default": "warn", + "deny": [] + }, "include_dev": false }