49 lines
1.6 KiB
Rust
49 lines
1.6 KiB
Rust
//! OSCAL assessment endpoint.
|
|
//!
|
|
//! Returns a standard OSCAL assessment-results document for a target's findings,
|
|
//! driven by each finding's stamped `control_refs` (from the scan's control-triage
|
|
//! stage): mapped findings target their controls, unmapped findings are reported
|
|
//! as-is. See `compliance_core::models::oscal_assessment`.
|
|
|
|
use axum::extract::Extension;
|
|
use axum::http::StatusCode;
|
|
use axum::response::{IntoResponse, Response};
|
|
use axum::Json;
|
|
use mongodb::bson::doc;
|
|
use serde::Deserialize;
|
|
|
|
use compliance_core::models::oscal_assessment::assess;
|
|
use compliance_core::models::Finding;
|
|
use compliance_core::tenant_ctx::TenantCtx;
|
|
|
|
use super::dto::{collect_cursor_async, tenant_db, AgentExt};
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct AssessRequest {
|
|
/// The target / repo id whose findings are assessed.
|
|
pub target_id: String,
|
|
}
|
|
|
|
/// `POST /api/v1/oscal/assess` — OSCAL assessment-results for a target's findings.
|
|
pub async fn assess_target(
|
|
Extension(agent): AgentExt,
|
|
tenant: TenantCtx,
|
|
Json(req): Json<AssessRequest>,
|
|
) -> Response {
|
|
let db = match tenant_db(&agent, &tenant).await {
|
|
Ok(db) => db,
|
|
Err(code) => return code.into_response(),
|
|
};
|
|
|
|
let findings: Vec<Finding> = match db.findings().find(doc! { "repo_id": &req.target_id }).await
|
|
{
|
|
Ok(cursor) => collect_cursor_async(cursor).await,
|
|
Err(e) => {
|
|
tracing::warn!(error = %e, "failed to load findings for OSCAL assessment");
|
|
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
|
}
|
|
};
|
|
|
|
Json(assess(&findings, chrono::Utc::now())).into_response()
|
|
}
|