Skip to content

feat: store and verify PGP signatures #1631

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
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
38 changes: 38 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ members = [
"modules/graphql",
"modules/importer",
"modules/ingestor",
"modules/signature",
"modules/storage",
"modules/ui",
"modules/user",
Expand Down Expand Up @@ -120,8 +121,9 @@ semver = "1"
serde = "1.0.183"
serde-cyclonedx = "0.9.1"
serde_json = "1.0.114"
serde_with = "3.11.0"
serde_with = { version = "3.12.0", features = ["base64"] }
serde_yml = { package = "serde_yaml_ng", version = "0.10" }
sequoia-openpgp = { version = "2", default-features = false }
sha2 = "0.10.8"
spdx = "0.10.6"
spdx-expression = "0.5.2"
Expand Down Expand Up @@ -169,6 +171,7 @@ trustify-module-fundamental = { path = "modules/fundamental" }
trustify-module-graphql = { path = "modules/graphql" }
trustify-module-importer = { path = "modules/importer" }
trustify-module-ingestor = { path = "modules/ingestor" }
trustify-module-signature = { path = "modules/signature" }
trustify-module-storage = { path = "modules/storage" }
trustify-module-ui = { path = "modules/ui", default-features = false }
trustify-module-user = { path = "modules/user" }
Expand Down
20 changes: 12 additions & 8 deletions common/auth/src/authenticator/default.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
use std::collections::HashMap;

/// A convenience function to get the default scopes in an allocated form.
pub fn default_scope_mappings() -> HashMap<String, Vec<String>> {
DEFAULT_SCOPE_MAPPINGS
.iter()
.map(|(k, v)| (k.to_string(), v.iter().map(ToString::to_string).collect()))
.collect()
}

/// Default scope mappings (in a `const` form).
///
/// See [`default_scope_mappings`] for a `HashMap` form.
Expand All @@ -14,6 +22,7 @@ pub const DEFAULT_SCOPE_MAPPINGS: &[(&str, &[&str])] = &[
"create.importer",
"create.metadata",
"create.sbom",
"create.trustAnchor",
"create.weakness",
"upload.dataset",
],
Expand All @@ -26,6 +35,7 @@ pub const DEFAULT_SCOPE_MAPPINGS: &[(&str, &[&str])] = &[
"read.importer",
"read.metadata",
"read.sbom",
"read.trustAnchor",
"read.weakness",
],
),
Expand All @@ -36,6 +46,7 @@ pub const DEFAULT_SCOPE_MAPPINGS: &[(&str, &[&str])] = &[
"update.importer",
"update.metadata",
"update.sbom",
"update.trustAnchor",
"update.weakness",
],
),
Expand All @@ -46,16 +57,9 @@ pub const DEFAULT_SCOPE_MAPPINGS: &[(&str, &[&str])] = &[
"delete.importer",
"delete.metadata",
"delete.sbom",
"delete.trustAnchor",
"delete.vulnerability",
"delete.weakness",
],
),
];

/// A convenience function to get the default scopes in an allocated form.
pub fn default_scope_mappings() -> HashMap<String, Vec<String>> {
DEFAULT_SCOPE_MAPPINGS
.iter()
.map(|(k, v)| (k.to_string(), v.iter().map(ToString::to_string).collect()))
.collect()
}
9 changes: 9 additions & 0 deletions common/auth/src/permission.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@

#[strum(serialize = "delete.vulnerability")]
DeleteVulnerability,

#[strum(serialize = "create.trustAnchor")]

Check warning on line 112 in common/auth/src/permission.rs

View check run for this annotation

Codecov / codecov/patch

common/auth/src/permission.rs#L112

Added line #L112 was not covered by tests
CreateTrustAnchor,
#[strum(serialize = "read.trustAnchor")]

Check warning on line 114 in common/auth/src/permission.rs

View check run for this annotation

Codecov / codecov/patch

common/auth/src/permission.rs#L114

Added line #L114 was not covered by tests
ReadTrustAnchor,
#[strum(serialize = "update.trustAnchor")]

Check warning on line 116 in common/auth/src/permission.rs

View check run for this annotation

Codecov / codecov/patch

common/auth/src/permission.rs#L116

Added line #L116 was not covered by tests
UpdateTrustAnchor,
#[strum(serialize = "delete.trustAnchor")]

Check warning on line 118 in common/auth/src/permission.rs

View check run for this annotation

Codecov / codecov/patch

common/auth/src/permission.rs#L118

Added line #L118 was not covered by tests
DeleteTrustAnchor,
}
}

Expand Down
9 changes: 9 additions & 0 deletions common/src/endpoints.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
pub mod guards {
use actix_web::guard::{self, Guard, GuardContext};

pub const JSON_MERGE_CONTENT_TYPE: &str = "application/merge-patch+json";

pub fn json_merge(ctx: &GuardContext) -> bool {
guard::Header("content-type", JSON_MERGE_CONTENT_TYPE).check(ctx)
}
}
1 change: 1 addition & 0 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub mod config;
pub mod cpe;
pub mod db;
pub mod decompress;
pub mod endpoints;
pub mod error;
pub mod hashing;
pub mod id;
Expand Down
15 changes: 14 additions & 1 deletion common/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,27 @@
}
}

// NOTE: This struct must be aligned with the struct in the [`paginated`] macro below.
/// Paginated results
///
/// This carries the requested page, plus the total number of items matching the request.
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct PaginatedResults<R> {
/// The page of items
pub items: Vec<R>,
/// The total number of items
pub total: u64,
}

impl<R> Default for PaginatedResults<R> {
fn default() -> Self {

Check warning on line 87 in common/src/model.rs

View check run for this annotation

Codecov / codecov/patch

common/src/model.rs#L87

Added line #L87 was not covered by tests
Self {
items: vec![],

Check warning on line 89 in common/src/model.rs

View check run for this annotation

Codecov / codecov/patch

common/src/model.rs#L89

Added line #L89 was not covered by tests
total: 0,
}
}
}

impl<R> PaginatedResults<R> {
/// Create a new paginated result
pub async fn new<C, S1, S2>(
Expand Down
2 changes: 1 addition & 1 deletion entity/src/advisory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub struct Model {
pub withdrawn: Option<OffsetDateTime>,
pub title: Option<String>,
pub labels: Labels,
pub source_document_id: Option<Uuid>,
pub source_document_id: Uuid,
}

#[cfg(feature = "async-graphql")]
Expand Down
3 changes: 3 additions & 0 deletions entity/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ pub mod sbom_package;
pub mod sbom_package_cpe_ref;
pub mod sbom_package_license;
pub mod sbom_package_purl_ref;
pub mod signature_type;
pub mod source_document;
pub mod source_document_signature;
pub mod status;
pub mod trust_anchor;
pub mod user_preferences;
pub mod version_range;
pub mod version_scheme;
Expand Down
2 changes: 1 addition & 1 deletion entity/src/sbom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub struct Model {
pub suppliers: Vec<String>,
pub data_licenses: Vec<String>,

pub source_document_id: Option<Uuid>,
pub source_document_id: Uuid,

#[cfg_attr(
feature = "async-graphql",
Expand Down
36 changes: 36 additions & 0 deletions entity/src/signature_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use sea_orm::{DeriveActiveEnum, EnumIter};

#[derive(
Debug,
Copy,
Clone,
Hash,
PartialEq,
Eq,
EnumIter,
DeriveActiveEnum,
strum::Display,
strum::EnumString,
strum::VariantArray,
serde::Serialize,
serde::Deserialize,
utoipa::ToSchema,
)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "signature_type")]
#[serde(rename_all = "lowercase")]
#[strum(serialize_all = "lowercase")]
// When adding a new variant, also add this to the "signature_type" enum.
pub enum SignatureType {
#[sea_orm(string_value = "pgp")]
Pgp,
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn names() {
assert_eq!(SignatureType::Pgp.to_string(), "pgp");
}
}
5 changes: 4 additions & 1 deletion entity/src/source_document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ pub struct Model {
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
pub enum Relation {
#[sea_orm(has_many = "super::source_document_signature::Entity")]
Signature,
}

impl ActiveModelBehavior for ActiveModel {}
30 changes: 30 additions & 0 deletions entity/src/source_document_signature.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use crate::signature_type::SignatureType;
use sea_orm::entity::prelude::*;

#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "source_document_signature")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: Uuid,
pub document_id: Uuid,
pub r#type: SignatureType,
pub payload: Vec<u8>,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::source_document::Entity",
from = "Column::DocumentId",
to = "super::source_document::Column::Id"
)]
SourceDocument,
}

impl ActiveModelBehavior for ActiveModel {}

impl Related<super::source_document::Entity> for Entity {
fn to() -> RelationDef {
Relation::SourceDocument.def()

Check warning on line 28 in entity/src/source_document_signature.rs

View check run for this annotation

Codecov / codecov/patch

entity/src/source_document_signature.rs#L27-L28

Added lines #L27 - L28 were not covered by tests
}
}
21 changes: 21 additions & 0 deletions entity/src/trust_anchor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use crate::signature_type::SignatureType;
use sea_orm::entity::prelude::*;

#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "trust_anchor")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: String,
pub revision: Uuid,

pub disabled: bool,
pub description: String,

pub r#type: SignatureType,
pub payload: Vec<u8>,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}

impl ActiveModelBehavior for ActiveModel {}
5 changes: 5 additions & 0 deletions etc/datasets/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@ ds3.zip:
ds3-sboms.zip:
-rm ds3-sbom.zip
cd ds3 && zip -r ../ds3-sboms.zip ./spdx

.PHONY: ds6.zip
ds6.zip:
-rm ds6.zip
cd ds6 && zip -r ../ds6.zip .
Loading