From d82a1503bd0bad0b8df2470d1f841bba15e672cb Mon Sep 17 00:00:00 2001 From: shaobo-he-aws <130499339+shaobo-he-aws@users.noreply.github.com> Date: Mon, 2 Oct 2023 21:57:03 -0700 Subject: [PATCH] Add a new command to the CLI that creates dummy Cedar project (#330) --- cedar-policy-cli/src/lib.rs | 111 ++++++++++++++++++++++++++++++++++- cedar-policy-cli/src/main.rs | 3 +- 2 files changed, 110 insertions(+), 4 deletions(-) diff --git a/cedar-policy-cli/src/lib.rs b/cedar-policy-cli/src/lib.rs index 804a0bfd6..66c9c30b8 100644 --- a/cedar-policy-cli/src/lib.rs +++ b/cedar-policy-cli/src/lib.rs @@ -22,7 +22,7 @@ mod err; use clap::{Args, Parser, Subcommand, ValueEnum}; -use miette::{miette, NamedSource, Report, Result, WrapErr}; +use miette::{miette, IntoDiagnostic, NamedSource, Report, Result, WrapErr}; use serde::{Deserialize, Serialize}; use std::{ collections::HashMap, @@ -37,8 +37,6 @@ use std::{ use cedar_policy::*; use cedar_policy_formatter::{policies_str_to_pretty, Config}; -use crate::err::IntoDiagnostic; - /// Basic Cedar CLI for evaluating authorization queries #[derive(Parser)] #[command(author, version, about, long_about = None)] // Pull from `Cargo.toml` @@ -98,6 +96,8 @@ pub enum Commands { Link(LinkArgs), /// Format a policy set Format(FormatArgs), + /// Create a Cedar project + New(NewArgs), } #[derive(Args, Debug)] @@ -291,6 +291,13 @@ pub struct FormatArgs { pub indent_width: isize, } +#[derive(Args, Debug)] +pub struct NewArgs { + /// Name of the Cedar project + #[arg(short, long, value_name = "DIR")] + pub name: String, +} + /// Wrapper struct #[derive(Clone, Debug, Deserialize)] #[serde(try_from = "HashMap")] @@ -506,6 +513,104 @@ pub fn format_policies(args: &FormatArgs) -> CedarExitCode { } } +fn generate_schema(path: &Path) -> Result<()> { + std::fs::write( + path, + serde_json::to_string_pretty(&serde_json::json!( + { + "": { + "entityTypes": { + "A": { + "memberOfTypes": [ + "B" + ] + }, + "B": { + "memberOfTypes": [] + }, + "C": { + "memberOfTypes": [] + } + }, + "actions": { + "action": { + "appliesTo": { + "resourceTypes": [ + "C" + ], + "principalTypes": [ + "A", + "B" + ] + } + } + } + } + })) + .into_diagnostic()?, + ) + .into_diagnostic() +} + +fn generate_policy(path: &Path) -> Result<()> { + std::fs::write( + path, + r#"permit ( + principal in A::"a", + action == Action::"action", + resource == C::"c" +) when { true }; +"#, + ) + .into_diagnostic() +} + +fn generate_entities(path: &Path) -> Result<()> { + std::fs::write( + path, + serde_json::to_string_pretty(&serde_json::json!( + [ + { + "uid": { "type": "A", "id": "a"} , + "attrs": {}, + "parents": [{"type": "B", "id": "b"}] + }, + { + "uid": { "type": "B", "id": "b"} , + "attrs": {}, + "parents": [] + }, + { + "uid": { "type": "C", "id": "c"} , + "attrs": {}, + "parents": [] + } + ])) + .into_diagnostic()?, + ) + .into_diagnostic() +} + +fn new_inner(args: &NewArgs) -> Result<()> { + let dir = &std::env::current_dir().into_diagnostic()?.join(&args.name); + std::fs::create_dir(dir).into_diagnostic()?; + let schema_path = dir.join("schema.cedarschema.json"); + let policy_path = dir.join("policy.cedar"); + let entities_path = dir.join("entities.jon"); + generate_schema(&schema_path)?; + generate_policy(&policy_path)?; + generate_entities(&entities_path) +} + +pub fn new(args: &NewArgs) -> CedarExitCode { + if let Err(err) = new_inner(args) { + println!("Error: {err:?}"); + CedarExitCode::Failure + } else { + CedarExitCode::Success + } +} + fn create_slot_env(data: &HashMap) -> Result> { data.iter() .map(|(key, value)| Ok(EntityUid::from_str(value).map(|euid| (key.clone(), euid))?)) diff --git a/cedar-policy-cli/src/main.rs b/cedar-policy-cli/src/main.rs index d009fd7ad..1e2540d36 100644 --- a/cedar-policy-cli/src/main.rs +++ b/cedar-policy-cli/src/main.rs @@ -20,7 +20,7 @@ use clap::Parser; use miette::ErrorHook; use cedar_policy_cli::{ - authorize, check_parse, evaluate, format_policies, link, validate, CedarExitCode, Cli, + authorize, check_parse, evaluate, format_policies, link, new, validate, CedarExitCode, Cli, Commands, ErrorFormat, }; @@ -47,5 +47,6 @@ fn main() -> CedarExitCode { Commands::Validate(args) => validate(&args), Commands::Format(args) => format_policies(&args), Commands::Link(args) => link(&args), + Commands::New(args) => new(&args), } }