11//! Checks the licenses of third-party dependencies.
22
3- use cargo_metadata:: { Metadata , Package , PackageId } ;
3+ use cargo_metadata:: { Metadata , Package , PackageId , Resolve } ;
44use std:: collections:: { BTreeSet , HashSet } ;
55use std:: path:: Path ;
66
@@ -50,6 +50,10 @@ const EXCEPTIONS: &[(&str, &str)] = &[
5050 ( "crossbeam-channel" , "MIT/Apache-2.0 AND BSD-2-Clause" ) , // cargo
5151] ;
5252
53+ /// These are the root crates that are part of the runtime. The licenses for
54+ /// these and all their dependencies *must not* be in the exception list.
55+ const RUNTIME_CRATES : & [ & str ] = & [ "std" , "core" , "alloc" , "panic_abort" , "panic_unwind" ] ;
56+
5357/// Which crates to check against the whitelist?
5458const WHITELIST_CRATES : & [ & str ] = & [ "rustc" , "rustc_codegen_llvm" ] ;
5559
@@ -227,14 +231,17 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
227231 }
228232 }
229233 }
234+
230235 let exception_names: Vec < _ > = EXCEPTIONS . iter ( ) . map ( |( name, _license) | * name) . collect ( ) ;
236+ let runtime_ids = compute_runtime_crates ( metadata) ;
237+
231238 // Check if any package does not have a valid license.
232239 for pkg in & metadata. packages {
233240 if pkg. source . is_none ( ) {
234241 // No need to check local packages.
235242 continue ;
236243 }
237- if exception_names. contains ( & pkg. name . as_str ( ) ) {
244+ if !runtime_ids . contains ( & pkg . id ) && exception_names. contains ( & pkg. name . as_str ( ) ) {
238245 continue ;
239246 }
240247 let license = match & pkg. license {
@@ -246,6 +253,13 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
246253 }
247254 } ;
248255 if !LICENSES . contains ( & license. as_str ( ) ) {
256+ if pkg. name == "fortanix-sgx-abi" {
257+ // This is a specific exception because SGX is considered
258+ // "third party". See
259+ // https://github.com/rust-lang/rust/issues/62620 for more. In
260+ // general, these should never be added.
261+ continue ;
262+ }
249263 println ! ( "invalid license `{}` in `{}`" , license, pkg. id) ;
250264 * bad = true ;
251265 }
@@ -366,10 +380,8 @@ fn check_crate_duplicate(metadata: &Metadata, bad: &mut bool) {
366380
367381/// Returns a list of dependencies for the given package.
368382fn deps_of < ' a > ( metadata : & ' a Metadata , pkg_id : & ' a PackageId ) -> Vec < & ' a Package > {
369- let node = metadata
370- . resolve
371- . as_ref ( )
372- . unwrap ( )
383+ let resolve = metadata. resolve . as_ref ( ) . unwrap ( ) ;
384+ let node = resolve
373385 . nodes
374386 . iter ( )
375387 . find ( |n| & n. id == pkg_id)
@@ -392,3 +404,42 @@ fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package
392404 assert ! ( i. next( ) . is_none( ) , "more than one package found for `{}`" , name) ;
393405 result
394406}
407+
408+ /// Finds all the packages that are in the rust runtime.
409+ fn compute_runtime_crates < ' a > ( metadata : & ' a Metadata ) -> HashSet < & ' a PackageId > {
410+ let resolve = metadata. resolve . as_ref ( ) . unwrap ( ) ;
411+ let mut result = HashSet :: new ( ) ;
412+ for name in RUNTIME_CRATES {
413+ let id = & pkg_from_name ( metadata, name) . id ;
414+ normal_deps_of_r ( resolve, id, & mut result) ;
415+ }
416+ result
417+ }
418+
419+ /// Recursively find all normal dependencies.
420+ fn normal_deps_of_r < ' a > (
421+ resolve : & ' a Resolve ,
422+ pkg_id : & ' a PackageId ,
423+ result : & mut HashSet < & ' a PackageId > ,
424+ ) {
425+ if !result. insert ( pkg_id) {
426+ return ;
427+ }
428+ let node = resolve
429+ . nodes
430+ . iter ( )
431+ . find ( |n| & n. id == pkg_id)
432+ . unwrap_or_else ( || panic ! ( "could not find `{}` in resolve" , pkg_id) ) ;
433+ // Don't care about dev-dependencies.
434+ // Build dependencies *shouldn't* matter unless they do some kind of
435+ // codegen. For now we'll assume they don't.
436+ let deps = node. deps . iter ( ) . filter ( |node_dep| {
437+ node_dep
438+ . dep_kinds
439+ . iter ( )
440+ . any ( |kind_info| kind_info. kind == cargo_metadata:: DependencyKind :: Normal )
441+ } ) ;
442+ for dep in deps {
443+ normal_deps_of_r ( resolve, & dep. pkg , result) ;
444+ }
445+ }
0 commit comments