Skip to main content

sparrow/
git_workflow.rs

1use serde::Serialize;
2
3#[derive(Debug, Clone, Serialize)]
4pub struct CommitPlan {
5    pub message: String,
6    pub staged_stat: String,
7    pub secret_findings: Vec<String>,
8}
9
10pub fn build_commit_plan(
11    message: Option<String>,
12    staged_stat: String,
13    staged_diff: &str,
14) -> CommitPlan {
15    let secret_findings = scan_diff_for_secret_patterns(staged_diff);
16    let message = message.unwrap_or_else(|| generated_message(&staged_stat));
17    CommitPlan {
18        message,
19        staged_stat,
20        secret_findings,
21    }
22}
23
24pub fn scan_diff_for_secret_patterns(diff: &str) -> Vec<String> {
25    let mut findings = Vec::new();
26    for (idx, line) in diff.lines().enumerate() {
27        if !line.starts_with('+') || line.starts_with("+++") {
28            continue;
29        }
30        let lower = line.to_ascii_lowercase();
31        let suspicious = lower.contains("api_key")
32            || lower.contains("secret")
33            || lower.contains("token")
34            || line.contains("sk-")
35            || line.contains("ghp_")
36            || line.contains("xoxb-")
37            || line.contains("AKIA");
38        if suspicious {
39            findings.push(format!("line {}: {}", idx + 1, line.trim()));
40        }
41    }
42    findings
43}
44
45fn generated_message(staged_stat: &str) -> String {
46    if staged_stat.contains("docs/") || staged_stat.contains("README") {
47        "docs: update Sparrow release materials".into()
48    } else if staged_stat.contains("Cargo.toml") || staged_stat.contains("Cargo.lock") {
49        "chore: update Sparrow workspace configuration".into()
50    } else if staged_stat.contains("console.html") {
51        "feat: improve Sparrow console experience".into()
52    } else {
53        "chore: update Sparrow".into()
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn commit_plan_detects_secret_like_added_lines() {
63        let plan = build_commit_plan(
64            None,
65            "Cargo.toml | 2 +".into(),
66            "+OPENAI_API_KEY=sk-test\n context\n",
67        );
68        assert_eq!(
69            plan.message,
70            "chore: update Sparrow workspace configuration"
71        );
72        assert_eq!(plan.secret_findings.len(), 1);
73    }
74}