cargo-allow 0.1.8

Source-tree exception ledger and policy scanner for Rust repositories.
use allow_core::{CargoAllowError, CargoAllowResult};
use allow_match::{CheckMode, evaluate};

#[path = "audit_args.rs"]
mod audit_args;
pub(crate) use audit_args::ReportArgs;

use crate::{
    EvidenceReportSummary, EvidenceValidationMode, ProfileArg, ReportRenderArgs,
    evidence_inventory::current_evidence_source_tree_files, load_compat_world,
    load_world_with_evidence_mode, policy_baseline_debt_entries, print_report, report_config,
    spec_system,
};

pub(crate) fn cmd_audit(args: &ReportArgs) -> CargoAllowResult<()> {
    if matches!(args.profile, Some(ProfileArg::SpecSystem)) {
        reject_source_exception_options(args.compat, args.kind.as_deref(), args.include_untracked)?;
        return spec_system::cmd_spec_system(spec_system::SpecSystemCommandArgs {
            command: "audit",
            root: &args.root,
            config: args.config.as_deref(),
            format: args.format,
            output: args.output.as_deref(),
            receipt: None,
        });
    }

    let (root, cfg, findings, inventory_facts) = if args.compat {
        load_compat_world(
            args.root.root.as_deref(),
            args.config.as_deref(),
            args.kind.as_deref(),
            args.include_untracked,
        )?
    } else {
        load_world_with_evidence_mode(
            args.root.root.as_deref(),
            args.config.as_deref(),
            false,
            args.kind.as_deref(),
            args.include_untracked,
            EvidenceValidationMode::ReportOnly,
        )?
    };
    let report_cfg = report_config(&cfg, args.kind.as_deref())?;
    let outcomes = evaluate(&report_cfg, &findings, CheckMode::Audit);
    let evidence_source_tree_files =
        current_evidence_source_tree_files(&root, args.include_untracked);
    let evidence = EvidenceReportSummary::from_policy_with_source_tree_files(
        &root,
        &report_cfg,
        &outcomes,
        evidence_source_tree_files.as_ref(),
    );
    print_report(ReportRenderArgs {
        command: "audit",
        format: args.format,
        baseline_debt_entries: policy_baseline_debt_entries(&report_cfg),
        evidence,
        findings: &findings,
        outcomes: &outcomes,
        failed: false,
        output: args.output.as_deref(),
        root: &root,
        inventory_facts,
    })?;
    Ok(())
}

fn reject_source_exception_options(
    compat: bool,
    kind: Option<&str>,
    include_untracked: bool,
) -> CargoAllowResult<()> {
    if compat {
        return Err(CargoAllowError::new(
            "--compat is not supported with --profile spec-system",
        ));
    }
    if kind.is_some() {
        return Err(CargoAllowError::new(
            "--kind is not supported with --profile spec-system",
        ));
    }
    if include_untracked {
        return Err(CargoAllowError::new(
            "--include-untracked is not supported with --profile spec-system",
        ));
    }
    Ok(())
}

#[cfg(test)]
#[path = "audit_tests.rs"]
mod tests;