use crate::contracts::PROPOSE_ARTIFACT;
use crate::json::{bool_json, option_json, push_json_fixed_artifact_preamble};
use crate::{CLAIM_BOUNDARY_TEXT, ProposeReport};
use allow_core::json_escape;
pub fn render_propose_human(report: ProposeReport<'_>) -> String {
let mut out = String::new();
out.push_str("cargo-allow propose summary\n");
out.push_str(&format!(
"inventory: {}/{} via {}{}\n",
report.inventory.scope,
report.inventory.scanner,
report.inventory.source,
propose_inventory_files_suffix(report.inventory)
));
if let Some(root) = report.inventory.root {
out.push_str(&format!("source_tree_root: {root}\n"));
}
if let Some(kind) = report.kind {
out.push_str(&format!("kind filter: {kind}\n"));
}
out.push_str(&format!("findings scanned: {}\n", report.findings_scanned));
out.push_str(&format!(
"baseline_debt entries proposed: {}\n",
report.baseline_debt_entries_proposed
));
out.push_str(&format!(
"unsafe baseline_debt entries proposed: {}\n",
report.unsafe_baseline_debt_entries_proposed
));
out.push_str("owner: unowned\n");
out.push_str("classification: baseline_debt\n");
out.push_str("reason: Generated by cargo-allow propose; requires human review.\n");
out.push_str(&format!("expires: {}\n", report.expires));
if let Some(output) = report.policy_output {
out.push_str(&format!("output: {output}\n"));
} else {
out.push_str("output: stdout\n");
}
out.push_str(
"claim boundary: proposal only; generated debt still requires human review and evidence.\n",
);
out.push_str(CLAIM_BOUNDARY_TEXT);
out.push('\n');
out
}
fn propose_inventory_files_suffix(inventory: crate::InventoryContext<'_>) -> String {
inventory
.files_scanned
.map(|files| format!("; files scanned: {files}"))
.unwrap_or_default()
}
pub fn render_propose_json(report: ProposeReport<'_>) -> String {
let mut out = String::new();
out.push_str("{\n");
push_json_fixed_artifact_preamble(&mut out, PROPOSE_ARTIFACT, report.inventory);
out.push_str(" \"options\": {\n");
out.push_str(&format!(" \"kind\": {},\n", option_json(report.kind)));
out.push_str(&format!(
" \"expires\": \"{}\",\n",
json_escape(report.expires)
));
out.push_str(&format!(
" \"policy_output\": {},\n",
option_json(report.policy_output)
));
out.push_str(&format!(" \"force\": {}\n", bool_json(report.force)));
out.push_str(" },\n");
out.push_str(" \"summary\": {\n");
out.push_str(&format!(
" \"findings_scanned\": {},\n",
report.findings_scanned
));
out.push_str(&format!(
" \"baseline_debt_entries_proposed\": {},\n",
report.baseline_debt_entries_proposed
));
out.push_str(&format!(
" \"unsafe_baseline_debt_entries_proposed\": {}\n",
report.unsafe_baseline_debt_entries_proposed
));
out.push_str(" },\n");
out.push_str(" \"generated_entry_defaults\": {\n");
out.push_str(" \"owner\": \"unowned\",\n");
out.push_str(" \"classification\": \"baseline_debt\",\n");
out.push_str(" \"reason\": \"Generated by cargo-allow propose; requires human review.\",\n");
out.push_str(&format!(
" \"expires\": \"{}\"\n",
json_escape(report.expires)
));
out.push_str(" }\n");
out.push_str("}\n");
out
}