feat(core): set_analysis (Suppression/Analyse via PUT /analysis)
CI / test (push) Failing after 5m24s
CI / test (push) Failing after 5m24s
This commit is contained in:
@@ -3,7 +3,11 @@ use reqwest::Client;
|
||||
|
||||
pub use dtrack_config::DtrackConfig;
|
||||
|
||||
/// Read-only Client fuer die Dependency-Track REST-API (v1).
|
||||
/// Client fuer die Dependency-Track REST-API (v1).
|
||||
///
|
||||
/// Ueberwiegend read-only (Projekte, Findings, Metriken, VEX/SBOM ...). Einzige
|
||||
/// Schreib-Operation ist `set_analysis` (Suppression/Analyse setzen) -- diese
|
||||
/// braucht einen API-Key mit dem DT-Recht VULNERABILITY_ANALYSIS.
|
||||
///
|
||||
/// Bewusst duenn: liefert die rohen JSON-Antworten als String zurueck. Das
|
||||
/// Modellieren einzelner DT-Typen (serde-Structs) heben wir uns fuer spaeter
|
||||
@@ -58,6 +62,26 @@ impl DtrackClient {
|
||||
.await
|
||||
.with_context(|| format!("Request an {url} fehlgeschlagen"))?;
|
||||
|
||||
self.handle(path, resp).await
|
||||
}
|
||||
|
||||
/// PUT mit JSON-Body. Einzige Schreib-Operation des Clients.
|
||||
async fn put_json(&self, path: &str, body: serde_json::Value) -> Result<String> {
|
||||
let url = format!("{}{}", self.base_url, path);
|
||||
let resp = self
|
||||
.http
|
||||
.put(&url)
|
||||
.header("X-Api-Key", &self.api_key)
|
||||
.json(&body)
|
||||
.send()
|
||||
.await
|
||||
.with_context(|| format!("Request an {url} fehlgeschlagen"))?;
|
||||
|
||||
self.handle(path, resp).await
|
||||
}
|
||||
|
||||
/// Gemeinsame Status-/Body-Behandlung fuer GET und PUT.
|
||||
async fn handle(&self, path: &str, resp: reqwest::Response) -> Result<String> {
|
||||
let status = resp.status();
|
||||
let body = resp.text().await.unwrap_or_default();
|
||||
if !status.is_success() {
|
||||
@@ -114,6 +138,50 @@ impl DtrackClient {
|
||||
self.get(&format!("/bom/cyclonedx/project/{uuid}?format=json"))
|
||||
.await
|
||||
}
|
||||
|
||||
/// PUT /analysis -- Analyse-/Suppression-Entscheidung fuer ein Finding setzen.
|
||||
///
|
||||
/// Adressiert wird das Finding ueber das Tripel (project, component,
|
||||
/// vulnerability) -- alle drei UUIDs stehen in der `project_findings`-Antwort.
|
||||
/// `suppressed` schaltet die Unterdrueckung an/aus; `state`/`justification`/
|
||||
/// `comment` sind optionale Analyse-Felder (DT-Enums, z.B. state
|
||||
/// `FALSE_POSITIVE`/`NOT_AFFECTED`). Braucht das DT-Recht VULNERABILITY_ANALYSIS.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn set_analysis(
|
||||
&self,
|
||||
project: &str,
|
||||
component: &str,
|
||||
vulnerability: &str,
|
||||
suppressed: Option<bool>,
|
||||
state: Option<&str>,
|
||||
justification: Option<&str>,
|
||||
comment: Option<&str>,
|
||||
) -> Result<String> {
|
||||
let mut body = serde_json::json!({
|
||||
"project": project,
|
||||
"component": component,
|
||||
"vulnerability": vulnerability,
|
||||
});
|
||||
let obj = body
|
||||
.as_object_mut()
|
||||
.expect("json! erzeugt immer ein Objekt");
|
||||
if let Some(s) = suppressed {
|
||||
obj.insert("suppressed".into(), serde_json::Value::Bool(s));
|
||||
}
|
||||
if let Some(s) = state {
|
||||
obj.insert("analysisState".into(), serde_json::Value::String(s.into()));
|
||||
}
|
||||
if let Some(j) = justification {
|
||||
obj.insert(
|
||||
"analysisJustification".into(),
|
||||
serde_json::Value::String(j.into()),
|
||||
);
|
||||
}
|
||||
if let Some(c) = comment {
|
||||
obj.insert("comment".into(), serde_json::Value::String(c.into()));
|
||||
}
|
||||
self.put_json("/analysis", body).await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user