chore(tools/rust-crates-advisory): move custom checker to user dir

Profpatsch originally implemented an advisory checker from scratch in
Rust. We now ended up just using cargo-audit for the global checks
exposed via CI and the custom implementation is unused. To clean up
//tools/rust-crates-advisory a bit, we can move the unused parts to his
user directory.

Change-Id: Iacbd27c163edd07c804220fd1b3569c23aebd3e7
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7171
Tested-by: BuildkiteCI
Reviewed-by: Profpatsch <mail@profpatsch.de>
This commit is contained in:
sterni 2022-11-06 19:10:16 +01:00
parent d92ca10990
commit 8699370fae
3 changed files with 69 additions and 60 deletions

View file

@ -1,119 +0,0 @@
extern crate semver;
extern crate toml;
use std::io::Write;
/// reads a security advisory of the form
/// https://github.com/RustSec/advisory-db/blob/a24932e220dfa9be8b0b501210fef8a0bc7ef43e/EXAMPLE_ADVISORY.md
/// and a crate version number,
/// and returns 0 if the crate version is patched
/// and returns 1 if the crate version is *not* patched
///
/// If PRINT_ADVISORY is set, the advisory is printed if it matches.
fn main() {
let mut args = std::env::args_os();
let file = args.nth(1).expect("security advisory md file is $1");
let crate_version = args
.nth(0)
.expect("crate version is $2")
.into_string()
.expect("crate version string not utf8");
let crate_version = semver::Version::parse(&crate_version)
.expect(&format!("this is not a semver version: {}", &crate_version));
let filename = file.to_string_lossy();
let content = std::fs::read(&file).expect(&format!("could not read {}", filename));
let content = std::str::from_utf8(&content)
.expect(&format!("file {} was not encoded as utf-8", filename));
let content = content.trim_start();
let toml_start = content
.strip_prefix("```toml")
.expect(&format!("file did not start with ```toml: {}", filename));
let toml_end_index = toml_start.find("```").expect(&format!(
"the toml section did not end, no `` found: {}",
filename
));
let toml = &toml_start[..toml_end_index];
let toml: toml::Value = toml::de::from_slice(toml.as_bytes())
.expect(&format!("could not parse toml: {}", filename));
let versions = toml
.as_table()
.expect(&format!("the toml is not a table: {}", filename))
.get("versions")
.expect(&format!(
"the toml does not contain the versions field: {}",
filename
))
.as_table()
.expect(&format!(
"the toml versions field must be a table: {}",
filename
));
let unaffected = match versions.get("unaffected") {
Some(u) => u
.as_array()
.expect(&format!(
"the toml versions.unaffected field must be a list of semvers: {}",
filename
))
.iter()
.map(|v| {
semver::VersionReq::parse(
v.as_str()
.expect(&format!("the version field {} is not a string", v)),
)
.expect(&format!(
"the version field {} is not a valid semver VersionReq",
v
))
})
.collect(),
None => vec![],
};
let mut patched: Vec<semver::VersionReq> = versions
.get("patched")
.expect(&format!(
"the toml versions.patched field must exist: {}",
filename
))
.as_array()
.expect(&format!(
"the toml versions.patched field must be a list of semvers: {}",
filename
))
.iter()
.map(|v| {
semver::VersionReq::parse(
v.as_str()
.expect(&format!("the version field {} is not a string", v)),
)
.expect(&format!(
"the version field {} is not a valid semver VersionReq",
v
))
})
.collect();
patched.extend_from_slice(&unaffected[..]);
let is_patched_or_unaffected = patched.iter().any(|req| req.matches(&crate_version));
if is_patched_or_unaffected {
std::process::exit(0);
} else {
if std::env::var_os("PRINT_ADVISORY").is_some() {
write!(
std::io::stderr(),
"Advisory {} matched!\n{}\n",
filename,
content
)
.unwrap();
}
std::process::exit(1);
}
}

View file

@ -3,16 +3,12 @@
let
bins =
depot.nix.getBins pkgs.s6-portable-utils [ "s6-ln" "s6-cat" "s6-echo" "s6-mkdir" "s6-test" "s6-touch" "s6-dirname" ]
// depot.nix.getBins pkgs.lr [ "lr" ]
// depot.nix.getBins pkgs.cargo-audit [ "cargo-audit" ]
depot.nix.getBins pkgs.cargo-audit [ "cargo-audit" ]
// depot.nix.getBins pkgs.jq [ "jq" ]
// depot.nix.getBins pkgs.findutils [ "find" ]
// depot.nix.getBins pkgs.gnused [ "sed" ]
;
crate-advisories = "${depot.third_party.rustsec-advisory-db}/crates";
our-crates = lib.filter (v: v ? outPath)
(builtins.attrValues depot.third_party.rust-crates);
@ -27,59 +23,6 @@ let
'')
our-crates);
check-security-advisory = depot.nix.writers.rustSimple
{
name = "parse-security-advisory";
dependencies = [
depot.third_party.rust-crates.toml
depot.third_party.rust-crates.semver
];
}
(builtins.readFile ./check-security-advisory.rs);
# $1 is the directory with advisories for crate $2 with version $3
check-crate-advisory = depot.nix.writeExecline "check-crate-advisory" { readNArgs = 3; } [
"pipeline"
[ bins.lr "-0" "-t" "depth == 1" "$1" ]
"forstdin"
"-0"
"-Eo"
"0"
"advisory"
"if"
[ depot.tools.eprintf "advisory %s\n" "$advisory" ]
check-security-advisory
"$advisory"
"$3"
];
# Run through everything in the `crate-advisories` repository
# and check whether we can parse all the advisories without crashing.
test-parsing-all-security-advisories = depot.nix.runExecline "check-all-our-crates" { } [
"pipeline"
[ bins.lr "-0" "-t" "depth == 1" crate-advisories ]
"if"
[
# this will succeed as long as check-crate-advisory doesnt `panic!()` (status 101)
"forstdin"
"-0"
"-E"
"-x"
"101"
"crate_advisories"
check-crate-advisory
"$crate_advisories"
"foo"
"0.0.0"
]
"importas"
"out"
"out"
bins.s6-touch
"$out"
];
lock-file-report = pkgs.writers.writeBash "lock-file-report" ''
set -u
@ -161,8 +104,6 @@ let
in
depot.nix.readTree.drvTargets {
inherit
test-parsing-all-security-advisories
check-crate-advisory
lock-file-report
;