Skip to content

Commit 2aa62d4

Browse files
authored
Fix exception issue and add regression tests (#16)
* Fix exception issue and add regression tests * Bump version
1 parent 66a37a6 commit 2aa62d4

10 files changed

+889
-18
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "conda-deny"
33
description = "A CLI tool to check your project's dependencies for license compliance."
4-
version = "0.3.1"
4+
version = "0.3.2"
55
edition = "2021"
66

77
[features]

deny.toml

+2
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ feature-depth = 1
7171
# output a note when they are encountered.
7272
ignore = [
7373
#"RUSTSEC-0000-0000",
74+
# This crate is stable:
75+
"RUSTSEC-2024-0388",
7476
#{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" },
7577
#"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish
7678
#{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" },

src/expression_utils.rs

+52-14
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,20 @@
11
use anyhow::{Context, Result};
2-
use spdx::{Expression, LicenseItem, LicenseReq, ParseMode};
2+
use spdx::{Expression, LicenseReq, ParseMode};
33

4-
pub fn extract_license_ids(expression: &Expression) -> Vec<String> {
4+
pub fn extract_license_texts(expression: &Expression) -> Vec<String> {
55
expression
66
.requirements()
7-
.map(|req| match &req.req.license {
8-
LicenseItem::Spdx { id, .. } => id.name.to_string(),
9-
LicenseItem::Other { lic_ref, .. } => lic_ref.clone(),
10-
})
7+
.map(|req| req.req.to_string())
118
.collect()
129
}
1310

1411
fn check_license_req_safety(license_req: &LicenseReq, safe_licenses: &[Expression]) -> bool {
15-
let safe_license_ids: Vec<String> =
16-
safe_licenses.iter().flat_map(extract_license_ids).collect();
12+
let safe_license_requirements: Vec<String> = safe_licenses
13+
.iter()
14+
.flat_map(extract_license_texts)
15+
.collect();
1716

18-
match &license_req.license {
19-
LicenseItem::Spdx { id, .. } => safe_license_ids.contains(&id.name.to_string()),
20-
LicenseItem::Other { lic_ref, .. } => safe_license_ids.contains(lic_ref),
21-
}
17+
safe_license_requirements.contains(&license_req.to_string())
2218
}
2319

2420
pub fn check_expression_safety(expression: &Expression, safe_licenses: &[Expression]) -> bool {
@@ -43,12 +39,54 @@ mod tests {
4339

4440
use crate::expression_utils::parse_expression;
4541

42+
#[test]
43+
fn test_extract_license_texts() {
44+
let expression = parse_expression("MIT OR GPL-3.0-or-later").unwrap();
45+
let license_texts = extract_license_texts(&expression);
46+
47+
assert_eq!(
48+
license_texts,
49+
vec!["MIT".to_string(), "GPL-3.0-or-later".to_string()]
50+
);
51+
}
52+
53+
#[test]
54+
fn test_license_with_exception() {
55+
let expression = parse_expression("GPL-2.0-only").unwrap();
56+
let safe_licenses = &[Expression::parse("GPL-2.0-only WITH GCC-exception-2.0").unwrap()];
57+
58+
let license_allowed = check_expression_safety(&expression, safe_licenses);
59+
60+
assert!(!license_allowed);
61+
62+
let expression = parse_expression("GPL-2.0-only WITH GCC-exception-2.0").unwrap();
63+
let safe_licenses = &[Expression::parse("GPL-2.0-only").unwrap()];
64+
let license_allowed = check_expression_safety(&expression, safe_licenses);
65+
66+
assert!(!license_allowed);
67+
68+
let expression = parse_expression("GPL-3.0-only WITH GCC-exception-3.1").unwrap();
69+
let safe_licenses = &[Expression::parse("GPL-3.0-only").unwrap()];
70+
let license_allowed = check_expression_safety(&expression, safe_licenses);
71+
72+
assert!(!license_allowed);
73+
74+
let expression = parse_expression("GPL-3.0-only").unwrap();
75+
let safe_licenses = &[Expression::parse("GPL-3.0-only WITH GCC-exception-3.1").unwrap()];
76+
let license_allowed = check_expression_safety(&expression, safe_licenses);
77+
78+
assert!(!license_allowed);
79+
}
80+
4681
#[test]
4782
fn test_extract_license_ids() {
4883
let expression = parse_expression("MIT OR GPL-3.0-or-later").unwrap();
49-
let license_ids = super::extract_license_ids(&expression);
84+
let license_ids = super::extract_license_texts(&expression);
5085

51-
assert_eq!(license_ids, vec!["MIT".to_string(), "GPL-3.0".to_string()]);
86+
assert_eq!(
87+
license_ids,
88+
vec!["MIT".to_string(), "GPL-3.0-or-later".to_string()]
89+
);
5290
}
5391

5492
#[test]

src/license_info.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use colored::*;
99
use crate::{
1010
conda_deny_config::CondaDenyConfig,
1111
conda_meta_entry::{CondaMetaEntries, CondaMetaEntry},
12-
expression_utils::{check_expression_safety, extract_license_ids, parse_expression},
12+
expression_utils::{check_expression_safety, extract_license_texts, parse_expression},
1313
license_whitelist::ParsedLicenseWhitelist,
1414
list,
1515
pixi_lock::get_package_records_for_pixi_lock,
@@ -272,7 +272,7 @@ impl LicenseInfos {
272272
for license_info in &self.license_infos {
273273
match &license_info.license {
274274
LicenseState::Valid(license) => {
275-
let license_ids = extract_license_ids(license);
275+
let license_ids = extract_license_texts(license);
276276
let is_safe = license_ids.iter().all(|license_id_str| {
277277
if let Some(license_id) = spdx::license_id(license_id_str) {
278278
license_id.is_osi_approved()

tests/integration_tests.rs

+9
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,13 @@ mod tests {
128128

129129
println!("Output has {} lines", line_count);
130130
}
131+
132+
#[test]
133+
fn test_exception_check() {
134+
let test_dir = Path::new("tests/test_end_to_end/test_exception_use_case");
135+
136+
let mut command = Command::cargo_bin("conda-deny").unwrap();
137+
command.arg("check").current_dir(test_dir);
138+
command.assert().failure();
139+
}
131140
}

0 commit comments

Comments
 (0)