codetether_agent/github_pr/
provenance_block.rs1use crate::provenance::{ExecutionProvenance, sign_provenance};
4
5const SIG_PREVIEW_CHARS: usize = 16;
6
7pub fn provenance_markdown_block(provenance: &ExecutionProvenance) -> String {
9 let signature = sign_provenance(provenance);
10 let sig_label = signature.as_deref().unwrap_or("UNSIGNED");
11 let sig_preview = &sig_label[..sig_label.len().min(SIG_PREVIEW_CHARS)];
12 format!(
13 "### 🔐 Provenance\n\
14 \n\
15 | Field | Value |\n\
16 |-------|-------|\n\
17 | Agent | `{agent}` |\n\
18 | Origin | `{origin}` |\n\
19 | Run ID | `{run}` |\n\
20 | Provenance ID | `{prov}` |\n\
21 | Signature | `{sig}` |\n\
22 \n\
23 > Verify: `codetether verify-pr {prov}`",
24 agent = provenance.identity.agent_name,
25 origin = provenance.identity.origin.as_str(),
26 run = provenance.run_id.as_deref().unwrap_or("N/A"),
27 prov = provenance.provenance_id,
28 sig = sig_preview,
29 )
30}
31
32#[cfg(test)]
33mod tests {
34 use super::provenance_markdown_block;
35 use crate::provenance::{ExecutionOrigin, ExecutionProvenance};
36
37 #[test]
38 fn renders_block_with_required_fields() {
39 unsafe {
40 std::env::remove_var("CODETETHER_SIGNING_SECRET");
41 }
42 let mut provenance = ExecutionProvenance::for_operation("ralph", ExecutionOrigin::Ralph);
43 provenance.set_run_id("run-42");
44 let block = provenance_markdown_block(&provenance);
45 assert!(block.contains("### 🔐 Provenance"));
46 assert!(block.contains("| Agent | `ralph` |"));
47 assert!(block.contains("| Run ID | `run-42` |"));
48 assert!(block.contains(&provenance.provenance_id));
49 assert!(block.contains("`UNSIGNED`"));
50 }
51}