@@ -184,6 +184,35 @@ pub fn validate_front_matter_identity(front_matter: &FrontMatter) -> Result<()>
184184 ) ;
185185 }
186186 }
187+
188+ // Validate trigger.pipeline fields for newlines
189+ if let Some ( trigger_config) = & front_matter. triggers {
190+ if let Some ( pipeline) = & trigger_config. pipeline {
191+ if pipeline. name . contains ( '\n' ) || pipeline. name . contains ( '\r' ) {
192+ anyhow:: bail!(
193+ "Front matter 'triggers.pipeline.name' must be a single line (no newlines). \
194+ Multi-line values could inject YAML structure into the generated pipeline.",
195+ ) ;
196+ }
197+ if let Some ( project) = & pipeline. project {
198+ if project. contains ( '\n' ) || project. contains ( '\r' ) {
199+ anyhow:: bail!(
200+ "Front matter 'triggers.pipeline.project' must be a single line (no newlines). \
201+ Multi-line values could inject YAML structure into the generated pipeline.",
202+ ) ;
203+ }
204+ }
205+ for branch in & pipeline. branches {
206+ if branch. contains ( '\n' ) || branch. contains ( '\r' ) {
207+ anyhow:: bail!(
208+ "Front matter 'triggers.pipeline.branches' entries must be single line (no newlines). \
209+ Multi-line values could inject YAML structure into the generated pipeline.",
210+ ) ;
211+ }
212+ }
213+ }
214+ }
215+
187216 Ok ( ( ) )
188217}
189218
@@ -2325,14 +2354,73 @@ mod tests {
23252354 }
23262355
23272356 #[ test]
2328- fn test_validate_front_matter_identity_allows_valid_values ( ) {
2357+ fn test_validate_front_matter_identity_rejects_newline_in_trigger_pipeline_name ( ) {
2358+ let mut fm = minimal_front_matter ( ) ;
2359+ fm. triggers = Some ( TriggerConfig {
2360+ pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
2361+ name : "Build\n injected: true" . to_string ( ) ,
2362+ project : None ,
2363+ branches : vec ! [ ] ,
2364+ } ) ,
2365+ } ) ;
2366+ let result = validate_front_matter_identity ( & fm) ;
2367+ assert ! ( result. is_err( ) ) ;
2368+ assert ! ( result. unwrap_err( ) . to_string( ) . contains( "triggers.pipeline.name" ) ) ;
2369+ }
2370+
2371+ #[ test]
2372+ fn test_validate_front_matter_identity_rejects_newline_in_trigger_pipeline_project ( ) {
2373+ let mut fm = minimal_front_matter ( ) ;
2374+ fm. triggers = Some ( TriggerConfig {
2375+ pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
2376+ name : "Build Pipeline" . to_string ( ) ,
2377+ project : Some ( "OtherProject\n injected: true" . to_string ( ) ) ,
2378+ branches : vec ! [ ] ,
2379+ } ) ,
2380+ } ) ;
2381+ let result = validate_front_matter_identity ( & fm) ;
2382+ assert ! ( result. is_err( ) ) ;
2383+ assert ! ( result. unwrap_err( ) . to_string( ) . contains( "triggers.pipeline.project" ) ) ;
2384+ }
2385+
2386+ #[ test]
2387+ fn test_validate_front_matter_identity_rejects_newline_in_trigger_pipeline_branch ( ) {
2388+ let mut fm = minimal_front_matter ( ) ;
2389+ fm. triggers = Some ( TriggerConfig {
2390+ pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
2391+ name : "Build Pipeline" . to_string ( ) ,
2392+ project : None ,
2393+ branches : vec ! [ "main\n injected: true" . to_string( ) ] ,
2394+ } ) ,
2395+ } ) ;
2396+ let result = validate_front_matter_identity ( & fm) ;
2397+ assert ! ( result. is_err( ) ) ;
2398+ assert ! ( result. unwrap_err( ) . to_string( ) . contains( "triggers.pipeline.branches" ) ) ;
2399+ }
2400+
2401+ #[ test]
2402+ fn test_validate_front_matter_identity_allows_valid_name_and_description ( ) {
23292403 let mut fm = minimal_front_matter ( ) ;
23302404 fm. name = "Daily Code Review Agent" . to_string ( ) ;
23312405 fm. description = "Reviews code daily for quality issues" . to_string ( ) ;
23322406 let result = validate_front_matter_identity ( & fm) ;
23332407 assert ! ( result. is_ok( ) ) ;
23342408 }
23352409
2410+ #[ test]
2411+ fn test_validate_front_matter_identity_allows_valid_trigger_pipeline_fields ( ) {
2412+ let mut fm = minimal_front_matter ( ) ;
2413+ fm. triggers = Some ( TriggerConfig {
2414+ pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
2415+ name : "Build Pipeline" . to_string ( ) ,
2416+ project : Some ( "OtherProject" . to_string ( ) ) ,
2417+ branches : vec ! [ "main" . to_string( ) , "release/*" . to_string( ) ] ,
2418+ } ) ,
2419+ } ) ;
2420+ let result = validate_front_matter_identity ( & fm) ;
2421+ assert ! ( result. is_ok( ) ) ;
2422+ }
2423+
23362424 #[ test]
23372425 fn test_validate_front_matter_identity_rejects_runtime_expression ( ) {
23382426 let mut fm = minimal_front_matter ( ) ;
0 commit comments