osp-cli 1.5.1

CLI and REPL for querying and managing OSP infrastructure data
Documentation
use super::{NativeCommand, NativeCommandContext, NativeCommandOutcome, NativeCommandRegistry};
use crate::config::{ConfigLayer, ConfigResolver, ResolveOptions, ResolvedConfig};
use crate::core::command_policy::CommandPath;
use crate::core::plugin::{
    DescribeCommandAuthV1, DescribeCommandV1, DescribeVisibilityModeV1, PLUGIN_PROTOCOL_V1,
    ResponseMetaV1, ResponseV1,
};
use crate::core::runtime::RuntimeHints;
use clap::Command;
use serde_json::json;

fn resolved_config() -> ResolvedConfig {
    let mut defaults = ConfigLayer::default();
    defaults.set("profile.default", "default");
    let mut resolver = ConfigResolver::default();
    resolver.set_defaults(defaults);
    resolver
        .resolve(ResolveOptions::default())
        .expect("resolved config")
}

fn native_context() -> NativeCommandContext<'static> {
    let config = Box::leak(Box::new(resolved_config()));
    NativeCommandContext {
        config,
        runtime_hints: RuntimeHints::default(),
    }
}

struct TestNativeCommand;

impl NativeCommand for TestNativeCommand {
    fn command(&self) -> Command {
        Command::new("ldap")
            .about("Directory lookups")
            .subcommand(Command::new("user").about("Look up a user"))
    }

    fn auth(&self) -> Option<DescribeCommandAuthV1> {
        Some(DescribeCommandAuthV1 {
            visibility: Some(DescribeVisibilityModeV1::Public),
            required_capabilities: Vec::new(),
            feature_flags: vec!["uio".to_string()],
        })
    }

    fn execute(
        &self,
        args: &[String],
        _context: &NativeCommandContext<'_>,
    ) -> anyhow::Result<NativeCommandOutcome> {
        Ok(NativeCommandOutcome::Response(Box::new(ResponseV1 {
            protocol_version: PLUGIN_PROTOCOL_V1,
            ok: true,
            data: json!([{ "args": args }]),
            error: None,
            messages: Vec::new(),
            meta: ResponseMetaV1::default(),
        })))
    }
}

struct DefaultAuthCommand;

impl NativeCommand for DefaultAuthCommand {
    fn command(&self) -> Command {
        Command::new("version").about("Show version")
    }

    fn execute(
        &self,
        _args: &[String],
        _context: &NativeCommandContext<'_>,
    ) -> anyhow::Result<NativeCommandOutcome> {
        Ok(NativeCommandOutcome::Help("version help".to_string()))
    }
}

#[test]
fn registry_catalog_and_policy_projection_cover_lookup_completion_and_root_auth_unit() {
    let registry = NativeCommandRegistry::new().with_command(TestNativeCommand);

    let catalog = registry.catalog();
    assert_eq!(catalog.len(), 1);
    assert_eq!(catalog[0].name, "ldap");
    assert_eq!(catalog[0].about, "Directory lookups");
    assert_eq!(
        catalog[0]
            .auth
            .as_ref()
            .and_then(|auth| auth.hint())
            .as_deref(),
        Some("feature: uio")
    );
    assert_eq!(catalog[0].subcommands, vec!["user".to_string()]);
    assert!(
        catalog[0]
            .completion
            .subcommands
            .iter()
            .any(|child| child.name == "user")
    );

    assert!(registry.command("LDAP").is_some());
    assert!(registry.command(" ldap ").is_some());

    let policy = registry.command_policy_registry();
    assert!(policy.contains(&CommandPath::new(["ldap"])));
    assert!(!policy.contains(&CommandPath::new(["ldap", "user"])));
}

#[test]
fn empty_registry_and_default_auth_catalog_paths_unit() {
    assert!(NativeCommandRegistry::new().is_empty());
    assert!(NativeCommandRegistry::new().command("missing").is_none());

    let describe = DefaultAuthCommand.describe();
    assert_eq!(describe.name, "version");
    assert!(describe.auth.is_none());
    assert!(describe.subcommands.is_empty());
}

#[test]
fn registered_command_executes_through_registry_unit() {
    let registry = NativeCommandRegistry::new().with_command(TestNativeCommand);
    let context = native_context();
    let outcome = registry
        .command("ldap")
        .expect("registered command")
        .execute(&["user".to_string()], &context)
        .expect("native command should execute");

    let NativeCommandOutcome::Response(response) = outcome else {
        panic!("expected response outcome");
    };
    assert_eq!(response.protocol_version, PLUGIN_PROTOCOL_V1);
    assert_eq!(response.data, json!([{ "args": ["user"] }]));
}

struct TestNativeCommandWithNestedAuth;

impl NativeCommand for TestNativeCommandWithNestedAuth {
    fn command(&self) -> Command {
        Command::new("ldap")
            .about("Directory lookups")
            .subcommand(Command::new("user").about("Look up a user"))
    }

    fn describe(&self) -> DescribeCommandV1 {
        let mut root = DescribeCommandV1::from_clap(
            Command::new("ldap")
                .about("Directory lookups")
                .subcommand(Command::new("user").about("Look up a user")),
        );
        root.auth = Some(DescribeCommandAuthV1 {
            visibility: Some(DescribeVisibilityModeV1::Public),
            required_capabilities: Vec::new(),
            feature_flags: vec!["uio".to_string()],
        });
        root.subcommands[0].auth = Some(DescribeCommandAuthV1 {
            visibility: Some(DescribeVisibilityModeV1::CapabilityGated),
            required_capabilities: vec!["ldap.user.read".to_string()],
            feature_flags: Vec::new(),
        });
        root
    }

    fn execute(
        &self,
        _args: &[String],
        _context: &NativeCommandContext<'_>,
    ) -> anyhow::Result<NativeCommandOutcome> {
        unreachable!("not used in policy test");
    }
}

#[test]
fn registry_collects_nested_auth_policies_when_describe_is_overridden_unit() {
    let default_registry = NativeCommandRegistry::new().with_command(TestNativeCommand);
    assert!(
        default_registry
            .command_policy_registry()
            .resolved_policy(&CommandPath::new(["ldap", "user"]))
            .is_none()
    );

    let overridden_registry =
        NativeCommandRegistry::new().with_command(TestNativeCommandWithNestedAuth);
    let user_policy = overridden_registry
        .command_policy_registry()
        .resolved_policy(&CommandPath::new(["ldap", "user"]))
        .expect("nested native policy should exist");
    assert_eq!(
        user_policy.required_capabilities,
        ["ldap.user.read".to_string()].into_iter().collect()
    );
}