Skip to main content

v0.15.0 Release Notes

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

Metricv0.14.0v0.15.0Improvement
Dangerous operation interception rate0%100%Full coverage
Guardian validation latencyN/A12μsMicrosecond level
Sandbox isolation strengthN/AHard isolationSystem level
Audit completenessPartialCompleteFull chain
False interception rateN/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

DimensionValidation ContentExample
Physical constraintsElectrical lawsDisconnect under load
Operating proceduresStandard processesOperation sequence
Equipment statusCurrent conditionsEquipment under maintenance
Permission boundariesRole permissionsUnauthorized operation
Timing validationTime windowOutside 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 LayerObjectMechanismStrength
NetworkTrafficNamespaceComplete isolation
StorageDataReplicaCopy-on-write
CPUComputecgroupSoft isolation
MemoryAddress spaceIndependent heapHard isolation
TwinGrid stateSnapshotComplete 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 IDDangerous OperationDefault ActionDescription
D001Disconnect under loadHard interceptPhysical constraint
D002Close ground switch under voltageHard interceptPhysical constraint
D003Mistrip running breakerSoft interceptRequires approval
D004Energize during maintenanceHard interceptStatus validation
D005Out-of-limit output adjustmentSoft interceptPhysical constraint
D006Separate from main gridSoft interceptRequires approval
D007Cross-tenant operationHard interceptPermission validation
D008Operation outside maintenance windowAlarmProcedure 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-constraint deeply 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-guardian policy evaluation race condition under high concurrency (#1507)
  • Fixed eneros-guardian-sandbox incomplete resource release on sandbox exit (#1513)
  • Fixed eneros-guardian-audit audit chain breakage after restart (#1519)
  • Fixed eneros-guardian-policy OPA integration evaluation timeout on large policy sets (#1525)

Breaking Changes

  • syscall(ExecuteCommand): All execution syscalls now pass through guardian validation; original direct execution migrated to syscall_unchecked
  • Command::execute: Return type changed from Result<()> to Result<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.”