Skip to content
This repository was archived by the owner on May 19, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@djschleen @mirxcle
3 changes: 2 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
{
"type": "lldb",
"request": "launch",
"name": "Debug executable 'trustier' (juiceshop)",
"name": "Debug executable 'trustier' --strict (juiceshop)",
"cargo": {
"args": [
"build",
Expand All @@ -103,6 +103,7 @@
}
},
"args": [
"--strict",
"./tests/_TESTDATA_/juiceshop.cyclonedx.json"
],
"cwd": "${workspaceFolder}"
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[package]
name = "trustier"
version = "0.1.0"
version = "0.1.1"
edition = "2021"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
clap = { version = "4.5.17", features = ["derive"] }
clap = { version = "4.5.20", features = ["derive"] }
cyclonedx-bom = "0.7.0"
surf = "2.3.2"
async-std = "1.13.0"
Expand Down
38 changes: 27 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
## Table of Contents

- [Overview](#overview)
- [The importance of undetstanding supply chain attacks](#the-importance-of-undetstanding-supply-chain-attacks)
- [The importance of understanding supply chain attacks](#the-importance-of-understanding-supply-chain-attacks)
- [Installation](#installation)
- [Example Usage](#example-usage)
- [Application Arguments](#application-arguments)
- [Example Usage](#example-usage)
- [Troubleshooting](#troubleshooting)
- [SBOM Validation](#sbom-validation)
- [Supported CycloneDX versions](#supported-cyclonedx-versions)
- [Credits](#credits)

## Overview
Expand Down Expand Up @@ -59,16 +61,16 @@ Sources:

Binaries for Mac, Linux, and Windows Platforms are available from the [Releases](https://github.com/devops-kung-fu/trustier/releases) section of this repsitory. Download, unpack, and use!

__NOTE:__ The application has not been tested on all platforms and architectures. If you experience any issues, please report them [here](
https://github.com/devops-kung-fu/trustier/issues)
**NOTE:** The application has not been tested on all platforms and architectures. If you experience any issues, please report them [here](https://github.com/devops-kung-fu/trustier/issues)

## Application Arguments

| Argument | Description |
| ---------------------- | ----------------------------------------------------------------------------------------------------------- |
| `<SBOM>` | The SBOM (Software Bill of Materials) to process. This argument is required. |
| `--ratelimit <MS>` | Optional time in milliseconds to pause before making requests to https://trustypkg.dev. Defaults to 500 ms. |
| `--output_file <FILE>` | Optional file name to write JSON output to. If not provided, output will be printed to the console. |
| Argument | Description |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `<SBOM>` | The SBOM (Software Bill of Materials) to process. This argument is required. |
| `--ratelimit <MS>` | Optional time in milliseconds to pause before making requests to https://trustypkg.dev. Defaults to 500 ms. |
| `--output_file <FILE>` | Optional file name to write JSON output to. If not provided, output will be printed to the console. |
| `--strict` | If set, will perform a strict SBOM validation, otherwise `trustier` will attempt to process the SBOM. Optional and defaults to false |

## Example Usage

Expand All @@ -82,6 +84,9 @@ trustier sbom_file.json --ratelimit 1000
# Optional output_file argument
trustier sbom_file.json --output_file output.json

# Perform strict SBOM validation
trustier sbom_file.json --strict --output_file output.json

# Takes an SBOM from STDIN and outputs JSON without any console decoration
cat sbom_file.json | trustier -

Expand All @@ -91,13 +96,24 @@ cat sbom_file.json | trustier -

## Troubleshooting

During testing, we found there were some required fields needed in the SBOM in order to be considered valid. Ensure at minimum you have the following fields in your components:
### SBOM Validation

During testing, we found there were some required fields needed in the SBOM in order to be considered valid. We
utilized the validation logic provided in the CycloneDX dependencies we use in `trustier`. In version 0.1.1, we
disabled validation by default, but if you wish to utilize strict validation then utilize the `--strict` flag.

Ensure at minimum you have the following fields in your components if you are using strict validation:

- `name`
- `purl`
- `type`

__NOTE:__ `trustier` does not support SPDX formatted SBOMS at this time.
### Supported CycloneDX versions

`trustier` relies on [CycloneDX](https://github.com/CycloneDX/cyclonedx-rust-cargo/blob/main/cyclonedx-bom/README.md) to
load and work with SBOMs. This provides a limitation of only supporting versions 1.3, 1.4, and 1.5 of the CycloneDX specification at this time.

**NOTE:** `trustier` does not support SPDX formatted SBOMS at this time.

## Credits

Expand Down
30 changes: 17 additions & 13 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,18 @@ struct Args {
//Optional file name to write json output to
#[arg(short, long, required = false)]
output_file: Option<String>,

//Optional flag to enable strict SBOM validation
#[arg(short, long, default_value_t = false)]
strict: bool,
}

fn main() {
let args = Args::parse();

if args.sbom.is_file() {
print_ascii_header();
}

if args.sbom.is_file() {
conditional_println!(args.sbom.is_file(), "* Reading SBOM from file...");
} else {
conditional_println!(args.sbom.is_file(), "* Reading SBOM from stdin...");
conditional_println!(true, "* Reading SBOM from file...");
}

let file_contents = match args.sbom.clone().into_reader() {
Expand All @@ -62,17 +61,21 @@ fn main() {
let bom = match Bom::parse_from_json_v1_5(file_contents) {
Ok(bom) => bom,
Err(e) => {
eprintln!("Error parsing SBOM: {}", e);
eprintln!("* Error parsing SBOM! \n\n{}", e);
return;
}
};

if !bom.validate().passed() {
eprintln!("* Provided input is not a valid SBOM");
return;
if args.strict {
conditional_println!(args.sbom.is_file(), "* strict SBOM checking enabled...");
if !bom.validate().passed() {
eprintln!("* Provided input is not a valid SBOM");
return;
} else {
conditional_println!(args.sbom.is_file(), "* SBOM is valid");
}
}

conditional_println!(args.sbom.is_file(), "* SBOM is valid");
if let Some(serial_number) = &bom.serial_number {
conditional_println!(
args.sbom.is_file(),
Expand Down Expand Up @@ -141,7 +144,8 @@ async fn process_sbom(
collected_purls.len()
);
} else {
conditional_println!(args.sbom.is_file(), "* Nothing to do...\n")
conditional_println!(args.sbom.is_file(), "* Nothing to do...\n");
return Ok(());
}

let responses = fetch_purl_bodies(&collected_purls, args.ratelimit).await?;
Expand All @@ -156,7 +160,7 @@ async fn process_sbom(
}
}
fs::write(of_clone, json).expect("Failed to write JSON to file");
conditional_println!(args.sbom.is_file(), "\n* JSON written to file: {}\n", of);
conditional_println!(args.sbom.is_file(), "* JSON written to file: {}\n", of);
} else {
let json = serde_json::to_string_pretty(&responses).unwrap();
println!("{}", json);
Expand Down