Compare commits

...

6 Commits

Author SHA1 Message Date
brotoskyj 0dbc744471 Merge remote-tracking branch 'origin/RustImplementation' into RustImplementation 2025-12-15 14:14:16 -05:00
brotoskyj 7a912bddab Bug Fixes
Security Vulnerabilities Patched
RUSTSEC-2025-0009 - Some AES functions may panic when overflow checking is enabled
RUSTSEC-2024-0336 - rustls::Connection::Common::complete_io could fall into an infinite loop based on network input
closes #47
2025-12-15 14:13:57 -05:00
brotoskyj 24211c318b Merge remote-tracking branch 'origin/RustImplementation' into RustImplementation
Build Library / Build Library (push) Successful in 5m2s
2025-12-15 14:12:30 -05:00
brotoskyj 630e0a3cdf Bug Fixes
Security Vulnerabilities Patched
RUSTSEC-2025-0009 - Some AES functions may panic when overflow checking is enabled
RUSTSEC-2024-0336 - rustls::Connection::Common::complete_io could fall into an infinite loop based on network input
2025-12-15 14:12:03 -05:00
Zarithas 797d0f4462 fix(policy-prep): implement table editors and workflow improvements
- Add table editors for Policy Prep workflow
- 'Add to policy' remains a placeholder
- Apply planned tweaks:
  - Replace ballot checkbox with ✓ for selection
  - Relocate loading screen text to bottom:
    'Building Path exclusions and publisher lists...
     This may take a moment for large datasets.'
  - Ensure interaction with all tables before allowing review steps
  - Move excessive logging to debug level
  - Add Step 0 to explain process before user begins

Notes:
Further discussion needed on enforcing table interaction before review.
2025-12-11 16:55:12 -05:00
brotoskyj 59bb97ec4e Refactored LoxideLibs
Build Library / Build Library (push) Successful in 5m30s
1. Added compatibility check, LoxideLibs will now abort the entire program if OS is not linux or windows.
2. Changed the python data extraction compatibility layer, LoxideLibs was calling the extract data function twice, causing very slight overhead. I have now changed this so that the function returns a Struct that is now easily extractable via dot method notation.
2025-12-11 11:47:50 -05:00
10 changed files with 1743 additions and 1277 deletions
File diff suppressed because it is too large Load Diff
+24 -24
View File
@@ -88,9 +88,9 @@ def sortHashes(
): ):
working_dir = load_env("WORKING_DIR") working_dir = load_env("WORKING_DIR")
history_days = Selector.select_value( history_days = Selector.select_value(
prompt="Enter how many days of history to pull (1150): ", prompt="Enter how many days of history to pull (1-365): ",
value_type=int, value_type=int,
valid_range=(1, 150), valid_range=(1, 365),
) )
logger.debug(f"{history_days} day selected for history") logger.debug(f"{history_days} day selected for history")
@@ -655,7 +655,7 @@ def section_header(title):
def printEnforceChecklist(selected_policies, destination_policy, destination_allowlist): def printEnforceChecklist(selected_policies, destination_policy, destination_allowlist):
working_dir = load_env("WORKING_DIR") working_dir = load_env("WORKING_DIR")
section_header("Prepare to Enforce Policy ") section_header("Prepare to Enforce Policy")
print( print(
colorText( colorText(
"\nSequentially follow these steps to prepare a policy for enforcement:", "\nSequentially follow these steps to prepare a policy for enforcement:",
@@ -670,11 +670,11 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all
) )
) )
if not selected_policies: if not selected_policies:
print(colorText(" [] No policies have been chosen", "red")) print(colorText(" [❌] No policies have been chosen", "red"))
else: else:
print(colorText("The following policies have been chosen:", "green")) print(colorText("The following policies have been chosen:", "green"))
for policy in selected_policies: for policy in selected_policies:
print(colorText(f" [] {policy.name}", "green")) print(colorText(f" [✅] {policy.name}", "green"))
# Step 2: Destination Policy and Allowlist # Step 2: Destination Policy and Allowlist
print( print(
@@ -683,22 +683,22 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all
if destination_policy: if destination_policy:
print( print(
colorText( colorText(
f" [] {destination_policy[0].name} has been selected as the destination policy", f" [✅] {destination_policy[0].name} has been selected as the destination policy",
"green", "green",
) )
) )
else: else:
print(colorText(" [] No destination policy has been chosen", "red")) print(colorText(" [❌] No destination policy has been chosen", "red"))
if destination_allowlist: if destination_allowlist:
print( print(
colorText( colorText(
f" [] {destination_allowlist[0].name} has been selected as allowlist", f" [✅] {destination_allowlist[0].name} has been selected as allowlist",
"green", "green",
) )
) )
else: else:
print(colorText(" [] No allowlist has been chosen", "red")) print(colorText(" [❌] No allowlist has been chosen", "red"))
# Step 3: Data Preparation # Step 3: Data Preparation
print( print(
@@ -713,9 +713,9 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all
print( print(
colorText( colorText(
( (
" [] Data has been fetched" " [✅] Data has been fetched"
if os.path.exists(review_path) if os.path.exists(review_path)
else " [] Data has not been fetched" else " [❌] Data has not been fetched"
), ),
"green" if os.path.exists(review_path) else "red", "green" if os.path.exists(review_path) else "red",
) )
@@ -723,7 +723,7 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all
else: else:
print( print(
colorText( colorText(
" [] No policies selected, cannot check data fetch status", "red" " [❌] No policies selected, cannot check data fetch status", "red"
) )
) )
@@ -756,9 +756,9 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all
print( print(
colorText( colorText(
( (
" [] Reviewed hashes have been loaded" " [✅] Reviewed hashes have been loaded"
if os.path.exists(approved_path) if os.path.exists(approved_path)
else " [] Reviewed hashes have not been loaded" else " [❌] Reviewed hashes have not been loaded"
), ),
"green" if os.path.exists(approved_path) else "red", "green" if os.path.exists(approved_path) else "red",
) )
@@ -766,9 +766,9 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all
print( print(
colorText( colorText(
( (
" [] Path review list created" " [✅] Path review list created"
if os.path.exists(second_review_path) if os.path.exists(second_review_path)
else " [] Path review list has not been created" else " [❌] Path review list has not been created"
), ),
"green" if os.path.exists(second_review_path) else "red", "green" if os.path.exists(second_review_path) else "red",
) )
@@ -776,7 +776,7 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all
else: else:
print( print(
colorText( colorText(
" [] No policies selected, cannot check reviewed hashes or path list", " [❌] No policies selected, cannot check reviewed hashes or path list",
"red", "red",
) )
) )
@@ -812,9 +812,9 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all
print( print(
colorText( colorText(
( (
" [] Reviewed path list detected" " [✅] Reviewed path list detected"
if os.path.exists(reviewed_path) if os.path.exists(reviewed_path)
else " [] Path review list has not been detected" else " [❌] Path review list has not been detected"
), ),
"green" if os.path.exists(reviewed_path) else "red", "green" if os.path.exists(reviewed_path) else "red",
) )
@@ -825,9 +825,9 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all
print( print(
colorText( colorText(
( (
" [] Preflight Path Exclusion List has been generated" " [✅] Preflight Path Exclusion List has been generated"
if preflight_ready if preflight_ready
else " [] Preflight Path Exclusion List has not been generated" else " [❌] Preflight Path Exclusion List has not been generated"
), ),
"green" if preflight_ready else "red", "green" if preflight_ready else "red",
) )
@@ -835,7 +835,7 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all
else: else:
print( print(
colorText( colorText(
" [] No policies selected, cannot check preflight status", "red" " [❌] No policies selected, cannot check preflight status", "red"
) )
) )
@@ -866,5 +866,5 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all
print(colorText(" Apply approved hashes to allowlist", "cyan")) print(colorText(" Apply approved hashes to allowlist", "cyan"))
# Utility Options # Utility Options
print(colorText("F. Open Working Directory", "cyan")) print(colorText("F. Open Working Directory", "cyan"))
print(colorText("B. Back", "cyan")) print(colorText("B. Back", "cyan"))
+355 -884
View File
File diff suppressed because it is too large Load Diff
+11 -13
View File
@@ -1,33 +1,31 @@
[package] [package]
name = "airlock_libs" name = "signoz_test"
version = "5.2.0" version = "6.0.0"
edition = "2024" edition = "2024"
[lib]
crate-type = ["cdylib"]
[dependencies] [dependencies]
chrono = "0.4.42" chrono = "0.4.42"
indicatif = "0.18.2" indicatif = "0.18.2"
mongodb = "3.3.0" mongodb = "3.3.0"
opentelemetry = { version = "0.18.0", features = ["rt-tokio", "metrics", "trace"] } opentelemetry = { version = "0.27.0", features = ["logs", "metrics", "trace"] }
opentelemetry-otlp = { version = "0.11.0", features = ["trace", "metrics"] } opentelemetry-otlp = { version = "0.27.0", features = ["trace", "metrics", "grpc-tonic", "http-proto", "tls", "reqwest-client", "reqwest-rustls"] }
opentelemetry-semantic-conventions = { version = "0.10.0" } opentelemetry-semantic-conventions = { version = "0.27.0" }
opentelemetry-proto = { version = "0.1.0"} opentelemetry-proto = { version = "0.27.0"}
pyo3 = { version = "0.27.0", features = ["extension-module", "generate-import-lib"] } pyo3 = { version = "0.27.0", features = ["extension-module", "generate-import-lib"] }
reqwest = { version = "0.12.24", features = ["json", "native-tls"] } reqwest = { version = "0.12.24", features = ["json", "native-tls", "rustls-tls"] }
serde = "1.0.228" serde = "1.0.228"
serde-pyobject = "0.8.0" serde-pyobject = "0.8.0"
serde_json = "1.0.145" serde_json = "1.0.145"
tokio = { version = "1.48.0", features = ["full"] } tokio = { version = "1.48.0", features = ["full"] }
tonic = { version = "0.8.2", features = ["tls-roots"] } tonic = { version = "0.12.3", features = ["tls-roots"] }
tracing = "0.1.41" tracing = "0.1.41"
tracing-subscriber = "0.3.20" tracing-subscriber = "0.3.20"
tracing-opentelemetry = "0.32.0" tracing-opentelemetry = "0.32.0"
pyo3-async-runtimes = { version = "0.27.0", features = ["async-std", "tokio"] }
crossbeam = "0.8.4" crossbeam = "0.8.4"
log = "0.4.29" log = "0.4.29"
flexi_logger = "0.31.7" flexi_logger = "0.31.7"
opentelemetry-appender-log = "0.27.0"
opentelemetry_sdk = { version = "0.27.0", features = ["rt-tokio", "trace"] }
[package.metadata.maturin] [package.metadata.maturin]
generate-abi-stubs = true generate-abi-stubs = true
@@ -40,4 +38,4 @@ codegen-units = 1
panic = 'abort' panic = 'abort'
strip = true strip = true
debug-assertions = false debug-assertions = false
overflow-checks = false overflow-checks = true
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "maturin"
[project] [project]
name = "airlock_libs" name = "airlock_libs"
version = "5.2.0" version = "6.0.0"
description = "Airlock Digital API Wrapper" description = "Airlock Digital API Wrapper"
readme = "README.md" readme = "README.md"
license = { text = "AGPL-3.0-only" } license = { text = "AGPL-3.0-only" }
+20 -26
View File
@@ -64,36 +64,30 @@ pub struct Group {
pub(crate) localip: String, pub(crate) localip: String,
} }
pub enum ExtractedValues { pub struct PyData {
Headers(reqwest::header::HeaderMap), pub headers: reqwest::header::HeaderMap,
BaseUrl(String), pub base_url: String,
} }
pub trait Converter { impl PyData {
fn convert(py: Python<'_>, py_self: &Py<PyAny>, extract_headers: bool) -> ExtractedValues; pub fn extract_data(py: Python<'_>, obj: &Py<PyAny>) -> Self {
} let headers_raw = obj.getattr(py, "headers").unwrap().to_string();
let headers_json = headers_raw.replace('\'', "\"");
pub struct PyData; let parsed: Value = serde_json::from_str(&headers_json).unwrap();
let mut header_map = HeaderMap::new();
impl Converter for PyData { if let Some(obj) = parsed.as_object() {
fn convert(py: Python<'_>, py_self: &Py<PyAny>, extract_headers: bool) -> ExtractedValues { for (key, val) in obj {
if extract_headers { if let Some(v) = val.as_str() {
let headers = py_self.getattr(py, "headers").unwrap().to_string(); let header_name = HeaderName::from_str(key).unwrap();
let headers_replace = headers.replace('\'', "\""); let header_value: HeaderValue = HeaderValue::from_str(v).unwrap();
let parsed: Value = serde_json::from_str(headers_replace.as_str()).unwrap(); header_map.insert(header_name, header_value);
let mut header_map = HeaderMap::new();
if let Some(obj) = parsed.as_object() {
for (_key, value) in obj {
if let Some(v) = value.as_str() {
let val = HeaderValue::from_str(v).unwrap();
header_map.insert(HeaderName::from_str("X-APIKey").unwrap(), val);
}
} }
} }
ExtractedValues::Headers(header_map) }
} else { let base_url = obj.getattr(py, "base_url").unwrap().to_string();
let base_url = py_self.getattr(py, "base_url").unwrap().to_string(); Self {
ExtractedValues::BaseUrl(base_url) headers: header_map,
base_url,
} }
} }
} }
+6 -6
View File
@@ -1,15 +1,15 @@
pub use chrono::{Duration, Local, NaiveDate}; pub use chrono::{Duration, Local, NaiveDate};
pub use indicatif::{MultiProgress, ProgressBar, ProgressDrawTarget, ProgressStyle}; pub use indicatif::{MultiProgress, ProgressBar, ProgressDrawTarget, ProgressStyle};
pub use mongodb::bson::oid::ObjectId; pub use mongodb::bson::oid::ObjectId;
pub use opentelemetry::global::shutdown_tracer_provider; pub use opentelemetry::global::GlobalTracerProvider;
pub use opentelemetry::sdk::Resource;
pub use opentelemetry::trace::noop::NoopTracerProvider; pub use opentelemetry::trace::noop::NoopTracerProvider;
pub use opentelemetry::trace::{Status, TraceContextExt, TraceError}; pub use opentelemetry::trace::{Status, TraceContextExt, Tracer};
pub use opentelemetry::{Context, KeyValue, sdk::trace as sdktrace, trace::Tracer}; pub use opentelemetry::*;
pub use opentelemetry::{Key, global}; pub use opentelemetry_otlp::ExportConfig;
pub use opentelemetry_otlp::WithExportConfig; pub use opentelemetry_otlp::WithExportConfig;
pub use opentelemetry_sdk::Resource;
pub use opentelemetry_sdk::trace::{Config, TracerProvider};
pub use pyo3::{prelude::*, types::PyString}; pub use pyo3::{prelude::*, types::PyString};
pub use pyo3_async_runtimes::async_std;
pub use reqwest::{ pub use reqwest::{
Client, Client,
header::{HeaderMap, HeaderName, HeaderValue}, header::{HeaderMap, HeaderName, HeaderValue},
+44 -36
View File
@@ -1,8 +1,10 @@
use crate::modules::datatypes::*; use crate::modules::datatypes::*;
use crate::prelude::*; use crate::prelude::*;
use crossbeam::channel::unbounded; use crossbeam::channel::unbounded;
use opentelemetry_otlp::WithTonicConfig;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
use tonic::transport::{Channel, ClientTlsConfig};
#[pyfunction] #[pyfunction]
pub fn pull_policy_exec_histories( pub fn pull_policy_exec_histories(
py: Python<'_>, py: Python<'_>,
@@ -11,14 +13,10 @@ pub fn pull_policy_exec_histories(
exec_types: String, exec_types: String,
days: i64, days: i64,
) -> Py<PyString> { ) -> Py<PyString> {
let headers: HeaderMap = match PyData::convert(py, &py_self, true) { println!();
ExtractedValues::Headers(h) => h, let data: PyData = PyData::extract_data(py, &py_self);
ExtractedValues::BaseUrl(_) => std::process::abort(), let headers: HeaderMap = data.headers;
}; let base_url: String = data.base_url;
let base_url: String = match PyData::convert(py, &py_self, false) {
ExtractedValues::Headers(_) => std::process::abort(),
ExtractedValues::BaseUrl(b) => b,
};
let handle: thread::JoinHandle<String> = std::thread::spawn(move || { let handle: thread::JoinHandle<String> = std::thread::spawn(move || {
let rt: tokio::runtime::Runtime = match tokio::runtime::Runtime::new() { let rt: tokio::runtime::Runtime = match tokio::runtime::Runtime::new() {
Ok(rt) => rt, Ok(rt) => rt,
@@ -27,10 +25,9 @@ pub fn pull_policy_exec_histories(
std::process::abort(); std::process::abort();
} }
}; };
rt.block_on(async { let tracer_provider = rt.block_on(async { init_tracer() });
let _ = init_tracer(); global::set_tracer_provider(tracer_provider.clone());
}); let tracer: global::BoxedTracer = global::tracer("tracer");
let tracer: global::BoxedTracer = global::tracer("global_tracer");
let _cx: Context = Context::new(); let _cx: Context = Context::new();
let file_path: PathBuf = format!( let file_path: PathBuf = format!(
"{}\\cache\\chunkinator.json", "{}\\cache\\chunkinator.json",
@@ -111,7 +108,8 @@ pub fn pull_policy_exec_histories(
} }
} }
}); });
let cutoff: chrono::NaiveDateTime = Local::now().naive_local() - Duration::days(days); let cutoff: chrono::NaiveDateTime =
Local::now().naive_local() - chrono::Duration::days(days);
let (tx, rx) = unbounded::<Vec<Group>>(); let (tx, rx) = unbounded::<Vec<Group>>();
let pb_clone = progress_bar.clone(); let pb_clone = progress_bar.clone();
thread::spawn(move || { thread::spawn(move || {
@@ -186,7 +184,10 @@ pub fn pull_policy_exec_histories(
.unwrap() .unwrap()
.enable_steady_tick(std::time::Duration::from_millis(100)); .enable_steady_tick(std::time::Duration::from_millis(100));
let span: opentelemetry::trace::SpanRef<'_> = cx.span(); let span: opentelemetry::trace::SpanRef<'_> = cx.span();
span.set_attribute(Key::new("Days").string(days.to_string())); //span.set_attribute(Key::new("Days").string(days.to_string()));
//span.set_attribute(Key::new("Days"));
//span.set_attribute(KeyValue::new("Policy Name", policy_names.clone()));
span.set_attribute(KeyValue::new("Days", days));
span.set_attribute(KeyValue::new("Policy Name", policy_names.clone())); span.set_attribute(KeyValue::new("Policy Name", policy_names.clone()));
loop { loop {
let execution_histories = tracer.in_span(checkpoint_number.to_string(), |cx| { let execution_histories = tracer.in_span(checkpoint_number.to_string(), |cx| {
@@ -242,8 +243,10 @@ pub fn pull_policy_exec_histories(
std::process::abort(); std::process::abort();
} }
}; };
tracer_provider
.shutdown()
.expect("Failed to Shutdown Tracer Provdier");
drop(tx); drop(tx);
shutdown_tracer_provider();
return_data.to_string() return_data.to_string()
}); });
let gil_value: String = handle.join().unwrap(); let gil_value: String = handle.join().unwrap();
@@ -310,29 +313,34 @@ pub fn get_base_directory() -> PathBuf {
.unwrap_or_else(|| home.join("AppData").join("Roaming")); .unwrap_or_else(|| home.join("AppData").join("Roaming"));
appdata.join("Loxide") appdata.join("Loxide")
} }
_ => home.join(".local").join("share").join("Loxide"), "linux" => home.join(".local").join("share").join("Loxide"),
_ => {
println!("{} is currently not compatible with LoxideLibs", os);
std::process::abort();
}
} }
} }
fn init_tracer() -> Result<Option<sdktrace::Tracer>, TraceError> { fn init_tracer() -> opentelemetry_sdk::trace::TracerProvider {
let cfg: TelemetryConfig = TelemetryConfig::load(); let cfg: TelemetryConfig = TelemetryConfig::load();
if !cfg.TELEMETRY { let endpoint = cfg.TELEM_URL.unwrap_or_default().clone();
global::set_tracer_provider(NoopTracerProvider::new()); let channel_endpoint = endpoint.clone();
return Ok(None); let channel = Channel::from_shared(channel_endpoint.clone())
} .unwrap()
let endpoint: String = cfg.TELEM_URL.unwrap_or_default(); .tls_config(ClientTlsConfig::new().with_native_roots())
let tracer: sdktrace::Tracer = .unwrap()
opentelemetry_otlp::new_pipeline() .connect_lazy();
.tracing() let exporter = opentelemetry_otlp::SpanExporter::builder()
.with_exporter( .with_tonic()
opentelemetry_otlp::new_exporter() .with_endpoint(endpoint.clone())
.tonic() .with_channel(channel)
.with_endpoint(endpoint), .build()
) .expect("Failed to build exporter");
.with_trace_config(sdktrace::config().with_resource(Resource::new(vec![ opentelemetry_sdk::trace::TracerProvider::builder()
KeyValue::new("service.name", "LoxideLibs"), .with_simple_exporter(exporter)
]))) .with_resource(Resource::new(vec![KeyValue::new(
.install_simple() "service.name",
.unwrap(); "LoxideLibs",
Ok(Some(tracer)) )]))
.build()
} }
+1 -1
View File
@@ -11,4 +11,4 @@ urllib3==2.5.0
pyperclip==1.11.0 pyperclip==1.11.0
--extra-index-url https://git.racooncity.org/api/packages/brotoskyj/pypi/simple/ --extra-index-url https://git.racooncity.org/api/packages/brotoskyj/pypi/simple/
airlock_libs==5.2.0 airlock_libs==6.0.0
+15 -15
View File
@@ -38,9 +38,9 @@ logger = logging.getLogger(__name__)
def devicehistory(api: AirlockAPIWrapper, outputjson: bool): def devicehistory(api: AirlockAPIWrapper, outputjson: bool):
agents = selectAgents(api) agents = selectAgents(api)
history_days = Selector.select_value( history_days = Selector.select_value(
prompt="Enter how many days of history to pull (1150): ", prompt="Enter how many days of history to pull (1–365): ",
value_type=int, value_type=int,
valid_range=(1, 150), valid_range=(1, 365),
) )
if not agents or not history_days: if not agents or not history_days:
@@ -60,7 +60,7 @@ def devicehistory(api: AirlockAPIWrapper, outputjson: bool):
except Exception as e: except Exception as e:
print( print(
colorText( colorText(
f" Error retrieving history for {agent.hostname}: {e}", "red" f"❌ Error retrieving history for {agent.hostname}: {e}", "red"
) )
) )
continue continue
@@ -139,7 +139,7 @@ def findAgents(api, return_dataframe):
print( print(
colorText( colorText(
f"\n Matched devices exported to: {working_dir}\\{filename}", f"\n✓ Matched devices exported to: {working_dir}\\{filename}",
"green", "green",
) )
) )
@@ -148,7 +148,7 @@ def findAgents(api, return_dataframe):
def collect_device_names() -> List[str]: def collect_device_names() -> List[str]:
print(colorText("🖥Â Device Search", "cyan")) print(colorText("🖥��Â Device Search", "cyan"))
print( print(
colorText( colorText(
"Enter the device hostnames you'd like to search for, one per line.", "cyan" "Enter the device hostnames you'd like to search for, one per line.", "cyan"
@@ -185,7 +185,7 @@ def collect_device_names() -> List[str]:
else: else:
print( print(
colorText( colorText(
f"⚠️ Invalid input: '{stripped_line}'  only letters, numbers, underscores, spaces, and hyphens are allowed.", f"⚠️ Invalid input: '{stripped_line}' — only letters, numbers, underscores, spaces, and hyphens are allowed.",
"yellow", "yellow",
) )
) )
@@ -235,8 +235,8 @@ def show_unmatched(
] ]
if unmatched: if unmatched:
logger.debug(f"⚠️ No matches for: {', '.join(unmatched)}") logger.debug(f"⚠️ No matches for: {', '.join(unmatched)}")
print(colorText(f"⚠️ No matches for: {', '.join(unmatched)}", "yellow")) print(colorText(f"⚠️ No matches for: {', '.join(unmatched)}", "yellow"))
def enrich_agents(agents: List["Agent"], policies: List["Policy"]): def enrich_agents(agents: List["Agent"], policies: List["Policy"]):
@@ -248,7 +248,7 @@ def selectAgents(api: "AirlockAPIWrapper") -> List["Agent"]:
device_names = collect_device_names() device_names = collect_device_names()
if not device_names: if not device_names:
logger.debug("No device names entered") logger.debug("No device names entered")
print(colorText("⚠️ No device names entered.", "red")) print(colorText("⚠️ No device names entered.", "red"))
return [] return []
use_exact = choose_match_type() use_exact = choose_match_type()
@@ -261,11 +261,11 @@ def selectAgents(api: "AirlockAPIWrapper") -> List["Agent"]:
show_unmatched(device_names, matched_agents, use_exact) show_unmatched(device_names, matched_agents, use_exact)
if not matched_agents: if not matched_agents:
logger.debug(" No matching devices found.") logger.debug("❌ No matching devices found.")
print(colorText(" No matching devices found.", "red")) print(colorText("❌ No matching devices found.", "red"))
return [] return []
print(colorText(f" Found {len(matched_agents)} matching device(s).", "green")) print(colorText(f"✓ Found {len(matched_agents)} matching device(s).", "green"))
logger.info("Matched agent hostnames:") logger.info("Matched agent hostnames:")
rows = (len(matched_agents) + 2) // 3 # 3 columns rows = (len(matched_agents) + 2) // 3 # 3 columns
for row in range(rows): for row in range(rows):
@@ -283,8 +283,8 @@ def selectAgents(api: "AirlockAPIWrapper") -> List["Agent"]:
) )
if not matched_agents: if not matched_agents:
logger.debug(" No matching devices remain after refinement.") logger.debug("❌ No matching devices remain after refinement.")
print(colorText(" No matching devices remain after refinement.", "red")) print(colorText("❌ No matching devices remain after refinement.", "red"))
return [] return []
enrich_agents(matched_agents, policies) enrich_agents(matched_agents, policies)
@@ -302,7 +302,7 @@ def moveAgentToRelatedPolicy(
Args: Args:
api: AirlockAPIWrapper instance. api: AirlockAPIWrapper instance.
agent: Agent object. agent: Agent object.
policy_relationship_map: Dict mapping enforcement â–€ –€™ audit. policy_relationship_map: Dict mapping enforcement â–€ –€™ audit.
mode: 'audit' to move to audit, 'enforcement' to move to enforcement. mode: 'audit' to move to audit, 'enforcement' to move to enforcement.
""" """
policy_relationship_map = get_system_json("POLICY_MAP_ENF_AUD", "{}") policy_relationship_map = get_system_json("POLICY_MAP_ENF_AUD", "{}")