Skip to content

Commit 1ebac6f

Browse files
authored
Merge pull request #130 from rust-secure-code/cyclic-dep-fix
Fix `cargo auditable` sometimes encoding a cyclic dependency graph
2 parents ab130ca + dc34b16 commit 1ebac6f

File tree

11 files changed

+131
-10
lines changed

11 files changed

+131
-10
lines changed

auditable-serde/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,7 @@ schemars = {version = "0.8.10", optional = true }
2929
[[example]]
3030
name = "json-to-toml"
3131
required-features = ["toml"]
32+
33+
[[example]]
34+
name = "from-metadata"
35+
required-features = ["from_metadata"]

auditable-serde/src/lib.rs

+28-10
Original file line numberDiff line numberDiff line change
@@ -388,10 +388,15 @@ impl TryFrom<&cargo_metadata::Metadata> for VersionInfo {
388388
// dev-dependencies are not included
389389
let package: &mut Package = &mut packages[id_to_index[package_id]];
390390
// Dependencies
391-
for dep in node.dependencies.iter() {
392-
// omit package if it is a development-only dependency
393-
let dep_id = dep.repr.as_str();
394-
if id_to_dep_kind[dep_id] != PrivateDepKind::Development {
391+
for dep in node.deps.iter() {
392+
// Omit the graph edge if this is a development dependency
393+
// to fix https://github.com/rustsec/rustsec/issues/1043
394+
// It is possible that something that we depend on normally
395+
// is also a dev-dependency for something,
396+
// and dev-dependencies are allowed to have cycles,
397+
// so we may end up encoding cyclic graph if we don't handle that.
398+
let dep_id = dep.pkg.repr.as_str();
399+
if strongest_dep_kind(&dep.dep_kinds) != PrivateDepKind::Development {
395400
package.dependencies.push(id_to_index[dep_id]);
396401
}
397402
}
@@ -490,23 +495,36 @@ mod tests {
490495
#![allow(unused_imports)] // otherwise conditional compilation emits warnings
491496
use super::*;
492497
use std::fs;
493-
use std::{convert::TryInto, path::PathBuf};
498+
use std::{
499+
convert::TryInto,
500+
path::{Path, PathBuf},
501+
};
494502

495-
#[cfg(feature = "toml")]
496503
#[cfg(feature = "from_metadata")]
497-
fn load_own_metadata() -> cargo_metadata::Metadata {
504+
fn load_metadata(cargo_toml_path: &Path) -> cargo_metadata::Metadata {
498505
let mut cmd = cargo_metadata::MetadataCommand::new();
499-
let cargo_toml_path =
500-
PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()).join("Cargo.toml");
501506
cmd.manifest_path(cargo_toml_path);
502507
cmd.exec().unwrap()
503508
}
504509

510+
#[test]
511+
#[cfg(feature = "from_metadata")]
512+
fn dependency_cycle() {
513+
let cargo_toml_path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap())
514+
.join("tests/fixtures/cargo-audit-dep-cycle/Cargo.toml");
515+
let metadata = load_metadata(&cargo_toml_path);
516+
let version_info_struct: VersionInfo = (&metadata).try_into().unwrap();
517+
let json = serde_json::to_string(&version_info_struct).unwrap();
518+
VersionInfo::from_str(&json).unwrap(); // <- the part we care about succeeding
519+
}
520+
505521
#[test]
506522
#[cfg(feature = "toml")]
507523
#[cfg(feature = "from_metadata")]
508524
fn to_toml() {
509-
let metadata = load_own_metadata();
525+
let cargo_toml_path =
526+
PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()).join("Cargo.toml");
527+
let metadata = load_metadata(&cargo_toml_path);
510528
let version_info_struct: VersionInfo = (&metadata).try_into().unwrap();
511529
let _lockfile_struct: cargo_lock::Lockfile = (&version_info_struct).try_into().unwrap();
512530
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target

auditable-serde/tests/fixtures/cargo-audit-dep-cycle/Cargo.lock

+24
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[workspace]
2+
members = ["a", "b"]
3+
4+
[package]
5+
name = "cargo-audit-dep-cycle"
6+
version = "0.1.0"
7+
edition = "2021"
8+
9+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
10+
11+
[dependencies]
12+
a = { path = "a" }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Minimal example for cyclic dependency graph in audit data
2+
3+
When building this project with `cargo auditable build`, and then running `cargo audit` on it, this error is printed:
4+
5+
```
6+
error: parse error: Failed to deserialize audit data from JSON: The input JSON specifies a cyclic dependency graph
7+
```
8+
9+
This repository serves as a minimal example for reproducing the issue.
10+
11+
The issue was reported [here](https://github.com/rustsec/rustsec/issues/1043).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "a"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
b = { path = "../b" }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
pub fn add(left: usize, right: usize) -> usize {
2+
left + right
3+
}
4+
5+
#[cfg(test)]
6+
mod tests {
7+
use super::*;
8+
9+
#[test]
10+
fn it_works() {
11+
let result = add(2, 2);
12+
assert_eq!(result, 4);
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "b"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
10+
[dev-dependencies]
11+
a = { path = "../a" }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
pub fn add(left: usize, right: usize) -> usize {
2+
left + right
3+
}
4+
5+
#[cfg(test)]
6+
mod tests {
7+
use super::*;
8+
9+
#[test]
10+
fn it_works() {
11+
let result = add(2, 2);
12+
assert_eq!(result, 4);
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
println!("Hello, world!");
3+
}

0 commit comments

Comments
 (0)