Skip to content

Commit

Permalink
Provide a way to get vex statements/generic vulns by purl.
Browse files Browse the repository at this point in the history
  • Loading branch information
Bob McWhirter authored and bobmcwhirter committed Dec 5, 2023
1 parent 3cb0463 commit dce42db
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 2 deletions.
5 changes: 3 additions & 2 deletions lib/src/client/intrinsic/certify_vex_statement/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::client::intrinsic::{
use crate::client::{Error, Id};
use chrono::Utc;
use graphql_client::reqwest::post_graphql;
use serde::{Deserialize, Serialize};

type Time = chrono::DateTime<Utc>;

Expand Down Expand Up @@ -88,7 +89,7 @@ pub struct CertifyVexStatement {
pub collector: String,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub enum VexStatus {
NotAffected,
Affected,
Expand All @@ -97,7 +98,7 @@ pub enum VexStatus {
Other(String),
}

#[derive(Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum VexJustification {
ComponentNotPresent,
VulnerableCodeNotPresent,
Expand Down
80 changes: 80 additions & 0 deletions lib/src/client/semantic/spog/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use chrono::Utc;
use graphql_client::reqwest::post_graphql;
use graphql_client::GraphQLQuery;
use packageurl::PackageUrl;
use serde::{Deserialize, Serialize};
use serde_json::json;

type Time = chrono::DateTime<Utc>;
Expand Down Expand Up @@ -84,6 +85,76 @@ impl SemanticGuacClient {
Ok(res)
}

pub async fn find_vulnerability_statuses(
&self,
purl: &str,
offset: Option<i64>,
limit: Option<i64>,
) -> Result<Vec<VulnerabilityStatus>, Error> {
use self::find_vulnerability::find_vulnerability;

let variables = find_vulnerability::Variables {
purl: purl.to_string(),
offset,
limit,
};
let response_body = post_graphql::<FindVulnerability, _>(
self.intrinsic().client(),
self.intrinsic().url(),
variables,
)
.await?;

if let Some(errors) = response_body.errors {
//TODO fix query not to return error in this case
for error in errors.clone().into_iter() {
if error.message == "failed to locate package based on purl" {
return Ok(Vec::new());
}
}
return Err(Error::GraphQL(errors));
}

let data: <FindVulnerability as GraphQLQuery>::ResponseData =
response_body.data.ok_or(Error::GraphQL(vec![]))?;

let mut result = Vec::new();

for entry in &data.find_vulnerability {
match entry {
find_vulnerability::FindVulnerabilityFindVulnerability::CertifyVEXStatement(
inner,
) => {
let vex: CertifyVexStatement = CertifyVexStatement::from(inner);
match vex.subject {
SubjectPackage(inner) => {
for v in vex.vulnerability.vulnerability_ids {
result.push(VulnerabilityStatus {
id: v.vulnerability_id.clone(),
status: Some(vex.status.clone()),
justification: Some(vex.vex_justification.clone()),
});
}
}
_ => {}
};
}
find_vulnerability::FindVulnerabilityFindVulnerability::CertifyVuln(inner) => {
let cert = CertifyVuln::from(inner);
for v in cert.vulnerability.vulnerability_ids {
result.push(VulnerabilityStatus {
id: v.vulnerability_id.clone(),
status: None,
justification: None,
});
}
}
}
}

Ok(result)
}

pub async fn find_vulnerability(
&self,
purl: &str,
Expand Down Expand Up @@ -264,3 +335,12 @@ pub struct ProductByCve {
pub vex: CertifyVexStatement,
pub path: Vec<Package>,
}

#[derive(Serialize, Deserialize)]
pub struct VulnerabilityStatus {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<VexStatus>,
#[serde(skip_serializing_if = "Option::is_none")]
pub justification: Option<VexJustification>,
}

0 comments on commit dce42db

Please sign in to comment.