EnerOS v0.15.0
Release Date: February 16, 2025 Codename: Guardian Git Tag: v0.15.0 Support Status: Stable Total Crates: 38 (4 new) Test Cases: 5240+ (560 new)
Version Overview
EnerOS v0.15.0 “Guardian” is the core release for EnerOS in the “Operational Safety” direction. The primary goal is to introduce a Safety Guard System, providing multi-layer protection for dangerous operations in power systems, including operation sandboxing, permission auditing, dangerous operation interception, and a security policy engine—ensuring that any operation that may affect the physical safety of the grid undergoes strict validation before execution.
Power systems are typical “high-risk environments”—a single incorrect switch operation may cause equipment damage, grid separation, or even casualties. The permission model of traditional operating systems can only control “whether an operation can be executed” but cannot judge “whether execution is safe.” For example, a dispatcher with switch operation permission might open a disconnector under load, causing a “disconnect under load” accident. v0.15.0 embeds physical safety rules as the “guardian layer” of the operating system, performing physical feasibility validation before all operations, eliminating electrical misoperations at the source.
This version introduces four new crates: eneros-guardian (guardian core), eneros-guardian-sandbox (operation sandbox), eneros-guardian-audit (permission audit), and eneros-guardian-policy (security policy engine). The design philosophy is “safety first over functionality”—when the guardian determines an operation is dangerous, it will be intercepted and recorded regardless of the operator’s permission level, requiring a safety approval process before execution.
Key Metrics
| Metric | v0.14.0 | v0.15.0 | Improvement |
|---|---|---|---|
| Dangerous operation interception rate | 0% | 100% | Full coverage |
| Guardian validation latency | N/A | 12μs | Microsecond level |
| Sandbox isolation strength | N/A | Hard isolation | System level |
| Audit completeness | Partial | Complete | Full chain |
| False interception rate | N/A | < 0.01% | Extremely low |
New Features
1. Safety Guard System
Introduced the eneros-guardian crate as a unified interception layer for all dangerous operations. The guardian sits on the kernel syscall path—any ExecuteCommand syscall must pass guardian validation before execution. Validation covers multiple dimensions including physical constraints, operating procedures, equipment status, and operation sequence.
Guardian Architecture
use eneros_guardian::{Guardian, GuardianConfig, SafetyLevel};
let guardian = Guardian::new(GuardianConfig {
safety_level: SafetyLevel::Strict,
enable_sandbox: true,
enable_audit: true,
policy_engine: PolicyEngine::default(),
intercept_on_violation: true,
require_approval_for: SafetyLevel::Critical,
})?;
// Guardian automatically injected into syscall path
ctx.install_guardian(guardian).await?;
Guardian Validation Flow
// Agent initiates switch operation
let cmd = Command::OpenSwitch { id: 42 };
match ctx.guardian().check(&cmd).await {
Ok(SafetyReport::Safe) => {
// Validation passed, execute operation
ctx.syscall(ExecuteCommand(cmd)).await?;
}
Ok(SafetyReport::Warning(reason)) => {
// Risk warning, requires secondary confirmation
log::warn!("Operation risk: {}", reason);
ctx.require_confirmation().await?;
}
Err(InterceptError::Dangerous(violations)) => {
// Dangerous operation intercepted
log::error!("Operation intercepted: {:?}", violations);
ctx.audit().record_intercept(cmd, violations).await?;
}
}
Guardian Validation Dimensions
| Dimension | Validation Content | Example |
|---|---|---|
| Physical constraints | Electrical laws | Disconnect under load |
| Operating procedures | Standard processes | Operation sequence |
| Equipment status | Current conditions | Equipment under maintenance |
| Permission boundaries | Role permissions | Unauthorized operation |
| Timing validation | Time window | Outside maintenance window |
2. Operation Sandbox
Introduced the eneros-guardian-sandbox crate, providing an isolated execution environment for high-risk operations. Operations in the sandbox are rehearsed on a virtual grid (based on digital twin) before being applied to the real grid. The sandbox uses namespace isolation + resource limits to ensure sandboxed operations do not affect other workloads.
Sandbox Execution
use eneros_guardian_sandbox::{Sandbox, SandboxConfig};
// Create an operation sandbox
let sandbox = Sandbox::new(SandboxConfig {
twin_snapshot: twin.snapshot().await?,
resource_limits: ResourceLimits {
cpu: 2,
memory: 4 * 1024 * 1024 * 1024,
max_duration: Duration::minutes(5),
},
network_isolation: true,
rollback_on_exit: true,
})?;
// Rehearse operation in sandbox
let result = sandbox.run(async {
let cmd = Command::OpenSwitch { id: 42 };
ctx.syscall(ExecuteCommand(cmd)).await?;
// Observe rehearsal results
let state = ctx.twin().current_state()?;
Ok(state)
}).await?;
// Validate rehearsal results
if result.is_safe() {
// Rehearsal safe, execute in real environment
ctx.syscall(ExecuteCommand(cmd)).await?;
}
Sandbox Isolation Layers
| Isolation Layer | Object | Mechanism | Strength |
|---|---|---|---|
| Network | Traffic | Namespace | Complete isolation |
| Storage | Data | Replica | Copy-on-write |
| CPU | Compute | cgroup | Soft isolation |
| Memory | Address space | Independent heap | Hard isolation |
| Twin | Grid state | Snapshot | Complete isolation |
3. Permission Audit
Introduced the eneros-guardian-audit crate, providing full-chain audit recording for all operations, including operator, operation content, operation time, validation results, and execution results. Audit logs use append-only writes + signature chains, making them tamper-proof, satisfying NERC CIP, IEC 62443, and other compliance requirements.
Audit Recording
use eneros_guardian_audit::{AuditLog, AuditEntry};
let audit = AuditLog::new(AuditConfig {
storage: AuditStorage::append_only("/var/eneros/audit"),
hash_chain: HashChain::sha256(),
retention: Duration::days(365),
real_time_sync: true,
})?;
// Audit automatically records all operations
audit.record(AuditEntry {
timestamp: now(),
operator: ctx.user().id,
tenant: ctx.tenant(),
action: "open_switch",
target: "switch-42",
pre_check: SafetyReport::Safe,
execution: ExecutionResult::Success,
duration: Duration::milliseconds(120),
}).await?;
Audit Query
// Query operation history for a device
let history = audit.query()
.target("switch-42")
.range(now() - Duration::days(30), now())
.execute()?;
// Query intercepted operations
let intercepted = audit.query()
.filter(|e| e.pre_check.is_intercepted())
.range(now() - Duration::days(7), now())
.execute()?;
// Generate compliance report
let report = audit.compliance_report(Standard::NercCip)
.period(Q1_2025)
.generate()?;
4. Dangerous Operation Interception
The guardian system has a built-in knowledge base of dangerous operations for the power industry, automatically identifying and intercepting typical dangerous operations. Interception rules can be configured as hard intercept (reject execution), soft intercept (requires approval), or alarm (record but allow).
Built-in Dangerous Operation Rules
| Rule ID | Dangerous Operation | Default Action | Description |
|---|---|---|---|
| D001 | Disconnect under load | Hard intercept | Physical constraint |
| D002 | Close ground switch under voltage | Hard intercept | Physical constraint |
| D003 | Mistrip running breaker | Soft intercept | Requires approval |
| D004 | Energize during maintenance | Hard intercept | Status validation |
| D005 | Out-of-limit output adjustment | Soft intercept | Physical constraint |
| D006 | Separate from main grid | Soft intercept | Requires approval |
| D007 | Cross-tenant operation | Hard intercept | Permission validation |
| D008 | Operation outside maintenance window | Alarm | Procedure validation |
Custom Interception Rules
use eneros_guardian::{Interceptor, Rule, Action};
let interceptor = Interceptor::new()
.rule(Rule::new("D009")
.name("Low-frequency load shedding without confirmation")
.condition(|ctx, cmd| {
cmd.is_low_frequency_load_shed()
&& !ctx.confirmed()
})
.action(Action::SoftIntercept)
.message("Low-frequency load shedding requires confirmation of load conditions"))
.rule(Rule::new("D010")
.name("Main transformer overload timeout")
.condition(|ctx, cmd| {
let transformer = ctx.twin().transformer(cmd.target)?;
transformer.loading > 1.2 && transformer.overload_duration > Duration::minutes(30)
})
.action(Action::HardIntercept)
.message("Main transformer overloaded for over 30 minutes, further load increase prohibited"));
guardian.register_interceptor(interceptor)?;
5. Security Policy Engine
Introduced the eneros-guardian-policy crate, providing a configurable security policy engine supporting both OPA (Open Policy Agent) Rego policies and a built-in DSL. Policies can be flexibly configured by tenant, role, equipment type, and other dimensions.
Policy Definition
use eneros_guardian_policy::{PolicyEngine, Policy, Effect};
let engine = PolicyEngine::new();
// Define a policy: prohibit critical operations during non-business hours
engine.add_policy(Policy::new("non-business-hour-restrict")
.description("Restrict critical operations during non-business hours")
.match_|p| {
p.action.in_(&["open_switch", "close_switch", "adjust_generation"])
&& p.target.is_critical()
}
.condition(|ctx| {
!ctx.time().is_business_hour() && !ctx.user().has_role("emergency_operator")
})
.effect(Effect::Deny)
.message("Critical operations prohibited during non-business hours; contact duty dispatcher if needed"))?;
// Define a policy: prohibit energizing equipment under maintenance
engine.add_policy(Policy::new("maintenance-no-energize")
.match_|p| p.action == "energize"
.condition(|ctx, p| {
ctx.twin().equipment(p.target)?.status == EquipmentStatus::Maintenance
})
.effect(Effect::Deny)
.message("Equipment under maintenance, energization prohibited"))?;
Rego Policy Integration
use eneros_guardian_policy::opa;
// Load Rego policy
let rego = r#"
package eneros.guardian
default allow = false
allow {
input.action == "read"
input.user.role == "operator"
}
allow {
input.action == "dispatch"
input.user.role == "dispatcher"
input.target.is_critical == false
time.is_business_hour(input.timestamp)
}
"#;
engine.load_rego("dispatcher-policy", rego)?;
// Policy evaluation
let decision = engine.evaluate(DecisionRequest {
action: "dispatch",
user: ctx.user(),
target: &target,
timestamp: now(),
}).await?;
match decision.effect {
Effect::Allow => { /* Allow */ }
Effect::Deny => { /* Deny */ }
Effect::Audit => { /* Record */ }
}
Improvements
- Constraint Engine:
eneros-constraintdeeply integrated with guardian system, physical constraint validation automatically included in guardian flow - Digital Twin: Twin supports fast snapshots, sandbox rehearsal overhead reduced by 80%
- API Gateway: All write operation APIs automatically pass through guardian validation
- Observability: New guardian metrics exposed, including interception rate, validation latency, and rule hit rate
Bug Fixes
- Fixed
eneros-guardianpolicy evaluation race condition under high concurrency (#1507) - Fixed
eneros-guardian-sandboxincomplete resource release on sandbox exit (#1513) - Fixed
eneros-guardian-auditaudit chain breakage after restart (#1519) - Fixed
eneros-guardian-policyOPA integration evaluation timeout on large policy sets (#1525)
Breaking Changes
syscall(ExecuteCommand): All execution syscalls now pass through guardian validation; original direct execution migrated tosyscall_uncheckedCommand::execute: Return type changed fromResult<()>toResult<ExecutionReport>AuditLog::record: Changed to async, requires.await
Performance Improvements
- Guardian validation latency stable within 12μs
- Sandbox rehearsal overhead reduced from 800ms to 160ms (5x improvement)
- Audit log write throughput increased from 20K/s to 150K/s
- Policy evaluation latency reduced from 2ms to 200μs
Contributors
This version was jointly completed by 23 contributors with 398 commits. Special thanks to:
- @guardian-core: Guardian core and interception mechanism
- @sandbox-arch: Operation sandbox and isolation design
- @audit-chain: Audit log and hash chain
- @policy-engine: Policy engine and OPA integration
Upgrade Guide
Upgrading from v0.14.0
1. Update Dependencies
# Cargo.toml
[dependencies]
eneros-guardian = { version = "0.15" }
eneros-guardian-sandbox = { version = "0.15" }
eneros-guardian-audit = { version = "0.15" }
eneros-guardian-policy = { version = "0.15", features = ["opa"] }
2. Enable Guardian System
# eneros.toml
[guardian]
enabled = true
safety_level = "strict"
enable_sandbox = true
enable_audit = true
[guardian.audit]
storage = "/var/eneros/audit"
retention_days = 365
hash_chain = "sha256"
3. Adapt Syscall Changes
// v0.14.0 old approach: direct execution
ctx.syscall(ExecuteCommand(cmd)).await?;
// v0.15.0 new approach: through guardian validation (default behavior)
let report = ctx.syscall(ExecuteCommand(cmd)).await?;
if report.intercepted {
return Err(report.violations);
}
// To skip guardian (not recommended, requires privilege)
ctx.syscall_unchecked(ExecuteCommand(cmd)).await?;
4. Configure Dangerous Operation Rules
Recommend customizing dangerous operation interception rules based on your grid’s actual conditions:
use eneros_guardian::{Interceptor, Rule, Action};
let interceptor = Interceptor::new()
.rule(Rule::new("custom-001")
.name("Grid-specific dangerous operation")
.condition(|ctx, cmd| { /* ... */ })
.action(Action::HardIntercept));
guardian.register_interceptor(interceptor)?;
5. Audit Compliance Configuration
To meet NERC CIP or IEC 62443 compliance requirements, refer to the compliance manual to configure audit storage and retention policies, ensuring audit logs meet the three requirements of “tamper-proof, long-term retention, and traceable.”