Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions implants/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ members = [
"lib/eldritchv2/stdlib/eldritch-libreport",
"lib/eldritchv2/stdlib/eldritch-libsys",
"lib/eldritchv2/stdlib/eldritch-libtime",
"lib/eldritchv2/stdlib/eldritch-libcache",
"lib/eldritchv2/stdlib/tests",
"lib/eldritchv2/stdlib/migration",
"lib/eldritchv2/eldritchv2",
Expand All @@ -47,6 +48,7 @@ eldritchv2 = {path = "lib/eldritchv2/eldritchv2", default-features = false}
eldritch-agent = {path = "lib/eldritchv2/eldritch-agent"}
eldritch-libagent = {path = "lib/eldritchv2/stdlib/eldritch-libagent", default-features = false}
eldritch-libassets = {path = "lib/eldritchv2/stdlib/eldritch-libassets", default-features = false}
eldritch-libcache = {path = "lib/eldritchv2/stdlib/eldritch-libcache", default-features = false}
eldritch-libcrypto = {path = "lib/eldritchv2/stdlib/eldritch-libcrypto",default-features = false }
eldritch-libfile = {path = "lib/eldritchv2/stdlib/eldritch-libfile",default-features = false }
eldritch-libhttp = {path = "lib/eldritchv2/stdlib/eldritch-libhttp",default-features = false }
Expand Down
11 changes: 8 additions & 3 deletions implants/golemv2/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use eldritchv2::assets::{
AssetsLibrary,
std::{EmbeddedAssets, StdAssetsLibrary},
};
use eldritchv2::cache::std::StdCacheLibrary;
use eldritchv2::conversion::ToValue;
use eldritchv2::{ForeignValue, Interpreter, StdoutPrinter};
use pb::c2::TaskContext;
Expand Down Expand Up @@ -36,7 +37,7 @@ pub struct ParsedTome {
}

// Build a new runtime
fn new_runtime(assetlib: impl ForeignValue + 'static) -> Interpreter {
fn new_runtime(assetlib: impl ForeignValue + 'static, cache_lib: StdCacheLibrary) -> Interpreter {
// Maybe change the printer here?
let mut interp = Interpreter::new_with_printer(Arc::new(StdoutPrinter)).with_default_libs();
// Register the libraries that we need. Basically the same as interp.with_task_context but
Expand All @@ -55,6 +56,7 @@ fn new_runtime(assetlib: impl ForeignValue + 'static) -> Interpreter {
eldritchv2::pivot::std::StdPivotLibrary::new(agent.clone(), task_context.clone());
interp.register_lib(pivot_lib);
interp.register_lib(assetlib);
interp.register_lib(cache_lib);
interp
}

Expand Down Expand Up @@ -158,16 +160,17 @@ fn main() -> anyhow::Result<()> {
}
}

// Setup the interpreter. This will need refactored when we do multi-threaded
let mut interp = new_runtime(locker);
let cache_lib = StdCacheLibrary::new();

if matches.contains_id("interactive") {
let interp = new_runtime(locker.clone(), cache_lib);
repl::repl(interp)?;
return Ok(());
}

// Print a debug for the configured assets and tomes
if matches.get_flag("dump") {
let mut interp = new_runtime(locker.clone(), cache_lib.clone());
let tome_names: Vec<&str> = parsed_tomes.iter().map(|tome| tome.name.as_str()).collect();
println!("tomes = {:?}", tome_names);
match interp.interpret("print(\"assets =\", assets.list())") {
Expand All @@ -177,10 +180,12 @@ fn main() -> anyhow::Result<()> {
exit(127);
}
}
return Ok(());
}

// Time to run some commands
for tome in parsed_tomes {
let mut interp = new_runtime(locker.clone(), cache_lib.clone());
// In the future we would like to set input params here.
// We could compile them in for the default dropper assets
let params: BTreeMap<String, String> = BTreeMap::new();
Expand Down
17 changes: 15 additions & 2 deletions implants/imixv2/src/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::time::SystemTime;

use eldritchv2::agent::agent::Agent;
use eldritchv2::assets::std::EmbeddedAssets;
use eldritchv2::cache::std::StdCacheLibrary;
use eldritchv2::{Interpreter, Printer, Span, Value, conversion::ToValue};
use pb::c2::{ReportTaskOutputRequest, Task, TaskContext, TaskError, TaskOutput};
use prost_types::Timestamp;
Expand Down Expand Up @@ -46,6 +47,7 @@ struct TaskHandle {
#[derive(Clone)]
pub struct TaskRegistry {
tasks: Arc<Mutex<BTreeMap<i64, TaskHandle>>>,
cache_lib: StdCacheLibrary,
}

impl Default for TaskRegistry {
Expand All @@ -58,6 +60,7 @@ impl TaskRegistry {
pub fn new() -> Self {
Self {
tasks: Arc::new(Mutex::new(BTreeMap::new())),
cache_lib: StdCacheLibrary::new(),
}
}

Expand All @@ -74,6 +77,7 @@ impl TaskRegistry {
}

let tasks_registry = self.tasks.clone();
let cache_lib = self.cache_lib.clone();
// Capture runtime handle to spawn streaming task
let runtime_handle = tokio::runtime::Handle::current();

Expand All @@ -83,7 +87,7 @@ impl TaskRegistry {

thread::spawn(move || {
if let Some(tome) = task.tome {
execute_task(task_context.clone(), tome, agent, runtime_handle);
execute_task(task_context.clone(), tome, agent, runtime_handle, cache_lib);
} else {
#[cfg(debug_assertions)]
log::warn!("Task {0} has no tome", task_context.clone().task_id);
Expand Down Expand Up @@ -165,11 +169,18 @@ fn execute_task(
tome: pb::eldritch::Tome,
agent: Arc<dyn Agent>,
runtime_handle: tokio::runtime::Handle,
cache_lib: StdCacheLibrary,
) {
// Setup StreamPrinter and Interpreter
let (tx, rx) = mpsc::unbounded_channel();
let printer = Arc::new(StreamPrinter::new(tx));
let mut interp = setup_interpreter(task_context.clone(), &tome, agent.clone(), printer.clone());
let mut interp = setup_interpreter(
task_context.clone(),
&tome,
agent.clone(),
printer.clone(),
cache_lib,
);

// Report Start
report_start(task_context.clone(), &agent);
Expand Down Expand Up @@ -217,8 +228,10 @@ fn setup_interpreter(
tome: &pb::eldritch::Tome,
agent: Arc<dyn Agent>,
printer: Arc<StreamPrinter>,
cache_lib: StdCacheLibrary,
) -> Interpreter {
let mut interp = Interpreter::new_with_printer(printer).with_default_libs();
interp.register_lib(cache_lib);

// Remote asset filenames
let remote_assets = tome.file_names.clone();
Expand Down
4 changes: 4 additions & 0 deletions implants/lib/eldritchv2/eldritchv2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ eldritch-libregex = { workspace = true, default-features = false }
eldritch-libreport = { workspace = true, default-features = false }
eldritch-libsys = { workspace = true, default-features = false }
eldritch-libtime = { workspace = true, default-features = false }
eldritch-libcache = { workspace = true, default-features = false }
pb = { workspace = true }
eldritch-repl = { workspace = true, default-features = false }

Expand All @@ -41,6 +42,7 @@ fake_bindings = [
"fake_report",
"fake_sys",
"fake_time",
"fake_cache",
]
fake_agent = ["eldritch-libagent/fake_bindings"]
fake_assets = ["eldritch-libassets/fake_bindings"]
Expand All @@ -54,6 +56,7 @@ fake_regex = ["eldritch-libregex/fake_bindings"]
fake_report = ["eldritch-libreport/fake_bindings"]
fake_sys = ["eldritch-libsys/fake_bindings"]
fake_time = ["eldritch-libtime/fake_bindings"]
fake_cache = ["eldritch-libcache/fake_bindings"]
stdlib = [
"eldritch-libagent/stdlib",
"eldritch-libassets/stdlib",
Expand All @@ -67,6 +70,7 @@ stdlib = [
"eldritch-libreport/stdlib",
"eldritch-libsys/stdlib",
"eldritch-libtime/stdlib",
"eldritch-libcache/stdlib",
]

[dev-dependencies]
Expand Down
4 changes: 4 additions & 0 deletions implants/lib/eldritchv2/eldritchv2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ extern crate std;
// Re-exports from eldritch-stdlib
pub use eldritch_libagent as agent;
pub use eldritch_libassets as assets;
pub use eldritch_libcache as cache;
pub use eldritch_libcrypto as crypto;
pub use eldritch_libfile as file;
pub use eldritch_libhttp as http;
Expand Down Expand Up @@ -46,6 +47,8 @@ pub use crate::assets::std::EmptyAssets;
#[cfg(feature = "stdlib")]
use crate::assets::std::StdAssetsLibrary;
#[cfg(feature = "stdlib")]
use crate::cache::std::StdCacheLibrary;
#[cfg(feature = "stdlib")]
use crate::crypto::std::StdCryptoLibrary;
#[cfg(feature = "stdlib")]
use crate::file::std::StdFileLibrary;
Expand Down Expand Up @@ -117,6 +120,7 @@ impl Interpreter {
pub fn with_default_libs(mut self) -> Self {
#[cfg(feature = "stdlib")]
{
self.inner.register_lib(StdCacheLibrary::new());
self.inner.register_lib(StdCryptoLibrary);
self.inner.register_lib(StdFileLibrary);
self.inner.register_lib(StdHttpLibrary);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ impl AssetBackend for AgentAssets {
}
}

#[derive(Clone)]
#[eldritch_library_impl(AssetsLibrary)]
pub struct StdAssetsLibrary {
// Stores a vector of boxed trait objects for runtime polymorphism.
Expand Down
14 changes: 14 additions & 0 deletions implants/lib/eldritchv2/stdlib/eldritch-libcache/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "eldritch-libcache"
version = "0.1.0"
edition = "2024"

[dependencies]
eldritch-core = { workspace = true }
eldritch-macros = { workspace = true }
spin = { workspace = true, features = ["mutex"] }

[features]
default = ["stdlib"]
stdlib = []
fake_bindings = []
46 changes: 46 additions & 0 deletions implants/lib/eldritchv2/stdlib/eldritch-libcache/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#![allow(clippy::mutable_key_type)]
#![allow(unexpected_cfgs)]
extern crate alloc;

use alloc::string::String;
use eldritch_core::Value;
use eldritch_macros::{eldritch_library, eldritch_method};

#[cfg(feature = "stdlib")]
pub mod std;

#[eldritch_library("cache")]
/// The `cache` library provides a thread-safe in-memory cache shared across interpreters.
pub trait CacheLibrary {
#[eldritch_method]
/// Retrieves a value from the cache.
///
/// **Parameters**
/// - `key` (`str`): The key to look up.
///
/// **Returns**
/// - `Value`: The value if found, or `Null` (or undefined behavior depending on caller, but returns Value).
/// Actually, eldritch `Value` usually has a `Null` variant or we can return `Value::Null` equivalent.
fn get(&self, key: String) -> Result<Value, String>;

#[eldritch_method]
/// Sets a value in the cache.
///
/// **Parameters**
/// - `key` (`str`): The key to set.
/// - `val` (`Value`): The value to store.
///
/// **Returns**
/// - `None`
fn set(&self, key: String, val: Value) -> Result<(), String>;

#[eldritch_method]
/// Deletes a value from the cache.
///
/// **Parameters**
/// - `key` (`str`): The key to remove.
///
/// **Returns**
/// - `Value`: The removed value, or error/null if not found.
fn delete(&self, key: String) -> Result<Value, String>;
}
51 changes: 51 additions & 0 deletions implants/lib/eldritchv2/stdlib/eldritch-libcache/src/std.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use crate::CacheLibrary;
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::sync::Arc;
use eldritch_core::Value;
use eldritch_macros::eldritch_library_impl;
use spin::Mutex;

#[derive(Debug, Clone)]
#[eldritch_library_impl(CacheLibrary)]
pub struct StdCacheLibrary {
store: Arc<Mutex<BTreeMap<String, Value>>>,
}

impl Default for StdCacheLibrary {
fn default() -> Self {
Self {
store: Arc::new(Mutex::new(BTreeMap::new())),
}
}
}

impl StdCacheLibrary {
pub fn new() -> Self {
Self::default()
}
}

impl CacheLibrary for StdCacheLibrary {
fn get(&self, key: String) -> Result<Value, String> {
let guard = self.store.lock();
match guard.get(&key) {
Some(v) => Ok(v.clone()),
None => Ok(Value::None),
}
}

fn set(&self, key: String, val: Value) -> Result<(), String> {
let mut guard = self.store.lock();
guard.insert(key, val);
Ok(())
}

fn delete(&self, key: String) -> Result<Value, String> {
let mut guard = self.store.lock();
match guard.remove(&key) {
Some(v) => Ok(v),
None => Ok(Value::None),
}
}
}
1 change: 1 addition & 0 deletions implants/lib/eldritchv2/stdlib/tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ serde = { workspace = true, features = ["derive"] }
serde_yaml = {workspace = true}
spin = { version = "0.10.0", features = ["rwlock"] }
log = { workspace = true }
uuid = { workspace = true, features = ["v4"] }
Loading
Loading