EnerOS v0.27.0 Release Notes
Release Date: 2025-10-26 Codename: Comply Git Tag: v0.27.0 Support Status: Stable Total Crates: 71 (4 new) Test Cases: 9050+ (500+ new)
Overview
EnerOS v0.27.0 “Comply” is a compliance-framework-focused release that provides a compliance foundation for EnerOS deployment in the regulated power industry. The power industry is critical information infrastructure, and data processing and system operations are subject to strict legal and regulatory constraints: the EU’s General Data Protection Regulation (GDPR) governs personal data processing, China’s Personal Information Protection Law (PIPL) regulates the flow of personal information, and power regulators in various countries have explicit requirements for data retention and audit traceability. v0.27.0 builds compliance requirements into the kernel framework, making EnerOS compliant by design.
This release introduces five core capabilities: Compliance Framework, GDPR Compliance, PIPL Compliance, Data Retention Policy, and Audit Log. All data processing operations go through compliance policy validation, and all critical operations generate tamper-evident audit records.
In terms of design philosophy, v0.27.0 adheres to “compliance as code” — compliance requirements are defined as executable policies rather than relying on manual processes; “protection by default” — personal data is stored masked by default and requires explicit authorization to access plaintext; “tamper-evident” — audit logs use append-only writes with hash chain structure, making any tampering detectable.
Key Metrics
| Metric | Value | Description |
|---|---|---|
| Compliance policies | 120+ | Built-in policies |
| Audit log throughput | 80,000 entries/sec | Single node |
| Audit log verification | < 5ms | Single hash chain |
| Data masking types | 15 | Phone/ID/name, etc. |
| New Crates | 4 | Compliance-related |
| New tests | 500+ | Includes compliance tests |
New Features
1. Compliance Framework
Introduces the eneros-comply Crate, providing a unified compliance framework. Compliance policies are defined as rules, and all data processing operations go through the policy engine for validation.
Policy Definition
use eneros_comply::{ComplianceFramework, Policy, PolicyEngine};
let framework = ComplianceFramework::new()
.engine(PolicyEngine::strict())
.load_policies("policies/");
// Register policy
framework.register_policy(Policy::new("gdpr-art-6")
.rule(Rule::require_consent(
DataCategory::Personal,
Purpose::Marketing,
)))?;
framework.register_policy(Policy::new("pipl-art-13")
.rule(Rule::require_notice(
DataCategory::Personal,
Action::Collect,
)))?;
Compliance Validation
// Auto-validate before data processing
let action = DataAction::new()
.data(DataCategory::Personal)
.purpose(Purpose::Analytics)
.subject(user_id);
match framework.check(&action).await {
Ok(_) => process_data(action).await?,
Err(violations) => {
for v in violations {
log::error!("Compliance violation: {} - {}", v.policy, v.reason);
}
}
}
Compliance Standard Coverage
| Standard | Region | Main Requirements | Coverage |
|---|---|---|---|
| GDPR | EU | Personal data protection | Complete |
| PIPL | China | Personal information protection | Complete |
| CCPA | California | Consumer privacy | Partial |
| NERC CIP | North America | Power cybersecurity | Partial |
| MLPS 2.0 | China | Multi-Level Protection Scheme | Complete |
| ISO 27001 | Global | Information security | Partial |
2. GDPR Compliance
Introduces the eneros-comply-gdpr Crate, providing GDPR compliance capabilities. Covers data subject rights, lawful basis for data processing, data protection impact assessment, and other requirements.
Data Subject Rights
use eneros_comply_gdpr::{GdprEngine, SubjectRight};
let gdpr = GdprEngine::new(&framework);
// Right of access (Article 15)
let data = gdpr.handle_request(SubjectRight::Access {
subject_id: user_id,
}).await?;
// Returns a copy of all personal data for this user
// Right to erasure (Article 17)
gdpr.handle_request(SubjectRight::Erasure {
subject_id: user_id,
reason: "User initiated account deletion",
}).await?;
// Deletes all personal data, retaining legally required portions
// Right to data portability (Article 20)
let portable = gdpr.handle_request(SubjectRight::Portability {
subject_id: user_id,
format: ExportFormat::Json,
}).await?;
Consent Management
// Record user consent
gdpr.record_consent(Consent::new()
.subject(user_id)
.purpose(Purpose::LoadProfiling)
.lawful_basis(LawfulBasis::Consent)
.timestamp(now())
.expiry(Duration::days(365)))?;
// Auto-delete related data after consent withdrawal
gdpr.withdraw_consent(user_id, Purpose::LoadProfiling).await?;
GDPR Article Coverage
| Article | Requirement | Implementation |
|---|---|---|
| Art. 6 | Lawful basis | Consent management |
| Art. 7 | Consent conditions | Explicit consent records |
| Art. 15 | Right of access | Data export |
| Art. 17 | Right to erasure | Data erasure |
| Art. 20 | Right to portability | Structured export |
| Art. 25 | Privacy by design | Default masking |
| Art. 30 | Records of processing | Processing logs |
| Art. 33 | Data breach notification | Notification mechanism |
3. PIPL Compliance
Introduces the eneros-comply-pipl Crate, providing compliance capabilities for China’s Personal Information Protection Law.
Personal Information Classification
use eneros_comply_pipl::{PiplEngine, InfoCategory};
let pipl = PiplEngine::new(&framework);
// Data classification
let category = pipl.classify(&data)?;
match category {
InfoCategory::General => { /* General personal information */ }
InfoCategory::Sensitive => {
// Sensitive personal information (ID, biometrics, etc.)
// Requires separate consent
pipl.require_separate_consent(&data)?;
}
InfoCategory::NonPersonal => { /* Non-personal information */ }
}
Cross-border Transfer
// Personal information outbound compliance
let transfer = CrossBorderTransfer::new()
.data(&personal_data)
.destination("US")
.purpose("Technical support");
match pipl.check_cross_border(transfer).await {
Ok(approval) => {
// Passed security assessment or obtained certification
pipl.execute_transfer(approval).await?;
}
Err(reason) => {
log::warn!("Cross-border transfer rejected: {}", reason);
}
}
PIPL Article Coverage
| Article | Requirement | Implementation |
|---|---|---|
| Art. 13 | Processing basis | Lawful basis |
| Art. 17 | Notification obligation | Privacy notice |
| Art. 28 | Sensitive information | Separate consent |
| Art. 38 | Cross-border transfer | Security assessment |
| Art. 47 | Retention period | Retention policy |
4. Data Retention Policy
Introduces the eneros-comply-retention Crate, providing data retention policy management. Different types of data have different legal retention periods; expired data is automatically archived or deleted.
Retention Policy
use eneros_comply_retention::{RetentionEngine, RetentionPolicy};
let engine = RetentionEngine::new()
.policy(RetentionPolicy::new("scada-data")
.category(DataCategory::Operational)
.retain_for(Duration::years(2))
.action_after(RetentionAction::Archive))
.policy(RetentionPolicy::new("audit-log")
.category(DataCategory::Audit)
.retain_for(Duration::years(6)) // MLPS 2.0 requirement
.action_after(RetentionAction::Keep))
.policy(RetentionPolicy::new("user-personal")
.category(DataCategory::Personal)
.retain_for(Duration::years(1))
.action_after(RetentionAction::Delete)));
// Auto-execute retention policy
engine.schedule_daily().await?;
Data Lifecycle
// Mark data lifecycle
let data = DataRecord::new("load-profile-2025")
.category(DataCategory::Operational)
.created_at(now())
.retention(Duration::years(2));
engine.track(data).await?;
// Query data status
let status = engine.status("load-profile-2025").await?;
match status {
LifecycleStatus::Active => { /* Normal use */ }
LifecycleStatus::Archived => { /* Archived */ }
LifecycleStatus::PendingDeletion => { /* Pending deletion */ }
}
Retention Period Table
| Data Type | Retention Period | Basis | Expiry Action |
|---|---|---|---|
| SCADA telemetry | 2 years | Industry standard | Archive |
| Alarm records | 3 years | MLPS 2.0 | Archive |
| Audit logs | 6 years | MLPS 2.0 | Keep |
| Operation tickets | 5 years | Power regulations | Archive |
| Personal information | 1 year | PIPL | Delete |
| Fault recording | 1 year | Industry standard | Delete |
5. Audit Log
Introduces the eneros-comply-audit Crate, providing tamper-evident audit logs. Uses a hash chain structure, making any tampering detectable.
Audit Records
use eneros_comply_audit::{AuditLog, AuditEvent};
let audit = AuditLog::new("audit.log")
.hash_chain(HashChain::Sha256)
.rotation(Rotation::daily());
// Record audit event
audit.record(AuditEvent::new()
.actor(Actor::Agent("dispatch-1"))
.action(Action::Execute(Command::OpenSwitch { id: 42 }))
.resource(Resource::Switch(42))
.result(Result::Success)
.timestamp(now())
.ip("10.0.1.5")).await?;
Log Verification
// Verify log integrity
let verification = audit.verify_chain(
Range::from("2025-10-01").to("2025-10-26"),
).await?;
if verification.tampered_records.is_empty() {
println!("Audit log intact, no tampering");
} else {
for r in verification.tampered_records {
println!("Tampered record: {} expected hash {} actual {}",
r.id, r.expected_hash, r.actual_hash);
}
}
Audit Event Types
| Event Type | Description | Recorded Content |
|---|---|---|
| Authentication event | Login/logout | User, IP, time |
| Authorization event | Permission change | Subject, permission, operator |
| Operation event | System operation | Command, parameters, result |
| Data event | Data access | Data, operation, subject |
| Configuration event | Configuration change | Old value, new value, operator |
Improvements
- Audit Performance: Audit log writes changed from synchronous to batch async, throughput improved 5x
- Policy Cache: Compliance policy validation results cached by fingerprint; repeated validation reduced from 2ms to 0.1ms
- Masking Algorithm: Added Format-Preserving Encryption (FPE) to maintain format after masking
- Audit Query: Supports SQL-style audit log queries for compliance report generation
Bug Fixes
- Fixed
eneros-comply-gdprnot cascading cleanup of timeseries data during data deletion (#2708) - Fixed
eneros-comply-piplsensitive information classification missing biometrics (#2713) - Fixed
eneros-comply-retentionretention period calculation error across years (#2718) - Fixed
eneros-comply-audithash chain breakage during log rotation (#2723)
Breaking Changes
DataAction::new: Added requiredpurpose: PurposefieldAuditEvent: Fielduserrenamed toactorto support broader subject types
Upgrade Guide
- Run
cargo update -p eneros-comply - Add
purposefield to allDataActioncalls - Update
AuditEvent.userfield access toactor - Refer to
docs/migration/v0.27.0.mdfor detailed migration steps