[TSM.ID].[11031972] PXE : Platform X Ecosystem I [118 Module -LIVE-]
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
# [TSM.ID].[11031972] -- All Rights Reserved. Proprietary & Confidential.
|
||||
[package]
|
||||
name = "xcu-core"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["TSM.ID <tsm@tsm.id>"]
|
||||
description = "[TSM.ID].[11031972] XCU Core Engine - Platform X Foundation"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = "0.3"
|
||||
@@ -0,0 +1,79 @@
|
||||
// [TSM.ID].[11031972] — All Rights Reserved. Proprietary & Confidential.
|
||||
use axum::{
|
||||
extract::Request,
|
||||
middleware::Next,
|
||||
response::Response,
|
||||
http::StatusCode,
|
||||
};
|
||||
use jsonwebtoken::{decode, DecodingKey, Validation, Algorithm};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::warn;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct IamClaims {
|
||||
pub sub: String, // User/Tenant ID
|
||||
pub role: String, // "supreme_admin" or "tenant"
|
||||
pub packages: Vec<String>, // ["phase-1", "phase-72", "billing"]
|
||||
pub exp: usize,
|
||||
}
|
||||
|
||||
/// JWT Secret WAJIB dari environment variable — DILARANG HARDCODE
|
||||
/// Env: XCU_IAM_SECRET (harus sama dengan secret JUMPA.ID IAM)
|
||||
static IAM_SECRET: OnceLock<String> = OnceLock::new();
|
||||
|
||||
fn get_iam_secret() -> &'static str {
|
||||
IAM_SECRET.get_or_init(|| {
|
||||
std::env::var("XCU_IAM_SECRET").unwrap_or_else(|_| {
|
||||
warn!("[IAM] ⚠️ XCU_IAM_SECRET env var NOT SET! Using fallback. SET THIS IN PRODUCTION!");
|
||||
"XCU_IAM_SECRET_NOT_CONFIGURED".to_string()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn xcu_gatekeeper(
|
||||
mut req: Request,
|
||||
next: Next,
|
||||
) -> Result<Response, StatusCode> {
|
||||
// 1. Ekstrak Token dari Header atau Query Params (untuk SSE)
|
||||
let auth_header = req.headers().get("Authorization").and_then(|h| h.to_str().ok());
|
||||
|
||||
let token = if let Some(auth) = auth_header {
|
||||
if auth.starts_with("Bearer ") {
|
||||
Some(auth.trim_start_matches("Bearer "))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
// Fallback ke query param (misal untuk SSE)
|
||||
req.uri().query().and_then(|q| {
|
||||
q.split('&').find(|kv| kv.starts_with("token=")).map(|kv| kv.trim_start_matches("token="))
|
||||
})
|
||||
};
|
||||
|
||||
if let Some(t) = token {
|
||||
let validation = Validation::new(Algorithm::HS256);
|
||||
// validate_exp = true (default) — expired tokens WAJIB ditolak
|
||||
|
||||
match decode::<IamClaims>(
|
||||
t,
|
||||
&DecodingKey::from_secret(get_iam_secret().as_bytes()),
|
||||
&validation,
|
||||
) {
|
||||
Ok(token_data) => {
|
||||
// Token Sah! Masukkan Identitas Lintas-Dimensi ke dalam mesin.
|
||||
req.extensions_mut().insert(token_data.claims);
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("IAM Matrix Breach Detected: Invalid JWT Token. {:?}", e);
|
||||
return Err(StatusCode::UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TANPA TOKEN = REJECTED. Tidak ada guest bypass.
|
||||
warn!("[IAM] No token provided — ACCESS DENIED");
|
||||
return Err(StatusCode::UNAUTHORIZED);
|
||||
}
|
||||
|
||||
Ok(next.run(req).await)
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
//! [TSM.ID].[11031972] -- Platform X Ecosystem
|
||||
//! xcu-core -- XCU Core Engine Foundation
|
||||
//! Central orchestrator for the Platform X ecosystem
|
||||
#![deny(warnings)]
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CoreError {
|
||||
InitFailed(String),
|
||||
ModuleNotFound(String),
|
||||
ConfigError(String),
|
||||
RuntimeError(String),
|
||||
ShutdownError(String),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for CoreError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::InitFailed(e) => write!(f, "Init failed: {e}"),
|
||||
Self::ModuleNotFound(e) => write!(f, "Module not found: {e}"),
|
||||
Self::ConfigError(e) => write!(f, "Config error: {e}"),
|
||||
Self::RuntimeError(e) => write!(f, "Runtime error: {e}"),
|
||||
Self::ShutdownError(e) => write!(f, "Shutdown error: {e}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::error::Error for CoreError {}
|
||||
pub type Result<T> = std::result::Result<T, CoreError>;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CoreConfig {
|
||||
pub instance_id: String,
|
||||
pub modules: Vec<String>,
|
||||
pub params: HashMap<String, String>,
|
||||
pub max_workers: usize,
|
||||
}
|
||||
|
||||
impl Default for CoreConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
instance_id: "xcu-core-0".to_string(),
|
||||
modules: Vec::new(),
|
||||
params: HashMap::new(),
|
||||
max_workers: num_cpus(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn num_cpus() -> usize {
|
||||
std::thread::available_parallelism().map(|n| n.get()).unwrap_or(4)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CoreState { Booting, Ready, Running, Degraded, ShuttingDown, Stopped }
|
||||
|
||||
pub struct CoreEngine {
|
||||
config: CoreConfig,
|
||||
state: Arc<Mutex<CoreState>>,
|
||||
module_registry: Arc<Mutex<HashMap<String, ModuleInfo>>>,
|
||||
start_time: std::time::Instant,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ModuleInfo {
|
||||
pub name: String,
|
||||
pub version: String,
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
impl CoreEngine {
|
||||
pub fn new(config: CoreConfig) -> Result<Self> {
|
||||
Ok(Self {
|
||||
config,
|
||||
state: Arc::new(Mutex::new(CoreState::Booting)),
|
||||
module_registry: Arc::new(Mutex::new(HashMap::new())),
|
||||
start_time: std::time::Instant::now(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn init(&self) -> Result<()> {
|
||||
tracing::info!("XCU Core initializing: {}", self.config.instance_id);
|
||||
let mut s = self.state.lock().map_err(|e| CoreError::InitFailed(e.to_string()))?;
|
||||
*s = CoreState::Ready;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn start(&self) -> Result<()> {
|
||||
let mut s = self.state.lock().map_err(|e| CoreError::RuntimeError(e.to_string()))?;
|
||||
*s = CoreState::Running;
|
||||
tracing::info!("XCU Core running with {} workers", self.config.max_workers);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn shutdown(&self) -> Result<()> {
|
||||
let mut s = self.state.lock().map_err(|e| CoreError::ShutdownError(e.to_string()))?;
|
||||
*s = CoreState::ShuttingDown;
|
||||
tracing::info!("XCU Core shutting down gracefully");
|
||||
*s = CoreState::Stopped;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn register_module(&self, info: ModuleInfo) -> Result<()> {
|
||||
let mut reg = self.module_registry.lock().map_err(|e| CoreError::RuntimeError(e.to_string()))?;
|
||||
reg.insert(info.name.clone(), info);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn state(&self) -> Result<CoreState> {
|
||||
Ok(self.state.lock().map_err(|e| CoreError::RuntimeError(e.to_string()))?.clone())
|
||||
}
|
||||
|
||||
pub fn uptime_secs(&self) -> u64 { self.start_time.elapsed().as_secs() }
|
||||
pub fn module_count(&self) -> usize { self.module_registry.lock().map(|r| r.len()).unwrap_or(0) }
|
||||
pub fn config(&self) -> &CoreConfig { &self.config }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_core_lifecycle() {
|
||||
let engine = CoreEngine::new(CoreConfig::default()).unwrap();
|
||||
engine.init().unwrap();
|
||||
assert_eq!(engine.state().unwrap(), CoreState::Ready);
|
||||
engine.start().unwrap();
|
||||
assert_eq!(engine.state().unwrap(), CoreState::Running);
|
||||
engine.register_module(ModuleInfo {
|
||||
name: "test".into(), version: "0.1.0".into(), status: "ok".into()
|
||||
}).unwrap();
|
||||
assert_eq!(engine.module_count(), 1);
|
||||
engine.shutdown().unwrap();
|
||||
assert_eq!(engine.state().unwrap(), CoreState::Stopped);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user