Some checks failed
CI/CD Pipeline / Test Suite (push) Has been cancelled
CI/CD Pipeline / Security Audit (push) Has been cancelled
CI/CD Pipeline / Performance Benchmarks (push) Has been cancelled
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (nightly) (push) Has been cancelled
Rust CI / Check + Test + Lint (stable) (push) Has been cancelled
CI/CD Pipeline / Build Docker Image (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Cleanup (push) Has been cancelled
23 KiB
23 KiB
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
// 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
// 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
#!/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
# .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
# 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
/// 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
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.