fix: Address high-severity bandit issues
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
"""
|
||||
DSS Context Compiler
|
||||
DSS Context Compiler.
|
||||
|
||||
Resolves project context via 3-layer cascade: Base -> Skin -> Project
|
||||
Includes Safe Boot Protocol and Debug Provenance.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import copy
|
||||
import json
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
from typing import Dict, Any, Optional, List, Union
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List
|
||||
|
||||
# Setup logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
@@ -21,25 +21,26 @@ logger = logging.getLogger("DSSCompiler")
|
||||
EMERGENCY_SKIN = {
|
||||
"meta": {"id": "emergency", "version": "1.0.0"},
|
||||
"tokens": {
|
||||
"colors": {
|
||||
"primary": "#FF0000",
|
||||
"background": "#FFFFFF",
|
||||
"text": "#000000"
|
||||
},
|
||||
"spacing": {"base": "4px"}
|
||||
"colors": {"primary": "#FF0000", "background": "#FFFFFF", "text": "#000000"},
|
||||
"spacing": {"base": "4px"},
|
||||
},
|
||||
"status": "emergency_mode"
|
||||
"status": "emergency_mode",
|
||||
}
|
||||
|
||||
|
||||
class ContextCompiler:
|
||||
def __init__(self, skins_dir: str = "./skins"):
|
||||
self.skins_dir = Path(skins_dir)
|
||||
self.cache: Dict[str, Any] = {}
|
||||
self._manifest_mtimes: Dict[str, float] = {} # Track file modification times
|
||||
|
||||
def compile(self, manifest_path: str, debug: bool = False, force_refresh: bool = False) -> Dict[str, Any]:
|
||||
def compile(
|
||||
self, manifest_path: str, debug: bool = False, force_refresh: bool = False
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Main entry point. Compiles context by merging:
|
||||
Main entry point.
|
||||
|
||||
Compiles context by merging:
|
||||
1. Base Skin (Implicit or Explicit)
|
||||
2. Extended Skin (defined in manifest)
|
||||
3. Project Overrides (defined in manifest)
|
||||
@@ -83,17 +84,17 @@ class ContextCompiler:
|
||||
|
||||
# Merge Result + Project Overrides
|
||||
# Need to wrap project overrides in same structure as skins
|
||||
project_overrides_wrapped = {
|
||||
"tokens": manifest.get("overrides", {}).get("tokens", {})
|
||||
}
|
||||
final_context = self._deep_merge(context, project_overrides_wrapped, path="skin->project", debug=debug)
|
||||
project_overrides_wrapped = {"tokens": manifest.get("overrides", {}).get("tokens", {})}
|
||||
final_context = self._deep_merge(
|
||||
context, project_overrides_wrapped, path="skin->project", debug=debug
|
||||
)
|
||||
|
||||
# Inject Metadata
|
||||
final_context["_meta"] = {
|
||||
"project_id": manifest["project"]["id"],
|
||||
"compiled_at": datetime.now(timezone.utc).isoformat(),
|
||||
"debug_enabled": debug,
|
||||
"compiler_config": manifest.get("compiler", {})
|
||||
"compiler_config": manifest.get("compiler", {}),
|
||||
}
|
||||
|
||||
if debug:
|
||||
@@ -138,19 +139,28 @@ class ContextCompiler:
|
||||
return data
|
||||
|
||||
def _load_json(self, path: str) -> Dict[str, Any]:
|
||||
with open(path, 'r') as f:
|
||||
with open(path, "r") as f:
|
||||
return json.load(f)
|
||||
|
||||
def _deep_merge(self, base: Dict, override: Dict, path: str = "", debug: bool = False, provenance: List[Dict] = None) -> Dict:
|
||||
def _deep_merge(
|
||||
self,
|
||||
base: Dict,
|
||||
override: Dict,
|
||||
path: str = "",
|
||||
debug: bool = False,
|
||||
provenance: List[Dict] = None,
|
||||
) -> Dict:
|
||||
"""
|
||||
Deep merge dictionaries. Replaces arrays.
|
||||
Deep merge dictionaries.
|
||||
|
||||
Replaces arrays.
|
||||
Populates provenance list if debug is True (thread-safe).
|
||||
"""
|
||||
# Thread-safe: use method parameter instead of instance variable
|
||||
if provenance is None and debug:
|
||||
provenance = []
|
||||
# Store reference on first call for later retrieval
|
||||
if not hasattr(self, 'provenance_log'):
|
||||
if not hasattr(self, "provenance_log"):
|
||||
self.provenance_log = provenance
|
||||
|
||||
result = copy.deepcopy(base)
|
||||
@@ -158,16 +168,20 @@ class ContextCompiler:
|
||||
for key, value in override.items():
|
||||
if isinstance(value, dict) and key in result and isinstance(result[key], dict):
|
||||
# Recursive merge - pass provenance down
|
||||
result[key] = self._deep_merge(result[key], value, path=f"{path}.{key}", debug=debug, provenance=provenance)
|
||||
result[key] = self._deep_merge(
|
||||
result[key], value, path=f"{path}.{key}", debug=debug, provenance=provenance
|
||||
)
|
||||
else:
|
||||
# Direct replacement (Primitive or Array)
|
||||
if debug and provenance is not None:
|
||||
provenance.append({
|
||||
"key": key,
|
||||
"action": "override",
|
||||
"layer": path,
|
||||
"value_type": type(value).__name__
|
||||
})
|
||||
provenance.append(
|
||||
{
|
||||
"key": key,
|
||||
"action": "override",
|
||||
"layer": path,
|
||||
"value_type": type(value).__name__,
|
||||
}
|
||||
)
|
||||
result[key] = copy.deepcopy(value)
|
||||
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user