use std::collections::BTreeMap;
use std::path::PathBuf;
use crate::input::ChangeSet;
use crate::output::{Finding, Location, Severity};
pub fn parse_bypass_directives(text: &str) -> BTreeMap<String, String> {
let mut directives = BTreeMap::new();
for line in text.lines() {
let trimmed = line.trim();
if !trimmed.starts_with("BYPASS_") {
continue;
}
let Some((raw_name, raw_reason)) = trimmed.split_once('=') else {
continue;
};
let name = normalize_bypass_name(raw_name);
if !is_valid_bypass_name(&name) {
continue;
}
let reason = raw_reason.trim();
if reason.is_empty() {
continue;
}
directives.insert(name, reason.to_owned());
}
directives
}
pub fn parse_bypass_directives_from_descriptions(
commit_description: Option<&str>,
pr_description: Option<&str>,
) -> BTreeMap<String, String> {
let mut directives = BTreeMap::new();
if let Some(commit_description) = commit_description {
directives.extend(parse_bypass_directives(commit_description));
}
if let Some(pr_description) = pr_description {
directives.extend(parse_bypass_directives(pr_description));
}
directives
}
pub fn bypass_name_for_check_id(check_id: &str) -> String {
let mut normalized = String::new();
let mut last_was_underscore = false;
for ch in check_id.chars() {
if ch.is_ascii_alphanumeric() {
normalized.push(ch.to_ascii_uppercase());
last_was_underscore = false;
} else if !last_was_underscore {
normalized.push('_');
last_was_underscore = true;
}
}
while normalized.ends_with('_') {
normalized.pop();
}
while normalized.starts_with('_') {
normalized.remove(0);
}
format!("BYPASS_{normalized}")
}
pub fn bypass_failure_guidance(bypass_name: &str) -> String {
format!(
"Add `{bypass_name}=<specific legitimate reason>` to the PR or commit description only for a real exception. Never use bypasses for convenience."
)
}
pub fn bypass_applied_finding(
bypass_name: &str,
reason: &str,
location: Option<Location>,
) -> Finding {
Finding {
severity: Severity::Warning,
message: format!("check was bypassed via `{bypass_name}`"),
location,
remediation: Some(format!(
"Bypass reason: {reason}. Keep bypasses rare and only for legitimate exceptions."
)),
suggested_fix: None,
}
}
pub fn maybe_bypass_findings(
changeset: &ChangeSet,
allow_bypass: bool,
bypass_name: &str,
trigger_files: &[PathBuf],
) -> Option<Vec<Finding>> {
if !allow_bypass {
return None;
}
let reason = changeset.bypass_reason(bypass_name)?;
let location = trigger_files.first().cloned().map(|path| Location {
path,
line: None,
column: None,
});
Some(vec![bypass_applied_finding(bypass_name, &reason, location)])
}
fn normalize_bypass_name(raw_name: &str) -> String {
raw_name.trim().to_ascii_uppercase()
}
fn is_valid_bypass_name(name: &str) -> bool {
name.starts_with("BYPASS_")
&& name.len() > "BYPASS_".len()
&& name
.chars()
.all(|ch| ch.is_ascii_uppercase() || ch == '_' || ch.is_ascii_digit())
}
#[cfg(test)]
mod tests {
use super::{
bypass_applied_finding, bypass_failure_guidance, bypass_name_for_check_id,
maybe_bypass_findings, parse_bypass_directives, parse_bypass_directives_from_descriptions,
};
use crate::input::{ChangeKind, ChangeSet, ChangedFile};
use crate::output::{Location, Severity};
use std::path::PathBuf;
#[test]
fn parses_bypass_directives_from_freeform_text() {
let parsed = parse_bypass_directives(
r#"
some markdown text
BYPASS_API_BREAKING_SURFACE=This does not change public API behavior.
BYPASS_FRONTEND_NO_LEGACY_API = Legacy import remains in test fixture only.
"#,
);
assert_eq!(
parsed.get("BYPASS_API_BREAKING_SURFACE"),
Some(&"This does not change public API behavior.".to_owned())
);
assert_eq!(
parsed.get("BYPASS_FRONTEND_NO_LEGACY_API"),
Some(&"Legacy import remains in test fixture only.".to_owned())
);
}
#[test]
fn ignores_invalid_or_empty_bypass_directives() {
let parsed = parse_bypass_directives(
r#"
BYPASS_API_BREAKING_SURFACE=
BYPASS API_BREAKING_SURFACE=Bad name
BYPASS_MISSING_EQUALS
"#,
);
assert!(parsed.is_empty());
}
#[test]
fn maps_check_id_to_expected_bypass_name() {
assert_eq!(
bypass_name_for_check_id("api-breaking-surface"),
"BYPASS_API_BREAKING_SURFACE"
);
assert_eq!(
bypass_name_for_check_id("frontend-no-legacy-api"),
"BYPASS_FRONTEND_NO_LEGACY_API"
);
}
#[test]
fn pr_description_overrides_commit_description() {
let parsed = parse_bypass_directives_from_descriptions(
Some("BYPASS_API_BREAKING_SURFACE=From commit"),
Some("BYPASS_API_BREAKING_SURFACE=From pr"),
);
assert_eq!(
parsed.get("BYPASS_API_BREAKING_SURFACE"),
Some(&"From pr".to_owned())
);
}
#[test]
fn bypass_failure_guidance_includes_strict_wording() {
let guidance = bypass_failure_guidance("BYPASS_API_BREAKING_SURFACE");
assert!(guidance.contains("BYPASS_API_BREAKING_SURFACE=<specific legitimate reason>"));
assert!(guidance.contains("Never use bypasses for convenience"));
}
#[test]
fn bypass_applied_finding_is_warning_with_reason() {
let finding = bypass_applied_finding(
"BYPASS_API_BREAKING_SURFACE",
"No public API surface changed.",
Some(Location {
path: PathBuf::from("backend/blob/src/v3/auth.rs"),
line: None,
column: None,
}),
);
assert_eq!(finding.severity, Severity::Warning);
assert!(finding.message.contains("BYPASS_API_BREAKING_SURFACE"));
assert!(
finding
.remediation
.as_deref()
.unwrap_or_default()
.contains("No public API surface changed.")
);
}
#[test]
fn maybe_bypass_findings_returns_warning_finding_when_enabled_and_present() {
let changeset = ChangeSet::new(vec![ChangedFile {
path: PathBuf::from("backend/blob/src/v3/auth.rs"),
kind: ChangeKind::Modified,
old_path: None,
}])
.with_commit_description(Some(
"BYPASS_API_BREAKING_SURFACE=No public API surface changed.".to_owned(),
));
let trigger_files = vec![PathBuf::from("backend/blob/src/v3/auth.rs")];
let findings = maybe_bypass_findings(
&changeset,
true,
"BYPASS_API_BREAKING_SURFACE",
&trigger_files,
)
.expect("expected bypass findings");
assert_eq!(findings.len(), 1);
assert_eq!(findings[0].severity, Severity::Warning);
}
#[test]
fn maybe_bypass_findings_is_none_when_disabled() {
let changeset = ChangeSet::new(vec![ChangedFile {
path: PathBuf::from("backend/blob/src/v3/auth.rs"),
kind: ChangeKind::Modified,
old_path: None,
}])
.with_commit_description(Some(
"BYPASS_API_BREAKING_SURFACE=No public API surface changed.".to_owned(),
));
let trigger_files = vec![PathBuf::from("backend/blob/src/v3/auth.rs")];
assert!(
maybe_bypass_findings(
&changeset,
false,
"BYPASS_API_BREAKING_SURFACE",
&trigger_files
)
.is_none()
);
}
}