ockam_command 0.117.0

End-to-end encryption and mutual authentication for distributed applications.
Documentation
use clap::Args;
use colorful::Colorful;
use miette::IntoDiagnostic;
use std::str::FromStr;

use ockam::Context;
use ockam_abac::{Action, Expr, ResourceName, ResourceType};
use ockam_api::nodes::models::policies::ResourceTypeOrName;
use ockam_api::nodes::{BackgroundNodeClient, Policies};

use super::resource_type_parser;
use crate::node::util::initialize_default_node;
use crate::terminal::color_primary;
use crate::util::async_cmd;
use crate::{fmt_ok, fmt_warn, CommandGlobalOpts};

#[derive(Clone, Debug, Args)]
pub struct CreateCommand {
    #[arg(long, display_order = 900, id = "NODE_NAME")]
    pub at: Option<String>,

    #[arg(
        long,
        conflicts_with = "resource",
        value_parser = resource_type_parser
    )]
    pub resource_type: Option<ResourceType>,

    #[arg(long)]
    pub resource: Option<ResourceName>,

    #[arg(long)]
    pub expression: Expr,
}

impl CreateCommand {
    pub fn run(mut self, opts: CommandGlobalOpts) -> miette::Result<()> {
        async_cmd(&self.name(), opts.clone(), |ctx| async move {
            self.async_run(&ctx, opts).await
        })
    }

    pub fn name(&self) -> String {
        "create policy".into()
    }

    pub async fn async_run(
        &mut self,
        ctx: &Context,
        opts: CommandGlobalOpts,
    ) -> miette::Result<()> {
        initialize_default_node(ctx, &opts).await?;

        // Backwards compatibility
        if let Some(resource) = self.resource.as_ref() {
            if let Ok(resource_type) = ResourceType::from_str(resource.as_str()) {
                let resource_type_str = resource_type.to_string();
                opts.terminal.write_line(fmt_warn!(
                    "{} is deprecated. Please use {} instead",
                    color_primary(format!("--resource {}", resource_type_str)),
                    color_primary(format!("--resource-type {}", resource_type_str))
                ))?;
                self.resource_type = Some(resource_type);
            }
        }

        let resource = ResourceTypeOrName::new(self.resource_type.as_ref(), self.resource.as_ref())
            .into_diagnostic()?;

        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.at).await?;
        node.add_policy(ctx, &resource, &Action::HandleMessage, &self.expression)
            .await?;
        opts.terminal
            .stdout()
            .plain(fmt_ok!(
                "Policy created at node {}",
                color_primary(node.node_name())
            ))
            .write_line()?;
        Ok(())
    }
}