feat: add new scanners, enhanced triage, findings refinement, and deployment tooling
Some checks failed
CI / Deploy Agent (push) Has been skipped
CI / Deploy Dashboard (push) Has been skipped
CI / Deploy Docs (push) Has been skipped
CI / Deploy MCP (push) Has been skipped
CI / Deploy Agent (pull_request) Has been skipped
CI / Deploy Dashboard (pull_request) Has been skipped
CI / Deploy Docs (pull_request) Has been skipped
CI / Format (push) Failing after 3s
CI / Clippy (push) Failing after 2m44s
CI / Security Audit (push) Has been skipped
CI / Tests (push) Has been skipped
CI / Format (pull_request) Failing after 3s
CI / Clippy (pull_request) Failing after 2m51s
CI / Security Audit (pull_request) Has been skipped
CI / Tests (pull_request) Has been skipped
CI / Detect Changes (push) Has been skipped
CI / Detect Changes (pull_request) Has been skipped
CI / Deploy MCP (pull_request) Has been skipped
Some checks failed
CI / Deploy Agent (push) Has been skipped
CI / Deploy Dashboard (push) Has been skipped
CI / Deploy Docs (push) Has been skipped
CI / Deploy MCP (push) Has been skipped
CI / Deploy Agent (pull_request) Has been skipped
CI / Deploy Dashboard (pull_request) Has been skipped
CI / Deploy Docs (pull_request) Has been skipped
CI / Format (push) Failing after 3s
CI / Clippy (push) Failing after 2m44s
CI / Security Audit (push) Has been skipped
CI / Tests (push) Has been skipped
CI / Format (pull_request) Failing after 3s
CI / Clippy (pull_request) Failing after 2m51s
CI / Security Audit (pull_request) Has been skipped
CI / Tests (pull_request) Has been skipped
CI / Detect Changes (push) Has been skipped
CI / Detect Changes (pull_request) Has been skipped
CI / Deploy MCP (pull_request) Has been skipped
- Add gitleaks secret detection, lint scanning (clippy/eslint/ruff), and LLM code review scanners - Enhance LLM triage with multi-action support (confirm/downgrade/upgrade/dismiss), surrounding code context, and file-path classification confidence adjustment - Add text search, column sorting, and bulk status update to findings dashboard - Fix finding detail page status refresh and add developer feedback field - Fix BSON DateTime deserialization across all models with shared serde helpers - Add scan progress spinner with polling to repositories page - Batch OSV.dev queries to avoid "Too many queries" errors - Add gitleaks, semgrep, and ruff to Dockerfile.agent for deployment Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -41,6 +41,12 @@ pub struct FindingsFilter {
|
||||
pub scan_type: Option<String>,
|
||||
#[serde(default)]
|
||||
pub status: Option<String>,
|
||||
#[serde(default)]
|
||||
pub q: Option<String>,
|
||||
#[serde(default)]
|
||||
pub sort_by: Option<String>,
|
||||
#[serde(default)]
|
||||
pub sort_order: Option<String>,
|
||||
#[serde(default = "default_page")]
|
||||
pub page: u64,
|
||||
#[serde(default = "default_limit")]
|
||||
@@ -91,6 +97,17 @@ pub struct UpdateStatusRequest {
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct BulkUpdateStatusRequest {
|
||||
pub ids: Vec<String>,
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct UpdateFeedbackRequest {
|
||||
pub feedback: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SbomFilter {
|
||||
#[serde(default)]
|
||||
@@ -367,6 +384,29 @@ pub async fn list_findings(
|
||||
if let Some(status) = &filter.status {
|
||||
query.insert("status", status);
|
||||
}
|
||||
// Text search across title, description, file_path, rule_id
|
||||
if let Some(q) = &filter.q {
|
||||
if !q.is_empty() {
|
||||
let regex = doc! { "$regex": q, "$options": "i" };
|
||||
query.insert(
|
||||
"$or",
|
||||
mongodb::bson::bson!([
|
||||
{ "title": regex.clone() },
|
||||
{ "description": regex.clone() },
|
||||
{ "file_path": regex.clone() },
|
||||
{ "rule_id": regex },
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic sort
|
||||
let sort_field = filter.sort_by.as_deref().unwrap_or("created_at");
|
||||
let sort_dir: i32 = match filter.sort_order.as_deref() {
|
||||
Some("asc") => 1,
|
||||
_ => -1,
|
||||
};
|
||||
let sort_doc = doc! { sort_field: sort_dir };
|
||||
|
||||
let skip = (filter.page.saturating_sub(1)) * filter.limit as u64;
|
||||
let total = db
|
||||
@@ -378,7 +418,7 @@ pub async fn list_findings(
|
||||
let findings = match db
|
||||
.findings()
|
||||
.find(query)
|
||||
.sort(doc! { "created_at": -1 })
|
||||
.sort(sort_doc)
|
||||
.skip(skip)
|
||||
.limit(filter.limit)
|
||||
.await
|
||||
@@ -434,6 +474,55 @@ pub async fn update_finding_status(
|
||||
Ok(Json(serde_json::json!({ "status": "updated" })))
|
||||
}
|
||||
|
||||
pub async fn bulk_update_finding_status(
|
||||
Extension(agent): AgentExt,
|
||||
Json(req): Json<BulkUpdateStatusRequest>,
|
||||
) -> Result<Json<serde_json::Value>, StatusCode> {
|
||||
let oids: Vec<mongodb::bson::oid::ObjectId> = req
|
||||
.ids
|
||||
.iter()
|
||||
.filter_map(|id| mongodb::bson::oid::ObjectId::parse_str(id).ok())
|
||||
.collect();
|
||||
|
||||
if oids.is_empty() {
|
||||
return Err(StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
let result = agent
|
||||
.db
|
||||
.findings()
|
||||
.update_many(
|
||||
doc! { "_id": { "$in": oids } },
|
||||
doc! { "$set": { "status": &req.status, "updated_at": mongodb::bson::DateTime::now() } },
|
||||
)
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
Ok(Json(
|
||||
serde_json::json!({ "status": "updated", "modified_count": result.modified_count }),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn update_finding_feedback(
|
||||
Extension(agent): AgentExt,
|
||||
Path(id): Path<String>,
|
||||
Json(req): Json<UpdateFeedbackRequest>,
|
||||
) -> Result<Json<serde_json::Value>, StatusCode> {
|
||||
let oid = mongodb::bson::oid::ObjectId::parse_str(&id).map_err(|_| StatusCode::BAD_REQUEST)?;
|
||||
|
||||
agent
|
||||
.db
|
||||
.findings()
|
||||
.update_one(
|
||||
doc! { "_id": oid },
|
||||
doc! { "$set": { "developer_feedback": &req.feedback, "updated_at": mongodb::bson::DateTime::now() } },
|
||||
)
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
Ok(Json(serde_json::json!({ "status": "updated" })))
|
||||
}
|
||||
|
||||
pub async fn list_sbom(
|
||||
Extension(agent): AgentExt,
|
||||
Query(filter): Query<SbomFilter>,
|
||||
|
||||
Reference in New Issue
Block a user