56482911b8
CI / Check (push) Has been skipped
CI / Detect Changes (push) Successful in 6s
CI / Deploy Agent (push) Successful in 4m8s
CI / Deploy Dashboard (push) Successful in 4m58s
CI / Deploy Docs (push) Has been skipped
CI / Deploy MCP (push) Has been skipped
212 lines
6.0 KiB
Rust
212 lines
6.0 KiB
Rust
use dioxus::prelude::*;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
// ── Local types (no bson dependency, WASM-safe) ──
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
|
pub struct VulnRefData {
|
|
pub id: String,
|
|
pub source: String,
|
|
pub severity: Option<String>,
|
|
pub url: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
|
pub struct SbomEntryData {
|
|
#[serde(rename = "_id", default)]
|
|
pub id: Option<serde_json::Value>,
|
|
pub repo_id: String,
|
|
pub name: String,
|
|
pub version: String,
|
|
pub package_manager: String,
|
|
pub license: Option<String>,
|
|
pub purl: Option<String>,
|
|
#[serde(default)]
|
|
pub known_vulnerabilities: Vec<VulnRefData>,
|
|
#[serde(default)]
|
|
pub created_at: Option<serde_json::Value>,
|
|
#[serde(default)]
|
|
pub updated_at: Option<serde_json::Value>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
|
pub struct SbomListResponse {
|
|
pub data: Vec<SbomEntryData>,
|
|
pub total: Option<u64>,
|
|
pub page: Option<u64>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
|
pub struct LicenseSummaryData {
|
|
pub license: String,
|
|
pub count: u64,
|
|
pub is_copyleft: bool,
|
|
pub packages: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
|
pub struct LicenseSummaryResponse {
|
|
pub data: Vec<LicenseSummaryData>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
|
pub struct SbomDiffEntryData {
|
|
pub name: String,
|
|
pub version: String,
|
|
pub package_manager: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
|
pub struct SbomVersionDiffData {
|
|
pub name: String,
|
|
pub package_manager: String,
|
|
pub version_a: String,
|
|
pub version_b: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
|
pub struct SbomDiffResultData {
|
|
pub only_in_a: Vec<SbomDiffEntryData>,
|
|
pub only_in_b: Vec<SbomDiffEntryData>,
|
|
pub version_changed: Vec<SbomVersionDiffData>,
|
|
pub common_count: u64,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
|
pub struct SbomDiffResponse {
|
|
pub data: SbomDiffResultData,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
|
pub struct SbomFiltersResponse {
|
|
pub package_managers: Vec<String>,
|
|
pub licenses: Vec<String>,
|
|
}
|
|
|
|
// ── Server functions ──
|
|
|
|
#[server]
|
|
pub async fn fetch_sbom_filters() -> Result<SbomFiltersResponse, ServerFnError> {
|
|
let resp = super::agent_client::agent_get("/api/v1/sbom/filters")
|
|
.await?
|
|
.send()
|
|
.await
|
|
.map_err(|e| ServerFnError::new(e.to_string()))?;
|
|
let text = resp
|
|
.text()
|
|
.await
|
|
.map_err(|e| ServerFnError::new(e.to_string()))?;
|
|
let body: SbomFiltersResponse = serde_json::from_str(&text)
|
|
.map_err(|e| ServerFnError::new(format!("Parse error: {e} — body: {text}")))?;
|
|
Ok(body)
|
|
}
|
|
|
|
#[server]
|
|
pub async fn fetch_sbom_filtered(
|
|
repo_id: Option<String>,
|
|
package_manager: Option<String>,
|
|
q: Option<String>,
|
|
has_vulns: Option<bool>,
|
|
license: Option<String>,
|
|
page: u64,
|
|
) -> Result<SbomListResponse, ServerFnError> {
|
|
let mut params = vec![format!("page={page}"), "limit=50".to_string()];
|
|
if let Some(r) = &repo_id {
|
|
if !r.is_empty() {
|
|
params.push(format!("repo_id={r}"));
|
|
}
|
|
}
|
|
if let Some(pm) = &package_manager {
|
|
if !pm.is_empty() {
|
|
params.push(format!("package_manager={pm}"));
|
|
}
|
|
}
|
|
if let Some(q) = &q {
|
|
if !q.is_empty() {
|
|
params.push(format!("q={}", q.replace(' ', "%20")));
|
|
}
|
|
}
|
|
if let Some(hv) = has_vulns {
|
|
params.push(format!("has_vulns={hv}"));
|
|
}
|
|
if let Some(l) = &license {
|
|
if !l.is_empty() {
|
|
params.push(format!("license={}", l.replace(' ', "%20")));
|
|
}
|
|
}
|
|
|
|
let path = format!("/api/v1/sbom?{}", params.join("&"));
|
|
let resp = super::agent_client::agent_get(&path)
|
|
.await?
|
|
.send()
|
|
.await
|
|
.map_err(|e| ServerFnError::new(e.to_string()))?;
|
|
let text = resp
|
|
.text()
|
|
.await
|
|
.map_err(|e| ServerFnError::new(e.to_string()))?;
|
|
let body: SbomListResponse = serde_json::from_str(&text)
|
|
.map_err(|e| ServerFnError::new(format!("Parse error: {e} — body: {text}")))?;
|
|
Ok(body)
|
|
}
|
|
|
|
#[server]
|
|
pub async fn fetch_sbom_export(repo_id: String, format: String) -> Result<String, ServerFnError> {
|
|
let path = format!("/api/v1/sbom/export?repo_id={repo_id}&format={format}");
|
|
let resp = super::agent_client::agent_get(&path)
|
|
.await?
|
|
.send()
|
|
.await
|
|
.map_err(|e| ServerFnError::new(e.to_string()))?;
|
|
let text = resp
|
|
.text()
|
|
.await
|
|
.map_err(|e| ServerFnError::new(e.to_string()))?;
|
|
Ok(text)
|
|
}
|
|
|
|
#[server]
|
|
pub async fn fetch_license_summary(
|
|
repo_id: Option<String>,
|
|
) -> Result<LicenseSummaryResponse, ServerFnError> {
|
|
let mut path = "/api/v1/sbom/licenses".to_string();
|
|
if let Some(r) = &repo_id {
|
|
if !r.is_empty() {
|
|
path = format!("{path}?repo_id={r}");
|
|
}
|
|
}
|
|
|
|
let resp = super::agent_client::agent_get(&path)
|
|
.await?
|
|
.send()
|
|
.await
|
|
.map_err(|e| ServerFnError::new(e.to_string()))?;
|
|
let text = resp
|
|
.text()
|
|
.await
|
|
.map_err(|e| ServerFnError::new(e.to_string()))?;
|
|
let body: LicenseSummaryResponse = serde_json::from_str(&text)
|
|
.map_err(|e| ServerFnError::new(format!("Parse error: {e} — body: {text}")))?;
|
|
Ok(body)
|
|
}
|
|
|
|
#[server]
|
|
pub async fn fetch_sbom_diff(
|
|
repo_a: String,
|
|
repo_b: String,
|
|
) -> Result<SbomDiffResponse, ServerFnError> {
|
|
let path = format!("/api/v1/sbom/diff?repo_a={repo_a}&repo_b={repo_b}");
|
|
let resp = super::agent_client::agent_get(&path)
|
|
.await?
|
|
.send()
|
|
.await
|
|
.map_err(|e| ServerFnError::new(e.to_string()))?;
|
|
let text = resp
|
|
.text()
|
|
.await
|
|
.map_err(|e| ServerFnError::new(e.to_string()))?;
|
|
let body: SbomDiffResponse = serde_json::from_str(&text)
|
|
.map_err(|e| ServerFnError::new(format!("Parse error: {e} — body: {text}")))?;
|
|
Ok(body)
|
|
}
|