From 2d9ca9d4f9f084a2d4b4f40dd7bee426c88e54bf Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Tue, 26 Mar 2024 11:41:46 -0400 Subject: [PATCH] Add three columns to advisory: * published * modified * withdrawn Ingest those from OSV where appropriate. --- Cargo.lock | 1 + entity/Cargo.toml | 1 + entity/src/advisory.rs | 3 ++ migration/src/m0000060_create_advisory.rs | 6 +++ modules/graph/src/graph/advisory/mod.rs | 48 ++++++++++++++++++- .../src/service/advisory/osv/loader.rs | 6 +++ 6 files changed, 64 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index e3e560ca0..bf20be299 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5511,6 +5511,7 @@ name = "trustify-entity" version = "0.1.0" dependencies = [ "anyhow", + "chrono", "sea-orm", "serde_json", "time", diff --git a/entity/Cargo.toml b/entity/Cargo.toml index e4909a04e..5a5c3e66f 100644 --- a/entity/Cargo.toml +++ b/entity/Cargo.toml @@ -10,6 +10,7 @@ time = { workspace = true } tokio = { workspace = true, features = ["full"] } trustify-common = { path = "../common" } trustify-cvss = { path = "../cvss" } +chrono = { workspace = true } [dev-dependencies] anyhow = { workspace = true } diff --git a/entity/src/advisory.rs b/entity/src/advisory.rs index 4c0eeffea..6fef4849f 100644 --- a/entity/src/advisory.rs +++ b/entity/src/advisory.rs @@ -8,6 +8,9 @@ pub struct Model { pub identifier: String, pub location: String, pub sha256: String, + pub published: Option, + pub modified: Option, + pub withdrawn: Option, pub title: Option, } diff --git a/migration/src/m0000060_create_advisory.rs b/migration/src/m0000060_create_advisory.rs index eaf195ac4..fd9566112 100644 --- a/migration/src/m0000060_create_advisory.rs +++ b/migration/src/m0000060_create_advisory.rs @@ -19,6 +19,9 @@ impl MigrationTrait for Migration { .auto_increment() .primary_key(), ) + .col(ColumnDef::new(Advisory::Published).timestamp_with_time_zone()) + .col(ColumnDef::new(Advisory::Modified).timestamp_with_time_zone()) + .col(ColumnDef::new(Advisory::Withdrawn).timestamp_with_time_zone()) .col(ColumnDef::new(Advisory::Identifier).string().not_null()) .col(ColumnDef::new(Advisory::Location).string().not_null()) .col(ColumnDef::new(Advisory::Sha256).string().not_null()) @@ -39,6 +42,9 @@ impl MigrationTrait for Migration { pub enum Advisory { Table, Id, + Published, + Modified, + Withdrawn, Identifier, Location, Sha256, diff --git a/modules/graph/src/graph/advisory/mod.rs b/modules/graph/src/graph/advisory/mod.rs index 70ba541f2..1a173dac0 100644 --- a/modules/graph/src/graph/advisory/mod.rs +++ b/modules/graph/src/graph/advisory/mod.rs @@ -3,8 +3,9 @@ use crate::graph::advisory::advisory_vulnerability::AdvisoryVulnerabilityContext; use crate::graph::error::Error; use crate::graph::Graph; +use sea_orm::prelude::DateTimeUtc; use sea_orm::ActiveValue::Set; -use sea_orm::{ActiveModelTrait, EntityTrait, FromQueryResult, QueryFilter}; +use sea_orm::{ActiveModelTrait, EntityTrait, FromQueryResult, IntoActiveModel, QueryFilter}; use sea_orm::{ColumnTrait, QuerySelect, RelationTrait}; use sea_query::{Condition, JoinType}; use std::cmp::min; @@ -102,6 +103,51 @@ impl<'g> From<(&'g Graph, entity::advisory::Model)> for AdvisoryContext<'g> { } impl<'g> AdvisoryContext<'g> { + pub async fn set_published_at>( + &self, + published_at: DateTimeUtc, + tx: TX, + ) -> Result<(), Error> { + let mut entity = self.advisory.clone().into_active_model(); + entity.published = Set(Some(published_at)); + entity.save(&self.graph.connection(&tx)).await?; + Ok(()) + } + + pub fn published_at(&self) -> Option { + self.advisory.published + } + + pub async fn set_modified_at>( + &self, + modified_at: DateTimeUtc, + tx: TX, + ) -> Result<(), Error> { + let mut entity = self.advisory.clone().into_active_model(); + entity.modified = Set(Some(modified_at)); + entity.save(&self.graph.connection(&tx)).await?; + Ok(()) + } + + pub fn modified_at(&self) -> Option { + self.advisory.modified + } + + pub async fn set_withdrawn_at>( + &self, + withdrawn_at: DateTimeUtc, + tx: TX, + ) -> Result<(), Error> { + let mut entity = self.advisory.clone().into_active_model(); + entity.withdrawn = Set(Some(withdrawn_at)); + entity.save(&self.graph.connection(&tx)).await?; + Ok(()) + } + + pub fn withdrawn_at(&self) -> Option { + self.advisory.withdrawn + } + pub async fn get_vulnerability>( &self, identifier: &str, diff --git a/modules/ingestor/src/service/advisory/osv/loader.rs b/modules/ingestor/src/service/advisory/osv/loader.rs index bf66d6bc0..297702854 100644 --- a/modules/ingestor/src/service/advisory/osv/loader.rs +++ b/modules/ingestor/src/service/advisory/osv/loader.rs @@ -43,6 +43,12 @@ impl<'g> OsvLoader<'g> { .ingest_advisory(osv.id, location, sha256, &tx) .await?; + advisory.set_published_at(osv.published, &tx).await?; + advisory.set_modified_at(osv.modified, &tx).await?; + if let Some(withdrawn) = osv.withdrawn { + advisory.set_withdrawn_at(withdrawn, &tx).await?; + } + for cve_id in cve_ids { let advisory_vuln = advisory.link_to_vulnerability(cve_id, &tx).await?;