Add OWASP compliance mapping and security test case templates, and document version control implementation phases

This commit is contained in:
pacnpal
2025-02-07 10:51:11 -05:00
parent 2c82489691
commit c083f54afb
38 changed files with 5313 additions and 94 deletions

195
history_tracking/batch.py Normal file
View File

@@ -0,0 +1,195 @@
from django.db import transaction
from django.contrib.contenttypes.models import ContentType
from django.utils import timezone
from typing import List, Dict, Any, Optional
from concurrent.futures import ThreadPoolExecutor
import logging
from .models import VersionBranch, ChangeSet
from .caching import VersionHistoryCache
from .signals import get_current_branch
logger = logging.getLogger('version_control')
class BatchOperation:
"""
Handles batch operations for version control system.
Provides efficient handling of multiple changes and updates.
"""
def __init__(self, max_workers: int = 4):
self.max_workers = max_workers
self.changes: List[Dict[str, Any]] = []
self.error_handler = self.default_error_handler
def default_error_handler(self, error: Exception, item: Dict[str, Any]) -> None:
"""Default error handling for batch operations"""
logger.error(f"Batch operation error: {error}, item: {item}")
raise error
def set_error_handler(self, handler) -> None:
"""Set custom error handler for batch operations"""
self.error_handler = handler
def add_change(self, obj: Any, data: Dict[str, Any], branch: Optional[VersionBranch] = None) -> None:
"""Add a change to the batch"""
content_type = ContentType.objects.get_for_model(obj)
self.changes.append({
'content_type': content_type,
'object_id': obj.pk,
'data': data,
'branch': branch or get_current_branch()
})
@transaction.atomic
def process_change(self, change: Dict[str, Any]) -> ChangeSet:
"""Process a single change in the batch"""
try:
changeset = ChangeSet.objects.create(
branch=change['branch'],
content_type=change['content_type'],
object_id=change['object_id'],
data=change['data'],
status='pending'
)
# Apply the change
changeset.apply()
# Cache the result
VersionHistoryCache.cache_change(changeset.to_dict())
return changeset
except Exception as e:
self.error_handler(e, change)
raise
def process_parallel(self) -> List[ChangeSet]:
"""Process changes in parallel using thread pool"""
results = []
with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
future_to_change = {
executor.submit(self.process_change, change): change
for change in self.changes
}
for future in future_to_change:
try:
changeset = future.result()
results.append(changeset)
except Exception as e:
change = future_to_change[future]
self.error_handler(e, change)
return results
@transaction.atomic
def process_sequential(self) -> List[ChangeSet]:
"""Process changes sequentially in a single transaction"""
results = []
for change in self.changes:
try:
changeset = self.process_change(change)
results.append(changeset)
except Exception as e:
self.error_handler(e, change)
return results
def commit(self, parallel: bool = False) -> List[ChangeSet]:
"""Commit all changes in the batch"""
if not self.changes:
return []
start_time = timezone.now()
logger.info(f"Starting batch operation with {len(self.changes)} changes")
try:
results = self.process_parallel() if parallel else self.process_sequential()
duration = (timezone.now() - start_time).total_seconds()
logger.info(
f"Batch operation completed: {len(results)} changes processed in {duration:.2f}s"
)
return results
finally:
self.changes = [] # Clear the batch
class BulkVersionControl:
"""
Handles bulk version control operations for collections of objects.
"""
def __init__(self, model_class, branch: Optional[VersionBranch] = None):
self.model_class = model_class
self.branch = branch or get_current_branch()
self.content_type = ContentType.objects.get_for_model(model_class)
self.batch = BatchOperation()
def prepare_bulk_update(self, objects: List[Any], data: Dict[str, Any]) -> None:
"""Prepare bulk update for multiple objects"""
for obj in objects:
self.batch.add_change(obj, data, self.branch)
def prepare_bulk_delete(self, objects: List[Any]) -> None:
"""Prepare bulk delete for multiple objects"""
for obj in objects:
self.batch.add_change(obj, {'action': 'delete'}, self.branch)
def prepare_bulk_create(self, data_list: List[Dict[str, Any]]) -> None:
"""Prepare bulk create for multiple objects"""
for data in data_list:
# Create temporary object for content type
temp_obj = self.model_class()
self.batch.add_change(temp_obj, {'action': 'create', **data}, self.branch)
def commit(self, parallel: bool = True) -> List[ChangeSet]:
"""Commit all prepared bulk operations"""
return self.batch.commit(parallel=parallel)
class VersionControlQueue:
"""
Queue system for handling version control operations.
Allows for delayed processing and batching of changes.
"""
def __init__(self, batch_size: int = 100, auto_commit: bool = True):
self.batch_size = batch_size
self.auto_commit = auto_commit
self.current_batch = BatchOperation()
self._queued_count = 0
def queue_change(self, obj: Any, data: Dict[str, Any], branch: Optional[VersionBranch] = None) -> None:
"""Queue a change for processing"""
self.current_batch.add_change(obj, data, branch)
self._queued_count += 1
if self.auto_commit and self._queued_count >= self.batch_size:
self.process_queue()
def process_queue(self, parallel: bool = True) -> List[ChangeSet]:
"""Process all queued changes"""
if not self._queued_count:
return []
results = self.current_batch.commit(parallel=parallel)
self._queued_count = 0
return results
def batch_version_control(func):
"""
Decorator for batching version control operations within a function.
"""
def wrapper(*args, **kwargs):
batch = BatchOperation()
try:
with transaction.atomic():
result = func(*args, batch=batch, **kwargs)
if batch.changes:
batch.commit()
return result
except Exception as e:
logger.error(f"Batch operation failed: {e}")
raise
return wrapper