diff --git a/Cargo.lock b/Cargo.lock index c310ecb..385d77f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,19 +84,15 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8340c0ac2fd81daf453f19474b30c75d3b1152c5850c31b3519e20412a7f92d7" dependencies = [ - "forensicnomicon-core 1.3.0", + "forensicnomicon-core", "forensicnomicon-data", ] [[package]] name = "forensicnomicon-core" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26131e0c8a646fba012fc958151d480b3d17ddac27f3da2fa37e26a9fdde1e63" - -[[package]] -name = "forensicnomicon-core" -version = "1.4.0" +checksum = "21800c5e29085274fbb324be30790894481c9c5faf8c659b3d0d994840ca0941" [[package]] name = "forensicnomicon-data" @@ -104,7 +100,7 @@ version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e1239a47f728cf7a88d7508f21a446960ae2e7eae41ad14a6bf7caa61548fcf" dependencies = [ - "forensicnomicon-core 1.3.0", + "forensicnomicon-core", ] [[package]] @@ -196,7 +192,7 @@ dependencies = [ name = "peripheral-core" version = "0.8.1" dependencies = [ - "forensicnomicon-core 1.4.0", + "forensicnomicon-core", "shellitem", "winreg-core", ] diff --git a/core/Cargo.toml b/core/Cargo.toml index 4acaf14..809d27c 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -25,7 +25,7 @@ shellitem = "0.2" # Common USB VID->vendor facts are KNOWLEDGE (forensicnomicon), not reader data. # Path dep during the coordinated in-flight change; switch to the registry version # once forensicnomicon publishes the usb_vendors release (bottom-up, ADR-0006). -forensicnomicon-core = { version = "1.4", path = "../../../knowledge/forensicnomicon/crates/core" } +forensicnomicon-core = { version = "1.4" } [lints] workspace = true diff --git a/core/src/lib.rs b/core/src/lib.rs index d8d9707..838f8bb 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -340,4 +340,64 @@ mod tests { ); assert_eq!(Stamp::inferred(10).confidence, Confidence::Inferred); } + + /// A connection carrying only the ids the name lookups read. Every other + /// field is empty on purpose: these two methods must not depend on them. + fn connection(vid: Option, pid: Option) -> DeviceConnection { + DeviceConnection { + bus: Bus::Usb, + device_class_guid: None, + vid, + pid, + device_serial: None, + serial_is_os_generated: false, + friendly_name: None, + device_instance_id: String::new(), + first_install: None, + last_install: None, + last_arrival: None, + last_removal: None, + parent_id_prefix: None, + volume_guid: None, + drive_letter: None, + volume_serial: None, + disk_signature: None, + dma_capable: false, + mitre: Vec::new(), + source: Provenance { + file: String::new(), + line: 0, + key_path: None, + }, + } + } + + const IDS: &str = "0781 SanDisk Corp.\n\t5583 Ultra Fit\n"; + + #[test] + fn vendor_name_resolves_a_known_vid_and_stays_none_otherwise() { + let db = crate::usb_ids::UsbIdDb::parse(IDS); + assert_eq!( + connection(Some(0x0781), None).vendor_name(&db), + Some("SanDisk Corp.") + ); + // Unknown vid: the lookup misses rather than inventing a name. + assert_eq!(connection(Some(0xFFFF), None).vendor_name(&db), None); + // Absent vid: nothing to look up. + assert_eq!(connection(None, None).vendor_name(&db), None); + } + + #[test] + fn product_name_needs_both_ids() { + let db = crate::usb_ids::UsbIdDb::parse(IDS); + assert_eq!( + connection(Some(0x0781), Some(0x5583)).product_name(&db), + Some("Ultra Fit") + ); + // Each half alone falls to the `_ => None` arm: a pid without its vid is + // not a product key, and a vid alone does not name a product. + assert_eq!(connection(Some(0x0781), None).product_name(&db), None); + assert_eq!(connection(None, Some(0x5583)).product_name(&db), None); + assert_eq!(connection(None, None).product_name(&db), None); + } } diff --git a/core/src/usb_ids.rs b/core/src/usb_ids.rs index fc989f2..cbcd219 100644 --- a/core/src/usb_ids.rs +++ b/core/src/usb_ids.rs @@ -169,4 +169,38 @@ C 00 (Defined at Interface level)\n\ assert_eq!(db.vendor_name(0x0781), Some("SanDisk Corp.")); assert!(db.vendor_count() >= 20); } + + #[test] + fn interface_lines_are_skipped_not_read_as_products() { + // Two leading tabs is an interface line inside a product. Reading it as + // a product would register 0x0781:0x0000 "Mass Storage" — a device that + // does not exist. Real usb.ids nests these under most storage devices. + let db = UsbIdDb::parse("0781 SanDisk Corp.\n\t5583 Ultra Fit\n\t\t00 Mass Storage\n"); + assert_eq!(db.product_name(0x0781, 0x5583), Some("Ultra Fit")); + assert_eq!(db.product_name(0x0781, 0x0000), None); + } + + #[test] + fn four_hex_chars_alone_do_not_make_an_id_line() { + // Both lines open with four valid hex characters and are still rejected, + // so they exercise the separator check rather than the hex parse — the + // section headers in FIXTURE (`C 00`) fail earlier, at the hex step. + let db = UsbIdDb::parse("0781 SanDisk Corp.\n0951\tKingston\n"); + assert_eq!(db.vendor_count(), 0); + assert!(db.is_empty()); + assert_eq!(db.vendor_name(0x0781), None); + } + + #[test] + fn a_wider_separator_is_accepted_and_keeps_the_surplus_in_the_name() { + // Current behaviour, asserted so a change is visible rather than silent. + // `parse_id_line`'s doc says "exactly two spaces", but the check reads + // only positions 4..6, so a third space falls into the name and survives + // — `trim_end` does not touch a leading one. usb.ids uses exactly two + // spaces throughout, so no real line reaches this; if the name is ever + // trimmed at the front, this assertion is where it shows up. + let db = UsbIdDb::parse("0abc Three Spaces\n"); + assert_eq!(db.vendor_count(), 1); + assert_eq!(db.vendor_name(0x0abc), Some(" Three Spaces")); + } } diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index 2772ccb..a581366 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -2,3 +2,15 @@ # cargo-vet audits file [audits] + +[[trusted.forensicnomicon-core]] +criteria = "safe-to-deploy" +user-id = 347968 # Albert Hui (h4x0r) +start = "2026-06-28" +end = "2027-08-02" + +[[trusted.shellitem]] +criteria = "safe-to-deploy" +user-id = 347968 # Albert Hui (h4x0r) +start = "2026-06-13" +end = "2027-08-02" diff --git a/supply-chain/config.toml b/supply-chain/config.toml index 59e6adc..01dcc24 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -54,10 +54,6 @@ criteria = "safe-to-deploy" version = "1.8.0" criteria = "safe-to-deploy" -[[exemptions.forensicnomicon-core]] -version = "1.3.0" -criteria = "safe-to-deploy" - [[exemptions.forensicnomicon-data]] version = "1.3.1" criteria = "safe-to-deploy" diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index 0da619f..a0d7419 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -1,6 +1,20 @@ # cargo-vet imports lock +[[publisher.forensicnomicon-core]] +version = "1.5.0" +when = "2026-07-29" +user-id = 347968 +user-login = "h4x0r" +user-name = "Albert Hui" + +[[publisher.shellitem]] +version = "0.2.1" +when = "2026-07-25" +user-id = 347968 +user-login = "h4x0r" +user-name = "Albert Hui" + [[publisher.unicode-width]] version = "0.1.14" when = "2024-09-19"