cleanlib-cli 0.1.5

Terminal interface to CleanLibrary — query dependency verdicts and scan package manifests for ALLOW / DENY / WARN signals from the terminal or CI pipelines.
//! `cleanlib logout` (cycle-7 Cli2). Migrates `cmd_logout` and adds
//! keyring-aware removal.

use anyhow::Result;
use cleanlib_client::config;

use crate::auth;

pub fn run(also_keyring: bool) -> Result<()> {
    let path = config::default_path()
        .ok_or_else(|| anyhow::anyhow!("home directory not discoverable"))?;

    // Config-file path — preserved for back-compat. Idempotent if absent.
    if !path.exists() {
        eprintln!("no config file at {}; nothing to remove there", path.display());
    } else {
        let mut cfg = config::load(&path)?;
        if cfg.auth.api_key.is_none() {
            eprintln!("no api key configured in {}; nothing to remove there", path.display());
        } else {
            cfg.auth.api_key = None;
            config::save(&cfg, &path)?;
            eprintln!("api key removed from {}", path.display());
        }
    }

    if also_keyring {
        auth::bearer::delete_from_keyring()?;
        eprintln!("keyring entry removed (service={})", auth::KEYRING_SERVICE);
    }

    // CLEANLIB-156 (Path-2 defense-in-depth): clear the persistent verdict
    // cache on logout so a logged-out session is not served previously-cached
    // verdicts. Idempotent if the cache was never created.
    if let Some(dir) = crate::cache::persistent::default_cache_dir() {
        if dir.exists() {
            let cache = crate::cache::persistent::PersistentCache::open(&dir)?;
            let n = cache.len();
            cache.clear()?;
            eprintln!(
                "verdict cache cleared ({} entr{} removed from {})",
                n,
                if n == 1 { "y" } else { "ies" },
                dir.display()
            );
        }
    }
    Ok(())
}