diff --git a/crates/trusted-server-cli/src/commands/audit/generate/analyzer.rs b/crates/trusted-server-cli/src/commands/audit/generate/analyzer.rs index 06d784b7a..619dd9596 100644 --- a/crates/trusted-server-cli/src/commands/audit/generate/analyzer.rs +++ b/crates/trusted-server-cli/src/commands/audit/generate/analyzer.rs @@ -239,8 +239,10 @@ pub(crate) fn detect_integrations_from_inline_script(script: &str) -> Vec<(Strin pub(crate) fn extract_gtm_container_id(artifact: &AuditArtifact) -> Option { for integration in &artifact.detected_integrations { - if integration.id == "google_tag_manager" && GTM_REGEX.is_match(&integration.evidence) { - return Some(integration.evidence.clone()); + if integration.id == "google_tag_manager" + && let Some(matched) = GTM_REGEX.find(&integration.evidence) + { + return Some(matched.as_str().to_string()); } } @@ -551,6 +553,34 @@ mod tests { } } + #[test] + fn extract_gtm_container_id_from_integration_evidence() { + for evidence in [ + "GTM-ABC123", + "https://tags.example.com/gtm.js?id=GTM-ABC123", + "https://tags.example.com/gtm.js?id=GTM-ABC123&l=dataLayer", + ] { + let artifact = AuditArtifact { + audited_url: "https://example.com".to_string(), + page_title: None, + js_asset_count: 0, + third_party_asset_count: 0, + detected_integrations: vec![DetectedIntegration { + id: "google_tag_manager".to_string(), + evidence: evidence.to_string(), + }], + assets: Vec::new(), + warnings: Vec::new(), + }; + + assert_eq!( + extract_gtm_container_id(&artifact).as_deref(), + Some("GTM-ABC123"), + "should extract only the container ID from evidence {evidence}" + ); + } + } + #[test] fn extract_gtm_container_id_reads_query_parameter_urls() { let artifact = AuditArtifact { diff --git a/crates/trusted-server-cli/src/commands/audit/generate/mod.rs b/crates/trusted-server-cli/src/commands/audit/generate/mod.rs index 6532a7117..402421ea0 100644 --- a/crates/trusted-server-cli/src/commands/audit/generate/mod.rs +++ b/crates/trusted-server-cli/src/commands/audit/generate/mod.rs @@ -2698,6 +2698,39 @@ mod tests { toml::from_str::(&draft).expect("draft should parse as TOML"); } + #[test] + fn build_draft_config_extracts_gtm_container_id_from_url_evidence() { + let url = Url::parse("https://example.com").expect("should parse URL"); + let artifact = AuditArtifact { + audited_url: url.to_string(), + page_title: None, + js_asset_count: 0, + third_party_asset_count: 0, + detected_integrations: vec![DetectedIntegration { + id: "google_tag_manager".to_string(), + evidence: "https://tags.example.com/gtm.js?id=GTM-ABC123&l=dataLayer".to_string(), + }], + assets: Vec::new(), + warnings: Vec::new(), + }; + + let draft = build_draft_config(&url, &artifact, &gpt_slots::DiscoveredSlots::default()) + .expect("should build draft config"); + let config = toml::from_str::(&draft).expect("should parse draft config"); + let gtm = &config["integrations"]["google_tag_manager"]; + + assert_eq!( + gtm["enabled"].as_bool(), + Some(true), + "should enable GTM when URL evidence contains a container ID" + ); + assert_eq!( + gtm["container_id"].as_str(), + Some("GTM-ABC123"), + "should write only the container ID rather than the evidence URL" + ); + } + #[test] fn build_draft_config_does_not_enable_gtm_without_container_id() { let url = Url::parse("https://publisher.example/path").expect("should parse URL");