use serde_json::Value;
use sha2::{Digest, Sha256};
use std::fs;
use std::path::Path;
pub fn get_ram_gb() -> f64 {
use sysinfo::System;
let sys = System::new_all();
sys.total_memory() as f64 / 1024.0 / 1024.0 / 1024.0
}
fn which(name: &str) -> bool {
if let Ok(path) = std::env::var("PATH") {
for p in std::env::split_paths(&path) {
let exe_path = p.join(name);
#[cfg(target_os = "windows")]
{
if exe_path.with_extension("exe").exists() || exe_path.exists() {
return true;
}
}
#[cfg(not(target_os = "windows"))]
{
if exe_path.exists() {
return true;
}
}
}
}
false
}
pub fn detect_gpu() -> bool {
which("nvidia-smi")
}
pub fn calculate_tenant_cid(kyc_json: &str) -> Result<(String, String), String> {
let val: Value = serde_json::from_str(kyc_json).map_err(|e| e.to_string())?;
let map = val
.as_object()
.ok_or_else(|| "KYC must be a JSON object".to_string())?;
let canonical = serde_json::to_string(map).map_err(|e| e.to_string())?;
let mut hasher = Sha256::new();
hasher.update(canonical.as_bytes());
let hash = format!("{:x}", hasher.finalize());
Ok((canonical, hash))
}
pub fn generate_egress_rules(
target_path: &Path,
selected_categories: &[String],
) -> Result<(), String> {
let mut category_domains = std::collections::HashMap::new();
category_domains.insert(
"registries",
vec![
"ghcr.io",
"pkg-containers.githubusercontent.com",
"registry-1.docker.io",
"auth.docker.io",
"index.docker.io",
"production.cloudflare.docker.com",
],
);
category_domains.insert(
"huggingface",
vec![
"huggingface.co",
"cdn-lfs.hf.co",
"cdn-lfs-us-1.hf.co",
"cdn-lfs-eu-1.hf.co",
"cas-bridge.xethub.hf.co",
],
);
category_domains.insert(
"oidc",
vec!["login.microsoftonline.com", "accounts.google.com"],
);
category_domains.insert(
"cognitive",
vec![
"api.openai.com",
"api.anthropic.com",
"us-central1-aiplatform.googleapis.com",
"bedrock.us-east-1.amazonaws.com",
"bedrock.us-west-2.amazonaws.com",
],
);
let mut allowed_domains = Vec::new();
for cat in selected_categories {
if let Some(domains) = category_domains.get(cat.as_str()) {
allowed_domains.extend(domains.iter().map(|d| d.to_string()));
}
}
let rules_file = target_path.join("egress-whitelist.rules");
let mut rules_content = String::from(
"# CoReason Enterprise Outbound Firewall Rules (FQDN Whitelist)\n\
# Hand this file to your network/firewall security administrator.\n\n",
);
for domain in &allowed_domains {
rules_content.push_str(domain);
rules_content.push('\n');
}
fs::write(&rules_file, rules_content).map_err(|e| e.to_string())?;
let squid_file = target_path.join("egress-whitelist.squid.conf");
let mut squid_lines = vec![
"# Squid Proxy Whitelist Configuration for CoReason Sandbox Egress".to_string(),
"acl SSL_ports port 443".to_string(),
"acl Safe_ports port 80".to_string(),
"acl Safe_ports port 443".to_string(),
"acl CONNECT method CONNECT".to_string(),
"".to_string(),
"http_access deny !Safe_ports".to_string(),
"http_access deny CONNECT !SSL_ports".to_string(),
"http_access allow localhost manager".to_string(),
"http_access deny manager".to_string(),
"".to_string(),
"# Allow local traffic within docker bridge network".to_string(),
"acl localnet src 10.0.0.0/8".to_string(),
"acl localnet src 172.16.0.0/12".to_string(),
"acl localnet src 192.168.0.0/16".to_string(),
"http_access allow localhost".to_string(),
"http_access allow localnet".to_string(),
"".to_string(),
"# Whitelisted destination domains".to_string(),
];
for domain in &allowed_domains {
squid_lines.push(format!("acl allowed_domains dstdomain {}", domain));
if !domain.starts_with('.') && domain != "pkg-containers.githubusercontent.com" {
squid_lines.push(format!("acl allowed_domains dstdomain .{}", domain));
}
}
squid_lines.push("http_access allow allowed_domains".to_string());
squid_lines.push("http_access deny all".to_string());
squid_lines.push("http_port 3128".to_string());
squid_lines.push("coredump_dir /var/spool/squid".to_string());
squid_lines.push("refresh_pattern ^ftp: 1440 20% 10080".to_string());
squid_lines.push("refresh_pattern ^gopher: 1440 0% 1440".to_string());
squid_lines.push("refresh_pattern -i (/cgi-bin/|\\?) 0 0% 0".to_string());
squid_lines.push("refresh_pattern . 0 20% 4320".to_string());
squid_lines.push("".to_string());
fs::write(&squid_file, squid_lines.join("\n")).map_err(|e| e.to_string())?;
Ok(())
}