allow-policy-legacy 0.1.9

Legacy policy adapters for cargo-allow migrations.
Documentation
use allow_core::Lifecycle;

use crate::converter_lifecycle_support::lifecycle_from_legacy_fields;
use crate::types::LegacyWorkflowRule;

pub(crate) fn lifecycle_from_workflow_rule(rule: &LegacyWorkflowRule) -> Lifecycle {
    lifecycle_from_legacy_fields(
        rule.created.clone(),
        rule.review_after.clone(),
        rule.expires.clone(),
    )
}

pub(crate) fn slug_id(input: &str) -> String {
    let mut out = String::new();
    for ch in input.chars() {
        if ch.is_ascii_alphanumeric() {
            out.push(ch.to_ascii_lowercase());
        } else if !out.ends_with('-') {
            out.push('-');
        }
    }
    out.trim_matches('-').to_string()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn lifecycle_from_workflow_rule_preserves_explicit_lifecycle_fields() {
        let rule = workflow_rule(Some("2026-01-02"), Some("2026-07-02"), Some("2027-01-02"));

        let lifecycle = lifecycle_from_workflow_rule(&rule);

        assert_eq!(lifecycle.created.as_deref(), Some("2026-01-02"));
        assert_eq!(lifecycle.review_after.as_deref(), Some("2026-07-02"));
        assert_eq!(lifecycle.expires.as_deref(), Some("2027-01-02"));
    }

    #[test]
    fn lifecycle_from_workflow_rule_uses_created_as_review_when_expiry_is_never() {
        let rule = workflow_rule(Some("2026-03-04"), None, Some("never"));

        let lifecycle = lifecycle_from_workflow_rule(&rule);

        assert_eq!(lifecycle.created.as_deref(), Some("2026-03-04"));
        assert_eq!(lifecycle.review_after.as_deref(), Some("2026-03-04"));
        assert_eq!(lifecycle.expires.as_deref(), Some("never"));
    }

    #[test]
    fn slug_id_lowercases_ascii_and_collapses_separator_runs() {
        assert_eq!(
            slug_id(".github/workflows/CI.yml::actions/Checkout@v4"),
            "github-workflows-ci-yml-actions-checkout-v4"
        );
    }

    #[test]
    fn slug_id_trims_edges_and_drops_inputs_without_ascii_alphanumerics() {
        assert_eq!(slug_id("---Release Lane---"), "release-lane");
        assert_eq!(slug_id("///"), "");
    }

    fn workflow_rule(
        created: Option<&str>,
        review_after: Option<&str>,
        expires: Option<&str>,
    ) -> LegacyWorkflowRule {
        LegacyWorkflowRule {
            path: ".github\\workflows\\ci.yml".to_string(),
            owner: "platform".to_string(),
            reason: "required CI lane".to_string(),
            permissions: Vec::new(),
            secrets_used: Vec::new(),
            external_actions: Vec::new(),
            duplicate_of_lane: None,
            evidence: Vec::new(),
            created: created.map(str::to_string),
            review_after: review_after.map(str::to_string),
            expires: expires.map(str::to_string),
        }
    }
}