//! 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, ) -> Response { let db = match tenant_db(&agent, &tenant).await { Ok(db) => db, Err(code) => return code.into_response(), }; let findings: Vec = 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() }