ferrous_forge/cargo_intercept/
mod.rs1pub mod validation;
15pub mod wrapper;
16
17use crate::Result;
18use crate::validation::ViolationType;
19use std::env;
20use std::path::Path;
21
22pub struct CargoInterceptor {
24 enforce_dogfooding: bool,
26 bypass_style: bool,
28 force_bypass: bool,
30}
31
32impl Default for CargoInterceptor {
33 fn default() -> Self {
34 Self::new()
35 }
36}
37
38impl CargoInterceptor {
39 pub fn new() -> Self {
41 let bypass_style = env::var("FERROUS_FORGE_BYPASS")
42 .unwrap_or_default()
43 .eq_ignore_ascii_case("true");
44
45 let force_bypass = env::var("FERROUS_FORGE_FORCE_BYPASS")
46 .unwrap_or_default()
47 .eq_ignore_ascii_case("true");
48
49 Self {
50 enforce_dogfooding: true,
51 bypass_style,
52 force_bypass,
53 }
54 }
55
56 pub fn with_dogfooding(enforce_dogfooding: bool) -> Self {
58 let mut interceptor = Self::new();
59 interceptor.enforce_dogfooding = enforce_dogfooding;
60 interceptor
61 }
62}
63
64pub async fn intercept_publish_command(project_path: &Path) -> Result<()> {
66 let interceptor = CargoInterceptor::new();
67
68 if interceptor.force_bypass {
69 eprintln!(
70 "\n⚠️ FERROUS FORGE FORCE BYPASSED — FERROUS_FORGE_FORCE_BYPASS=true\n\
71 All validation skipped. This should NEVER happen in production.\n"
72 );
73 return Ok(());
74 }
75
76 if interceptor.bypass_style {
77 tracing::warn!(
78 "FERROUS_FORGE_BYPASS enabled — style checks skipped, locked settings still enforced"
79 );
80 }
81
82 tracing::info!("Intercepting cargo publish — running validation");
83
84 validation::pre_publish_validation(project_path).await?;
86 validation::version_consistency_check(project_path)?;
87
88 if interceptor.enforce_dogfooding {
89 validation::enforce_dogfooding(project_path).await?;
90 }
91
92 tracing::info!("Pre-publish validation passed");
93 Ok(())
94}
95
96pub async fn intercept_dev_command(project_path: &Path) -> Result<()> {
100 let interceptor = CargoInterceptor::new();
101
102 if interceptor.force_bypass {
103 eprintln!(
104 "\n⚠️ FERROUS FORGE FORCE BYPASSED — FERROUS_FORGE_FORCE_BYPASS=true\n\
105 All validation skipped. This should NEVER happen in production.\n"
106 );
107 return Ok(());
108 }
109
110 let locked_violations = validation::check_locked_settings(project_path).await?;
112 if !locked_violations.is_empty() {
113 eprintln!("\n❌ FERROUS FORGE — Locked Setting Violations Detected\n");
114 for v in &locked_violations {
115 eprintln!("{}\n", v.message);
116 }
117 return Err(crate::Error::validation(
118 "Locked setting violations must be resolved before building. \
119 See messages above. DO NOT change locked values — escalate to human.",
120 ));
121 }
122
123 if !interceptor.bypass_style {
125 let style_violations = validation::check_style_violations(project_path).await?;
126 if !style_violations.is_empty() {
127 eprintln!(
128 "\n⚠️ Ferrous Forge style warnings ({} violations):",
129 style_violations.len()
130 );
131 for v in style_violations.iter().take(5) {
132 eprintln!(
133 " {:?}: {}:{} — {}",
134 v.violation_type,
135 v.file.display(),
136 v.line,
137 v.message.lines().next().unwrap_or("")
138 );
139 }
140 if style_violations.len() > 5 {
141 eprintln!(
142 " ... and {} more (run 'ferrous-forge validate' \
143 for full list)",
144 style_violations.len() - 5
145 );
146 }
147 eprintln!(" (These will block 'cargo publish'. Fix before publishing.)");
148 eprintln!(
149 " (Set FERROUS_FORGE_BYPASS=true to suppress these warnings.)\n"
150 );
151 }
152 } else {
153 tracing::info!(
154 "FERROUS_FORGE_BYPASS — style warnings suppressed (locked settings still checked)"
155 );
156 }
157
158 Ok(())
159}
160
161pub fn has_locked_violations(violations: &[crate::validation::Violation]) -> bool {
163 violations.iter().any(|v| {
164 matches!(
165 v.violation_type,
166 ViolationType::WrongEdition
167 | ViolationType::OldRustVersion
168 | ViolationType::LockedSetting
169 )
170 })
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 #[test]
178 fn test_cargo_interceptor_creation() {
179 let interceptor = CargoInterceptor::new();
180 assert!(interceptor.enforce_dogfooding);
181 }
182}