Skip to content

Commit

Permalink
Posix reasoner is now working
Browse files Browse the repository at this point in the history
Settled on having the paths come into a config instead of the ol' Brane way.

Next up: extending logging, re-introducing contexts.
  • Loading branch information
Lut99 committed Oct 15, 2024
1 parent c718b1b commit a380c56
Show file tree
Hide file tree
Showing 11 changed files with 468 additions and 283 deletions.
35 changes: 35 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 12 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ members = [
# Implementations
"lib/reasoners/eflint-json",
"lib/reasoners/no-op",
# "lib/reasoners/posix",
"lib/reasoners/posix",
"lib/loggers/file",
"lib/loggers/mock",
"lib/resolvers/file",
Expand Down Expand Up @@ -38,10 +38,10 @@ name = "eflint"
path = "./examples/eflint.rs"
required-features = ["eflint-json-reasoner", "eflint-to-json", "file-logger"]

# [[example]]
# name = "posix"
# path = "./examples/posix.rs"
# required-features = ["posix-reasoner", "file-logger"]
[[example]]
name = "posix"
path = "./examples/posix.rs"
required-features = ["posix-reasoner", "file-logger", "serde", "workflow"]

[[example]]
name = "no-op"
Expand All @@ -52,7 +52,7 @@ required-features = ["no-op-reasoner", "file-logger"]
[dependencies]
eflint-json-reasoner = { path = "./lib/reasoners/eflint-json", optional = true }
no-op-reasoner = { path = "./lib/reasoners/no-op", optional = true }
# posix-reasoner = { path = "./lib/reasoners/posix", optional = true }
posix-reasoner = { path = "./lib/reasoners/posix", optional = true }
file-logger = { path = "./lib/loggers/file", optional = true }
mock-logger = { path = "./lib/loggers/mock", optional = true }
file-resolver = { path = "./lib/resolvers/file", optional = true }
Expand All @@ -68,19 +68,19 @@ error-trace = { git = "https://github.com/Lut99/error-trace-rs", tag = "v3.0.0"
serde_json = "1.0.120"
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
tokio = { version = "1.40.0", default-features = false, features = ["macros", "rt"] }
tokio = { version = "1.40.0", default-features = false, features = ["fs", "io-std", "macros", "rt"] }


[features]
default = []

all = ["reasoners", "loggers", "resolvers", "auxillary"]

# reasoners = ["eflint-json-reasoner", "no-op-reasoner", "posix-reasoner"]
reasoners = ["eflint-json-reasoner", "no-op-reasoner"]
reasoners = ["eflint-json-reasoner", "no-op-reasoner", "posix-reasoner"]
# reasoners = ["eflint-json-reasoner", "no-op-reasoner"]
eflint-json-reasoner = ["dep:eflint-json-reasoner"]
no-op-reasoner = ["dep:no-op-reasoner"]
# posix-reasoner = ["dep:posix-reasoner"]
posix-reasoner = ["dep:posix-reasoner"]

loggers = ["file-logger", "mock-logger"]
file-logger = ["dep:file-logger"]
Expand All @@ -92,3 +92,5 @@ file-resolver = ["dep:file-resolver"]
auxillary = ["eflint-to-json", "workflow"]
eflint-to-json = ["dep:eflint-to-json"]
workflow = ["dep:workflow"]

serde = ["workflow/serde"]
188 changes: 186 additions & 2 deletions examples/posix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// Created:
// 11 Oct 2024, 16:32:29
// Last edited:
// 11 Oct 2024, 16:32:52
// 15 Oct 2024, 17:05:12
// Auto updated?
// Yes
//
Expand All @@ -13,6 +13,190 @@
//! persmissions.
//

use std::path::PathBuf;

use clap::Parser;
use console::style;
use error_trace::trace;
use file_logger::FileLogger;
use policy_reasoner::reasoners::posix::{PosixReasonerConnector, State};
use policy_reasoner::spec::auditlogger::SessionedAuditLogger;
use policy_reasoner::spec::ReasonerConnector as _;
use policy_reasoner::workflow::Workflow;
use posix_reasoner::config::Config;
use spec::reasonerconn::ReasonerResponse;
use tokio::fs;
use tokio::io::{self, AsyncReadExt as _};
use tracing::{debug, error, info, Level};


/***** HELPER FUNCTIONS *****/
/// Reads a [`Workflow`] from either stdin or disk.
///
/// # Arguments
/// - `input`: Either '-' to read from stdin, or a path of the file to read from otherwise.
///
/// # Returns
/// A parsed [`Workflow`] file.
///
/// # Errors
/// This function errors if it failed to read stdin OR the file, or parse it as a valid Workflow.
///
/// Note that errorring is done by calling [`std::process::exit()`].
async fn load_workflow(input: String) -> Workflow {
let workflow: String = if input == "-" {
let mut raw: Vec<u8> = Vec::new();
if let Err(err) = io::stdin().read_buf(&mut raw).await {
error!("{}", trace!(("Failed to read from stdin"), err));
std::process::exit(1);
}
match String::from_utf8(raw) {
Ok(raw) => raw,
Err(err) => {
error!("{}", trace!(("Stdin is not valid UTF-8"), err));
std::process::exit(1);
},
}
} else {
match fs::read_to_string(&input).await {
Ok(raw) => raw,
Err(err) => {
error!("{}", trace!(("Failed to read the workflow file {input:?}"), err));
std::process::exit(1);
},
}
};
match serde_json::from_str(&workflow) {
Ok(config) => config,
Err(err) => {
error!("{}", trace!(("{} is not a valid workflow", if input == "-" { "Stdin".to_string() } else { format!("File {input:?}") }), err));
std::process::exit(1);
},
}
}

/// Reads a [`Config`] from disk.
///
/// # Arguments
/// - `path`: The path to the config file to load.
///
/// # Returns
/// A parsed [`Config`] file.
///
/// # Errors
/// This function errors if it failed to read the file, or it did not contain a valid config.
///
/// Note that errorring is done by calling [`std::process::exit()`].
async fn load_config(path: PathBuf) -> Config {
// Load the file and parse it
let config: String = match fs::read_to_string(&path).await {
Ok(raw) => raw,
Err(err) => {
error!("{}", trace!(("Failed to read the config file {:?}", path.display()), err));
std::process::exit(1);
},
};
let mut config: Config = match serde_json::from_str(&config) {
Ok(config) => config,
Err(err) => {
error!("{}", trace!(("File {:?} is not a valid config file", path.display()), err));
std::process::exit(1);
},
};

// Resolve relative files to relative to the binary, for consistency of calling the example
let prefix: PathBuf = match std::env::current_exe() {
Ok(path) => {
if let Some(parent) = path.parent() {
parent.into()
} else {
path
}
},
Err(err) => {
error!("{}", trace!(("Failed to obtain the current executable's path"), err));
std::process::exit(1);
},
};
for path in config.data.values_mut().map(|data| &mut data.path) {
if path.is_relative() {
*path = prefix.join(&*path);
}
}
debug!("Config after resolving relative paths: {config:?}");

// Done
config
}





/***** ARGUMENTS *****/
/// The arguments for this binary.
#[derive(Parser)]
pub struct Arguments {
/// Whether to make `info!()` and `debug!()` visible.
#[clap(long, help = "If given, enables INFO- and DEBUG-level logging.")]
debug: bool,
/// Whether to make `trace!()` visible.
#[clap(long, help = "If given, enables TRACE-level logging. Implies '--debug'.")]
trace: bool,

/// The file containing the workflow to check.
#[clap(name = "WORKFLOW", default_value = "-", help = "The JSON workflow to evaluate. Use '-' to read from stdin.")]
workflow: String,
/// The file containing the config for the reasoner.
#[clap(short, long, help = "The JSON configuration file to read that configures the policy.")]
config: PathBuf,
}





/***** ENTRYPOINT *****/
fn main() {}
#[tokio::main(flavor = "current_thread")]
async fn main() {
// Parse the arguments
let args = Arguments::parse();

// Setup the logger
tracing_subscriber::fmt()
.with_max_level(if args.trace {
Level::TRACE
} else if args.debug {
Level::DEBUG
} else {
Level::WARN
})
.init();
info!("{} - v{}", env!("CARGO_BIN_NAME"), env!("CARGO_PKG_VERSION"));

// Read the workflow & config
let workflow: Workflow = load_workflow(args.workflow).await;
let config: Config = load_config(args.config).await;

// Create the logger
let logger: SessionedAuditLogger<FileLogger> =
SessionedAuditLogger::new("test", FileLogger::new(format!("{} - v{}", env!("CARGO_BIN_NAME"), env!("CARGO_PKG_VERSION")), "./test.log"));

// Run the reasoner
let conn: PosixReasonerConnector = PosixReasonerConnector::new();
let verdict: ReasonerResponse<()> = match conn.consult(State { workflow, config }, (), &logger).await {
Ok(res) => res,
Err(err) => {
error!("{}", trace!(("Failed to consult the POSIX reasoner"), err));
std::process::exit(1);
},
};

// OK, report
match verdict {
ReasonerResponse::Success => println!("{} {}", style("Reasoner says:").bold(), style("OK").bold().green()),
ReasonerResponse::Violated(_) => {
println!("{} {}", style("Reasoner says:").bold(), style("VIOLATION").bold().red());
},
}
}
3 changes: 2 additions & 1 deletion lib/reasoners/posix/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,11 @@ license.workspace = true


[dependencies]
itertools = "0.13.0"
# itertools = "0.13.0"
serde = { version = "1.0.204", features = ["derive"] }
serde_json = "1.0.120"
thiserror = "1.0.61"
tokio = { version = "1.40.0", default-features = false, features = ["fs", "io-util"] }
tracing = "0.1.40"

error-trace = { git = "https://github.com/Lut99/error-trace-rs", tag = "v3.1.0" }
Expand Down
Loading

0 comments on commit a380c56

Please sign in to comment.