Rustelo/docs/architecture/framework-integrity-protection.md

706 lines
23 KiB
Markdown
Raw Normal View History

2026-02-08 20:12:31 +00:00
# Framework Integrity Protection System
## 🛡️ Overview
The Framework Integrity Protection System ensures that Rustelo implementations remain updateable and don't become unmaintainable forks. This system provides mechanisms to:
- **Validate implementation compliance** with framework architecture
- **Detect unsafe modifications** that break update compatibility
- **Guide safe customization** through approved extension points
- **Automate integrity checks** during development and deployment
- **Provide migration assistance** when framework updates require changes
## 🏗️ Architecture Principles
### 1. Clear Boundaries
```
Framework Core (Protected) │ Implementation Space (Customizable)
├── Core traits and interfaces │ ├── Trait implementations
├── Template system │ ├── Custom components
├── Routing engine │ ├── Content and styling
├── Build system │ ├── Configuration overrides
└── Update mechanisms │ └── Feature integrations
```
### 2. Extension Points
Framework provides safe extension points where implementations can customize behavior without breaking updates:
- **Trait implementations**: Custom logic through trait system
- **Component overrides**: UI components via layered override system
- **Configuration layers**: Settings via layered configuration
- **Feature additions**: Modular features that compose cleanly
- **Content and styling**: Complete customization of presentation
### 3. Forbidden Modifications
The system prevents modifications that break update compatibility:
- ❌ Direct framework core modifications
- ❌ Hardcoded routes or paths bypassing configuration system
- ❌ Breaking trait contracts or interfaces
- ❌ Circumventing security or safety mechanisms
- ❌ Modifying shared build or update infrastructure
## 🔍 Integrity Validation System
### Core Validator Implementation
```rust
// crates/foundation/crates/core-lib/src/integrity.rs
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use std::path::{Path, PathBuf};
/// Framework integrity validator
#[derive(Debug)]
pub struct IntegrityValidator {
framework_manifest: FrameworkManifest,
implementation_root: PathBuf,
validation_rules: Vec<ValidationRule>,
}
/// Framework manifest defining protected boundaries
#[derive(Debug, Serialize, Deserialize)]
pub struct FrameworkManifest {
pub version: String,
pub protected_paths: Vec<String>,
pub required_traits: Vec<TraitRequirement>,
pub extension_points: Vec<ExtensionPoint>,
pub forbidden_patterns: Vec<ForbiddenPattern>,
pub update_compatibility: CompatibilityInfo,
}
/// Trait requirement for implementations
#[derive(Debug, Serialize, Deserialize)]
pub struct TraitRequirement {
pub trait_name: String,
pub required_methods: Vec<String>,
pub implementation_path: String,
pub compatibility_version: String,
}
/// Safe extension point definition
#[derive(Debug, Serialize, Deserialize)]
pub struct ExtensionPoint {
pub name: String,
pub location: String,
pub allowed_modifications: Vec<String>,
pub validation_schema: Option<String>,
pub examples: Vec<String>,
}
/// Pattern that breaks framework compatibility
#[derive(Debug, Serialize, Deserialize)]
pub struct ForbiddenPattern {
pub pattern: String,
pub reason: String,
pub suggested_alternative: String,
pub severity: ViolationSeverity,
}
/// Integrity validation result
#[derive(Debug)]
pub struct ValidationResult {
pub passed: bool,
pub violations: Vec<IntegrityViolation>,
pub warnings: Vec<IntegrityWarning>,
pub suggestions: Vec<ImprovementSuggestion>,
pub compatibility_score: f32,
}
/// Integrity violation details
#[derive(Debug, Serialize, Deserialize)]
pub struct IntegrityViolation {
pub severity: ViolationSeverity,
pub category: ViolationCategory,
pub description: String,
pub file_path: String,
pub line_number: Option<usize>,
pub suggested_fix: String,
pub breaking_change: bool,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum ViolationSeverity {
Critical, // Breaks updates completely
High, // May break future updates
Medium, // Best practice violation
Low, // Style or performance issue
}
#[derive(Debug, Serialize, Deserialize)]
pub enum ViolationCategory {
CoreModification, // Direct framework modification
TraitViolation, // Trait contract broken
ConfigurationBypass, // Hardcoded values bypassing config
SecurityBreach, // Security mechanism bypassed
ArchitecturalViolation, // Violates framework architecture
DeprecatedUsage, // Uses deprecated APIs
}
impl IntegrityValidator {
/// Create new validator with framework manifest
pub fn new(framework_root: &Path, implementation_root: &Path) -> Result<Self, IntegrityError> {
let manifest_path = framework_root.join("FRAMEWORK_MANIFEST.toml");
let framework_manifest = Self::load_manifest(&manifest_path)?;
let validation_rules = Self::build_validation_rules(&framework_manifest)?;
Ok(Self {
framework_manifest,
implementation_root: implementation_root.to_path_buf(),
validation_rules,
})
}
/// Run full integrity validation
pub fn validate(&self) -> Result<ValidationResult, IntegrityError> {
let mut violations = Vec::new();
let mut warnings = Vec::new();
let mut suggestions = Vec::new();
// Check protected paths
violations.extend(self.check_protected_paths()?);
// Validate trait implementations
violations.extend(self.validate_trait_implementations()?);
// Check for forbidden patterns
violations.extend(self.scan_forbidden_patterns()?);
// Validate configuration usage
violations.extend(self.validate_configuration_usage()?);
// Check extension point usage
violations.extend(self.validate_extension_points()?);
// Generate improvement suggestions
suggestions.extend(self.generate_suggestions(&violations)?);
let compatibility_score = self.calculate_compatibility_score(&violations);
let passed = violations.iter().all(|v| !matches!(v.severity, ViolationSeverity::Critical));
Ok(ValidationResult {
passed,
violations,
warnings,
suggestions,
compatibility_score,
})
}
/// Check if protected framework paths are modified
fn check_protected_paths(&self) -> Result<Vec<IntegrityViolation>, IntegrityError> {
let mut violations = Vec::new();
for protected_path in &self.framework_manifest.protected_paths {
let full_path = self.implementation_root.join(protected_path);
if full_path.exists() {
// Check if this is a legitimate override vs unauthorized modification
if !self.is_authorized_override(&full_path)? {
violations.push(IntegrityViolation {
severity: ViolationSeverity::Critical,
category: ViolationCategory::CoreModification,
description: format!("Unauthorized modification of protected framework path: {}", protected_path),
file_path: full_path.to_string_lossy().to_string(),
line_number: None,
suggested_fix: format!("Remove modifications to {} and use appropriate extension points", protected_path),
breaking_change: true,
});
}
}
}
Ok(violations)
}
/// Validate trait implementation compliance
fn validate_trait_implementations(&self) -> Result<Vec<IntegrityViolation>, IntegrityError> {
let mut violations = Vec::new();
for trait_req in &self.framework_manifest.required_traits {
let impl_path = self.implementation_root.join(&trait_req.implementation_path);
if !impl_path.exists() {
violations.push(IntegrityViolation {
severity: ViolationSeverity::High,
category: ViolationCategory::TraitViolation,
description: format!("Missing required trait implementation: {}", trait_req.trait_name),
file_path: impl_path.to_string_lossy().to_string(),
line_number: None,
suggested_fix: format!("Implement required trait {} at {}", trait_req.trait_name, trait_req.implementation_path),
breaking_change: true,
});
continue;
}
// Validate trait implementation completeness
let impl_content = std::fs::read_to_string(&impl_path)?;
violations.extend(self.validate_trait_methods(&impl_content, trait_req)?);
}
Ok(violations)
}
/// Scan for forbidden patterns that break compatibility
fn scan_forbidden_patterns(&self) -> Result<Vec<IntegrityViolation>, IntegrityError> {
let mut violations = Vec::new();
for forbidden in &self.framework_manifest.forbidden_patterns {
let pattern_violations = self.scan_pattern(&forbidden.pattern, &forbidden.reason, &forbidden.suggested_alternative, forbidden.severity)?;
violations.extend(pattern_violations);
}
Ok(violations)
}
/// Calculate compatibility score (0.0 = incompatible, 1.0 = fully compatible)
fn calculate_compatibility_score(&self, violations: &[IntegrityViolation]) -> f32 {
if violations.is_empty() {
return 1.0;
}
let total_severity_score: f32 = violations.iter()
.map(|v| match v.severity {
ViolationSeverity::Critical => 10.0,
ViolationSeverity::High => 5.0,
ViolationSeverity::Medium => 2.0,
ViolationSeverity::Low => 0.5,
})
.sum();
let max_possible_score = 100.0; // Arbitrary baseline
(max_possible_score - total_severity_score).max(0.0) / max_possible_score
}
}
/// Integrity error types
#[derive(Debug, thiserror::Error)]
pub enum IntegrityError {
#[error("Framework manifest not found or invalid: {0}")]
InvalidManifest(String),
#[error("IO error during validation: {0}")]
IoError(#[from] std::io::Error),
#[error("Parsing error: {0}")]
ParseError(String),
#[error("Configuration error: {0}")]
ConfigurationError(String),
}
/// Auto-repair capability for common violations
impl IntegrityValidator {
/// Attempt to automatically fix violations where possible
pub fn auto_repair(&self, violations: &[IntegrityViolation]) -> Result<RepairResult, IntegrityError> {
let mut repaired = Vec::new();
let mut failed = Vec::new();
for violation in violations {
match self.attempt_repair(violation) {
Ok(()) => repaired.push(violation.clone()),
Err(e) => failed.push((violation.clone(), e)),
}
}
Ok(RepairResult { repaired, failed })
}
/// Attempt to repair a specific violation
fn attempt_repair(&self, violation: &IntegrityViolation) -> Result<(), IntegrityError> {
match violation.category {
ViolationCategory::ConfigurationBypass => {
self.repair_configuration_bypass(violation)
},
ViolationCategory::DeprecatedUsage => {
self.repair_deprecated_usage(violation)
},
// Only safe, automated repairs
_ => Err(IntegrityError::ConfigurationError(
"Manual repair required for this violation type".to_string()
))
}
}
}
#[derive(Debug)]
pub struct RepairResult {
pub repaired: Vec<IntegrityViolation>,
pub failed: Vec<(IntegrityViolation, IntegrityError)>,
}
```
## 🔧 CLI Integration
### Integrity Commands
```rust
// Add to rustelo CLI in main.rs
/// Framework integrity protection commands
#[derive(Debug, Clap)]
pub enum IntegrityCommand {
/// Validate framework integrity
Validate {
/// Path to implementation root
#[clap(long, default_value = ".")]
path: String,
/// Output format (human, json, junit)
#[clap(long, default_value = "human")]
format: String,
/// Fail on warnings
#[clap(long)]
strict: bool,
/// Generate detailed report
#[clap(long)]
detailed: bool,
},
/// Auto-repair violations where possible
Repair {
/// Path to implementation root
#[clap(long, default_value = ".")]
path: String,
/// Dry run (don't make changes)
#[clap(long)]
dry_run: bool,
/// Only repair specific categories
#[clap(long)]
categories: Option<Vec<String>>,
},
/// Show framework compatibility information
Compatibility {
/// Framework version to check against
#[clap(long)]
target_version: Option<String>,
},
/// Initialize integrity protection for new implementation
Init {
/// Path to implementation root
#[clap(long, default_value = ".")]
path: String,
/// Enable continuous validation
#[clap(long)]
continuous: bool,
},
}
async fn handle_integrity_command(cmd: IntegrityCommand) -> Result<(), CliError> {
match cmd {
IntegrityCommand::Validate { path, format, strict, detailed } => {
validate_integrity(&path, &format, strict, detailed).await
},
IntegrityCommand::Repair { path, dry_run, categories } => {
repair_violations(&path, dry_run, categories).await
},
IntegrityCommand::Compatibility { target_version } => {
check_compatibility(target_version.as_deref()).await
},
IntegrityCommand::Init { path, continuous } => {
init_integrity_protection(&path, continuous).await
},
}
}
async fn validate_integrity(
path: &str,
format: &str,
strict: bool,
detailed: bool
) -> Result<(), CliError> {
let framework_root = detect_framework_root()?;
let implementation_root = PathBuf::from(path);
let validator = IntegrityValidator::new(&framework_root, &implementation_root)?;
let result = validator.validate()?;
match format {
"json" => println!("{}", serde_json::to_string_pretty(&result)?),
"junit" => output_junit_format(&result)?,
_ => output_human_format(&result, detailed)?,
}
if !result.passed || (strict && !result.warnings.is_empty()) {
std::process::exit(1);
}
Ok(())
}
```
## 🚨 Continuous Validation
### Pre-commit Hook Integration
```bash
#!/bin/bash
# .git/hooks/pre-commit - Framework integrity validation
echo "🛡️ Running framework integrity validation..."
# Run integrity check
if ! cargo rustelo integrity validate --strict; then
echo "❌ Framework integrity validation failed!"
echo "Run 'cargo rustelo integrity repair' to attempt automatic fixes"
echo "Or 'cargo rustelo integrity validate --detailed' for more information"
exit 1
fi
echo "✅ Framework integrity validation passed"
```
### CI/CD Integration
```yaml
# .github/workflows/integrity.yml
name: Framework Integrity Check
on:
pull_request:
branches: [main, develop]
push:
branches: [main, develop]
jobs:
integrity:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install Rustelo CLI
run: cargo install --path crates/templates/rustelo-cli
- name: Validate Framework Integrity
run: |
cargo rustelo integrity validate \
--format junit \
--strict \
--detailed > integrity-results.xml
- name: Upload Integrity Report
uses: actions/upload-artifact@v3
if: always()
with:
name: integrity-report
path: integrity-results.xml
- name: Comment PR with Integrity Issues
if: failure() && github.event_name == 'pull_request'
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const results = fs.readFileSync('integrity-results.xml', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## ⚠️ Framework Integrity Issues\n\`\`\`\n${results}\n\`\`\``
});
```
## 📋 Framework Manifest
### Core Framework Manifest
```toml
# FRAMEWORK_MANIFEST.toml - Defines framework boundaries and rules
[framework]
name = "rustelo"
version = "0.1.0"
integrity_version = "1.0"
compatibility_level = "stable"
# Paths that are protected from direct modification
[[protected_paths]]
path = "crates/foundation/crates/core-lib/src/lib.rs"
reason = "Core framework interface"
alternatives = ["Implement traits in your own crates"]
[[protected_paths]]
path = "crates/foundation/crates/core-lib/src/routing/mod.rs"
reason = "Core routing system"
alternatives = ["Use route configuration in config/routes/"]
[[protected_paths]]
path = "templates/shared/"
reason = "Shared template system"
alternatives = ["Create local overrides in config/local/"]
# Required trait implementations for compatibility
[[required_traits]]
trait_name = "ContentLoader"
implementation_path = "src/content/loader.rs"
required_methods = ["load", "validate", "cache_key"]
compatibility_version = "1.0"
[[required_traits]]
trait_name = "RouteHandler"
implementation_path = "src/routing/handlers.rs"
required_methods = ["handle_request", "supports_route"]
compatibility_version = "1.0"
# Safe extension points
[[extension_points]]
name = "custom_components"
location = "src/components/custom/"
allowed_modifications = ["create", "modify", "delete"]
description = "Custom UI components"
[[extension_points]]
name = "content_processors"
location = "src/content/processors/"
allowed_modifications = ["create", "extend"]
description = "Custom content processing logic"
[[extension_points]]
name = "configuration_overrides"
location = "config/local/"
allowed_modifications = ["create", "modify"]
description = "Local configuration overrides"
# Patterns that break framework compatibility
[[forbidden_patterns]]
pattern = 'hardcoded_routes = ["/', '"/api", "/admin"]'
reason = "Hardcoded routes bypass configuration system"
suggested_alternative = "Use route configuration in config/routes/*.toml"
severity = "Critical"
[[forbidden_patterns]]
pattern = "pub mod core_lib {"
reason = "Direct framework core modification"
suggested_alternative = "Implement traits and use extension points"
severity = "Critical"
[[forbidden_patterns]]
pattern = "unsafe {"
reason = "Unsafe code bypasses framework safety guarantees"
suggested_alternative = "Use safe alternatives or request framework extension"
severity = "High"
[[forbidden_patterns]]
pattern = 'include_str!("../../'
reason = "Relative includes bypass asset system"
suggested_alternative = "Use framework asset loading APIs"
severity = "Medium"
# Update compatibility information
[update_compatibility]
breaking_changes_policy = "semantic_versioning"
migration_assistance = true
automated_migration = ["configuration", "dependencies"]
manual_migration = ["trait_signatures", "api_changes"]
[validation_rules]
max_compatibility_score = 0.8 # Minimum score for updates
critical_violations_allowed = 0
high_violations_threshold = 3
medium_violations_threshold = 10
```
## 🔄 Update Safety System
### Safe Update Process
```rust
/// Safe framework update system
pub struct UpdateManager {
current_version: String,
target_version: String,
integrity_validator: IntegrityValidator,
}
impl UpdateManager {
/// Check if update is safe to apply
pub fn can_update_safely(&self) -> Result<UpdateSafetyReport, UpdateError> {
let validation_result = self.integrity_validator.validate()?;
if !validation_result.passed {
return Ok(UpdateSafetyReport {
safe: false,
reason: "Integrity violations must be resolved first".to_string(),
violations: validation_result.violations,
required_actions: self.generate_required_actions(&validation_result.violations),
});
}
let compatibility = self.check_version_compatibility()?;
Ok(UpdateSafetyReport {
safe: compatibility.compatible,
reason: compatibility.reason,
violations: Vec::new(),
required_actions: compatibility.migration_steps,
})
}
/// Perform safe update with validation
pub async fn update_safely(&mut self) -> Result<UpdateResult, UpdateError> {
let safety_report = self.can_update_safely()?;
if !safety_report.safe {
return Err(UpdateError::UnsafeUpdate {
reason: safety_report.reason,
required_actions: safety_report.required_actions,
});
}
// Create backup before update
self.create_backup().await?;
// Apply update
let result = self.apply_update().await?;
// Validate post-update
let post_validation = self.integrity_validator.validate()?;
if !post_validation.passed {
// Rollback on validation failure
self.rollback().await?;
return Err(UpdateError::PostUpdateValidationFailed {
violations: post_validation.violations,
});
}
Ok(result)
}
}
```
## 📊 Benefits
### For Implementation Maintainers
- **Safe updates**: Never worry about breaking changes
- **Clear guidance**: Know exactly what can be customized safely
- **Automated validation**: Catch issues before they become problems
- **Easy troubleshooting**: Clear error messages with suggested fixes
### For Framework Maintainers
- **Update confidence**: Know implementations won't break
- **Reduced support**: Fewer compatibility issues
- **Architecture enforcement**: Ensure design principles are followed
- **Quality control**: Maintain high standards across ecosystem
### For Teams
- **Collaboration safety**: Multiple developers can work without breaking compatibility
- **CI/CD integration**: Automated checks in development pipeline
- **Knowledge sharing**: Clear documentation of what's allowed/forbidden
- **Risk mitigation**: Prevent costly refactoring due to incompatible changes
2026-02-08 20:37:49 +00:00
This comprehensive framework integrity protection system ensures that Rustelo implementations remain updateable and compatible with the core framework while providing maximum flexibility for customization through approved extension points.