Refactored Architecture API
This document covers the refactored architecture components introduced to implement SOLID principles and improve maintainability. These components are internal implementation details but are documented for developers working on the framework itself.
AnalysisEngine Refactored Methods
The AnalysisEngine has been refactored from monolithic methods to focused, single-responsibility methods.
Result Building Methods
- AnalysisEngine._build_apk_overview(module_results: Dict[str, BaseResult]) APKOverview [source]
Build APK overview from analysis results.
Single Responsibility: Create APK overview object from module results.
- Parameters:
module_results – Dictionary of module analysis results
- Returns:
APKOverview object populated with analysis data
Creates APK overview objects from analysis module results. Includes fallback logic to use manifest analysis data when APK overview module fails.
Key Features:
Single responsibility: APK overview creation only
Fallback support: Uses manifest analysis when primary analysis fails
Field mapping: Systematically maps all relevant APK overview fields
Error resilience: Handles missing or failed analysis gracefully
Usage Pattern:
# Internal usage in _create_full_results
apk_overview = self._build_apk_overview(module_results)
- AnalysisEngine._build_in_depth_analysis(module_results: Dict[str, BaseResult], context: AnalysisContext) Results [source]
Build in-depth analysis results from module outputs.
Single Responsibility: Create in-depth analysis object from module results.
- Parameters:
module_results – Dictionary of module analysis results
context – Analysis context for fallback operations
- Returns:
Results object populated with in-depth analysis data
Orchestrates the creation of in-depth analysis results by delegating to specialized mapping methods.
Delegation Pattern:
def _build_in_depth_analysis(self, module_results, context):
in_depth_analysis = Results()
# Delegate to specialized mapping methods
self._map_manifest_results(in_depth_analysis, module_results)
self._map_permission_results(in_depth_analysis, module_results)
self._map_string_results(in_depth_analysis, module_results, context)
# ... other mapping methods
return in_depth_analysis
- AnalysisEngine._build_tool_results(tool_results: Dict[str, Any]) tuple [source]
Build external tool results objects from tool execution data.
This method creates structured result objects for external tools like APKID and Kavanoz based on their execution success and output data.
Single Responsibility: Create tool result objects from raw tool execution data.
- Parameters:
tool_results – Dictionary containing tool execution results Expected keys: ‘apkid’, ‘kavanoz’ with ‘success’ and ‘results’ fields
- Returns:
- (ApkidResults, KavanozResults) - Tool result objects
Objects are populated with data if tool execution succeeded, otherwise they contain empty/default data
- Return type:
- Side Effects:
None: Creates new objects without modifying input data
Single Responsibility: Create tool result objects from tool execution results.
- Parameters:
tool_results – Dictionary of tool execution results
- Returns:
Tuple of (apkid_results, kavanoz_results) objects
Creates external tool result objects (APKID, Kavanoz) based on tool execution success and output data.
Tool Integration:
Handles both successful and failed tool executions
Creates appropriate result objects with populated data
Provides consistent interface regardless of tool execution status
Result Mapping Methods
Specialized mapping methods handle specific result types with single responsibility:
- AnalysisEngine._map_manifest_results(in_depth_analysis: Results, module_results: Dict[str, BaseResult]) None [source]
Map manifest analysis results to in-depth analysis.
Maps manifest analysis results to in-depth analysis structure.
Mapped Fields: - Intent filters for security analysis - Component export status - Permission definitions
- AnalysisEngine._map_permission_results(in_depth_analysis: Results, module_results: Dict[str, BaseResult]) None [source]
Map permission analysis results to in-depth analysis.
Maps permission analysis results to in-depth analysis structure.
Mapped Fields: - Critical permissions list - Permission risk assessments - Custom permission analysis
- AnalysisEngine._map_signature_results(in_depth_analysis: Results, module_results: Dict[str, BaseResult]) None [source]
Map signature detection results to in-depth analysis structure.
Single Responsibility: Extract and map signature detection data to Results object.
- Parameters:
in_depth_analysis – Results object to populate with signature data
module_results – Dictionary containing module analysis results
- Side Effects:
Modifies in_depth_analysis.signatures if signature analysis succeeded
Maps signature detection results to in-depth analysis structure.
Mapped Fields: - VirusTotal detection results - Malware signature matches - Threat intelligence data
- AnalysisEngine._map_string_results(in_depth_analysis: Results, module_results: Dict[str, BaseResult], context: AnalysisContext) None [source]
Map string analysis results to in-depth analysis with fallback support.
This method handles string analysis results with built-in fallback logic. If string analysis module failed, it uses legacy string extraction methods to ensure string data is always available.
Single Responsibility: Map string analysis data with fallback handling.
- Parameters:
in_depth_analysis – Results object to populate with string data
module_results – Dictionary containing module analysis results
context – Analysis context for fallback string extraction
- Side Effects:
Modifies in_depth_analysis string fields (strings_emails, strings_ip, etc.) May trigger fallback string extraction if module analysis failed
Maps string analysis results with built-in fallback support. This method implements resilient string analysis by falling back to legacy methods when the string analysis module fails.
Resilience Features:
def _map_string_results(self, in_depth_analysis, module_results, context):
string_result = module_results.get('string_analysis')
if string_result and string_result.status.value == 'success':
# Use successful module results
self._apply_successful_string_results(in_depth_analysis, string_result)
else:
# Fallback to legacy string extraction
self._apply_string_analysis_fallback(in_depth_analysis, context)
- AnalysisEngine._apply_successful_string_results(in_depth_analysis: Results, string_result: BaseResult) None [source]
Apply successful string analysis results to in-depth analysis.
Single Responsibility: Map successful string analysis fields to Results object.
- Parameters:
in_depth_analysis – Results object to populate
string_result – Successful string analysis result with extracted data
- Side Effects:
Populates string fields in in_depth_analysis (emails, ip_addresses, urls, domains) Logs debug information about string counts
Applies successful string analysis results to in-depth analysis object.
Field Mapping: - emails → strings_emails - ip_addresses → strings_ip - urls → strings_urls - domains → strings_domain
- AnalysisEngine._apply_string_analysis_fallback(in_depth_analysis: Results, context: AnalysisContext) None [source]
Apply fallback string analysis when string module failed.
This method provides resilience by using legacy string extraction methods when the string analysis module fails. It directly processes the APK using Androguard objects to extract string data.
Single Responsibility: Handle fallback string extraction from Androguard objects.
- Parameters:
in_depth_analysis – Results object to populate with fallback string data
context – Analysis context containing APK path and Androguard objects
- Side Effects:
Populates string fields using legacy string_analysis_execute function Logs fallback operation and any errors encountered
- Raises:
None – Handles all exceptions gracefully and logs errors
Provides fallback string analysis when the string analysis module fails. Uses legacy string extraction methods with Androguard objects.
Fallback Process:
def _apply_string_analysis_fallback(self, in_depth_analysis, context):
try:
from ..string_analysis.string_analysis_module import string_analysis_execute
old_results = string_analysis_execute(context.apk_path, context.androguard_obj)
# Map legacy results to new structure
in_depth_analysis.strings_emails = list(old_results[0])
in_depth_analysis.strings_ip = list(old_results[1])
# ... other mappings
except Exception as e:
self.logger.error(f"String analysis fallback failed: {str(e)}")
- AnalysisEngine._map_library_results(in_depth_analysis: Results, module_results: Dict[str, BaseResult]) None [source]
Map library detection results to in-depth analysis structure.
Single Responsibility: Extract and map library detection data to Results object.
- Parameters:
in_depth_analysis – Results object to populate with library data
module_results – Dictionary containing module analysis results
- Side Effects:
Modifies in_depth_analysis.libraries if library detection succeeded
- AnalysisEngine._map_tracker_results(in_depth_analysis: Results, module_results: Dict[str, BaseResult]) None [source]
Map tracker analysis results to in-depth analysis structure.
Single Responsibility: Extract and map tracker analysis data to Results object.
- Parameters:
in_depth_analysis – Results object to populate with tracker data
module_results – Dictionary containing module analysis results
- Side Effects:
Modifies in_depth_analysis.trackers if tracker analysis succeeded
- AnalysisEngine._map_behavior_results(in_depth_analysis: Results, module_results: Dict[str, BaseResult]) None [source]
Map behavior analysis results to in-depth analysis structure.
Single Responsibility: Extract and map behavior analysis data to Results object.
- Parameters:
in_depth_analysis – Results object to populate with behavior data
module_results – Dictionary containing module analysis results
- Side Effects:
Modifies in_depth_analysis.behaviors if behavior analysis succeeded
Security Assessment Strategy Pattern
The security assessment system uses the Strategy Pattern to separate concerns and improve maintainability.
Strategy Pattern Classes
- class dexray_insight.security.sensitive_data_assessment.StringCollectionStrategy(logger)[source]
Bases:
object
Strategy for collecting strings from various analysis sources.
This strategy implements the first phase of secret detection by gathering strings from multiple analysis sources including string analysis results, Android properties, and raw strings.
Responsibilities: - Extract strings from string analysis module results - Collect Android properties and system configuration strings - Gather raw strings from multiple sources - Add location metadata to each collected string
Design Pattern: Strategy Pattern (part of secret detection workflow) SOLID Principles: Single Responsibility (only handles string collection)
- collect_strings(analysis_results: Dict[str, Any]) List[Dict[str, Any]] [source]
Collect strings with location information from analysis results.
This method systematically extracts strings from various analysis sources and enriches them with location metadata for later pattern detection.
- Parameters:
analysis_results – Dictionary containing results from various analysis modules Expected keys: ‘string_analysis’ (primary source)
- Returns:
‘value’: The string value to analyze
’location’: Human-readable source location
’file_path’: File path if available (optional)
’line_number’: Line number if available (optional)
- Return type:
List of dictionaries, each containing
- Raises:
None – Method handles all exceptions gracefully and returns partial results
Single Responsibility: Gather strings from all available sources.
Implements the first phase of secret detection by collecting strings from multiple analysis sources.
String Sources:
String analysis module results (emails, URLs, domains, IP addresses)
Android properties and system configuration
Raw strings from DEX analysis
Filtered and interesting strings from various sources
Location Metadata:
Each collected string includes:
{
'value': 'the_actual_string',
'location': 'String analysis (emails)', # Human-readable source
'file_path': None, # File path if available
'line_number': None # Line number if available
}
Usage Example:
collector = StringCollectionStrategy(logger)
strings_with_location = collector.collect_strings(analysis_results)
for item in strings_with_location:
print(f"Found '{item['value']}' in {item['location']}")
- class dexray_insight.security.sensitive_data_assessment.DeepAnalysisStrategy(logger)[source]
Bases:
object
Strategy for extracting strings from deep analysis sources (XML, Smali, DEX).
This strategy implements enhanced string extraction by leveraging deep analysis artifacts like Androguard objects, DEX files, XML resources, and Smali code. It only operates when deep analysis mode is enabled.
Responsibilities: - Determine analysis mode (fast vs deep) - Extract strings from DEX objects using Androguard - Extract strings from XML resources (delegates to existing methods) - Extract strings from Smali code (delegates to existing methods) - Enrich existing string collection with deep analysis findings
Design Pattern: Strategy Pattern (second phase of secret detection workflow) SOLID Principles: Single Responsibility (only handles deep string extraction)
- extract_deep_strings(analysis_results: Dict[str, Any], existing_strings: List[Dict[str, Any]]) List[Dict[str, Any]] [source]
Extract strings from deep analysis sources like XML and Smali files.
This method attempts to extract additional strings from deep analysis artifacts if they are available. It operates in different modes based on analysis depth: - DEEP mode: Extracts from DEX, XML, and Smali sources - FAST mode: Returns existing strings unchanged (limited sources)
- Parameters:
analysis_results – Dictionary containing analysis module results Expected keys: ‘behaviour_analysis’ with androguard_objects
existing_strings – List of strings already collected by StringCollectionStrategy
- Returns:
Enhanced list of string dictionaries with additional deep analysis findings. If deep analysis is unavailable, returns existing_strings unchanged.
- Raises:
None – Method handles all exceptions gracefully and logs errors
Single Responsibility: Handle deep string extraction from androguard objects.
Enhances string collection with deep analysis artifacts when available.
Analysis Modes:
DEEP mode: Extracts strings from DEX objects, XML files, and Smali code
FAST mode: Returns existing strings unchanged for performance
Deep String Extraction:
def extract_deep_strings(self, analysis_results, existing_strings):
behaviour_results = analysis_results.get('behaviour_analysis', {})
if hasattr(behaviour_results, 'androguard_objects'):
androguard_objs = behaviour_results.androguard_objects
if androguard_objs.get('mode') == 'deep':
# Extract from DEX objects
dex_obj = androguard_objs.get('dex_obj')
if dex_obj:
dex_count = self._extract_dex_strings(dex_obj, all_strings)
# Extract from XML and Smali (delegates to existing methods)
xml_count = self._extract_xml_strings(apk_obj, all_strings)
smali_count = self._extract_smali_strings(apk_obj, all_strings)
- class dexray_insight.security.sensitive_data_assessment.PatternDetectionStrategy(detection_patterns: Dict[str, Any], logger)[source]
Bases:
object
Strategy for detecting secrets using compiled patterns.
This strategy implements the core secret detection logic by applying 54 different detection patterns to collected strings. It identifies secrets across multiple severity levels and provides detailed match information.
Responsibilities: - Apply pattern matching to collected strings - Filter out strings too short for meaningful analysis - Delegate to existing pattern detection methods - Return structured detection results with metadata
Design Pattern: Strategy Pattern (third phase of secret detection workflow) SOLID Principles: Single Responsibility (only handles pattern detection)
- detect_secrets(strings_with_location: List[Dict[str, Any]]) List[Dict[str, Any]] [source]
Detect secrets in strings using pattern matching.
This method applies the comprehensive set of 54 secret detection patterns to identify hardcoded secrets across four severity levels (CRITICAL, HIGH, MEDIUM, LOW). It filters out very short strings and applies pattern matching logic to find potential secrets.
- Parameters:
strings_with_location – List of string dictionaries from collection strategies Each dict contains ‘value’, ‘location’, ‘file_path’, ‘line_number’
- Returns:
‘type’: Type of secret detected (e.g., ‘AWS Access Key’)
’severity’: Severity level (‘CRITICAL’, ‘HIGH’, ‘MEDIUM’, ‘LOW’)
’pattern_name’: Name of the pattern that matched
’value’: The detected secret value
’location’: Source location information
’file_path’: File path if available
’line_number’: Line number if available
- Return type:
List of detection dictionaries, each containing
- Raises:
None – Method handles pattern matching exceptions gracefully
Single Responsibility: Apply pattern detection to collected strings.
Applies comprehensive pattern matching for secret detection using 54 different patterns.
Detection Pattern Categories:
CRITICAL (11 patterns): Private keys, AWS credentials, GitHub tokens
HIGH (22 patterns): API keys, JWT tokens, service credentials
MEDIUM (13 patterns): Database URIs, SSH keys, cloud service URLs
LOW (8 patterns): S3 URLs, base64 strings, high-entropy data
Pattern Matching Process:
def detect_secrets(self, strings_with_location):
detected_secrets = []
for string_data in strings_with_location:
string_value = string_data.get('value', '')
# Filter very short strings
if len(string_value.strip()) < 3:
continue
# Apply all detection patterns
matches = self._apply_patterns_to_string(string_value, string_data)
detected_secrets.extend(matches)
return detected_secrets
- class dexray_insight.security.sensitive_data_assessment.ResultClassificationStrategy[source]
Bases:
object
Strategy for classifying detection results by severity.
This strategy organizes detected secrets into severity-based categories and prepares them for final SecurityFinding generation. It creates both terminal display formats and structured evidence entries.
Responsibilities: - Classify detected secrets by severity level - Create terminal display formats with location information - Generate structured evidence entries for JSON export - Prepare classified results for finding generation
Design Pattern: Strategy Pattern (fourth phase of secret detection workflow) SOLID Principles: Single Responsibility (only handles result classification)
- classify_by_severity(detected_secrets: List[Dict[str, Any]]) Dict[str, Any] [source]
Classify detected secrets by severity level.
This method processes detected secrets and organizes them into severity categories. It creates two types of output: terminal display format for logging and structured evidence entries for JSON export.
- Parameters:
detected_secrets – List of detection dictionaries from PatternDetectionStrategy Each dict contains type, severity, pattern_name, value, location info
- Returns:
- ‘findings’: Dict with severity keys (‘critical’, ‘high’, ‘medium’, ‘low’)
Values are lists of formatted strings for terminal display
- ’secrets’: Dict with severity keys containing structured evidence entries
Each entry has type, severity, value, location, preview, etc.
- Return type:
Dictionary containing
- Raises:
None – Method handles classification exceptions gracefully
Single Responsibility: Organize findings into severity categories.
Organizes detected secrets by severity level and prepares multiple output formats.
Output Formats:
Terminal Display Format: Human-readable with emojis and location info
Structured Evidence Entries: Detailed metadata for JSON export
Classification Process:
def classify_by_severity(self, detected_secrets):
classified_findings = {
'critical': [], 'high': [], 'medium': [], 'low': []
}
detected_secrets_by_severity = {
'critical': [], 'high': [], 'medium': [], 'low': []
}
for detection in detected_secrets:
# Create terminal display format
terminal_display = f"🔑 [{detection['severity']}] {detection['type']}: ..."
# Create structured evidence entry
evidence_entry = {
'type': detection['type'],
'severity': detection['severity'],
'value': detection['value'],
'preview': detection['value'][:100] + '...' if len(detection['value']) > 100 else detection['value'],
# ... full metadata
}
severity = detection['severity'].lower()
classified_findings[severity].append(terminal_display)
detected_secrets_by_severity[severity].append(evidence_entry)
return {
'findings': classified_findings,
'secrets': detected_secrets_by_severity
}
- class dexray_insight.security.sensitive_data_assessment.FindingGenerationStrategy(owasp_category: str)[source]
Bases:
object
Strategy for generating SecurityFinding objects from classified results.
This strategy creates the final SecurityFinding objects that integrate with the broader security assessment framework. It generates findings with secret-finder style messaging and comprehensive remediation guidance.
Responsibilities: - Generate SecurityFinding objects for each severity level - Create secret-finder style titles and descriptions with emojis - Provide comprehensive remediation steps and recommendations - Limit evidence lists to prevent overwhelming output
Design Pattern: Strategy Pattern (final phase of secret detection workflow) SOLID Principles: Single Responsibility (only handles finding generation)
- generate_security_findings(classified_results: Dict[str, Any]) List[SecurityFinding] [source]
Generate SecurityFinding objects from classified detection results.
This method creates SecurityFinding objects for each severity level that contains detected secrets. It uses secret-finder style messaging with emojis and provides comprehensive remediation guidance.
- Parameters:
classified_results – Dictionary from ResultClassificationStrategy containing: - ‘findings’: Severity-categorized terminal display strings - ‘secrets’: Severity-categorized structured evidence entries
- Returns:
List of SecurityFinding objects, one for each severity level that contains detected secrets. Empty severity levels are omitted.
SecurityFinding Structure: - category: OWASP A02:2021-Cryptographic Failures - severity: AnalysisSeverity enum value (CRITICAL, HIGH, MEDIUM, LOW) - title: Secret-finder style title with emoji and count - description: Detailed explanation of security implications - evidence: Limited list of findings (10-20 items max) - recommendation: Actionable security recommendation with emoji - remediation_steps: Detailed step-by-step remediation guidance
- Raises:
None – Method handles finding generation exceptions gracefully
Single Responsibility: Create final SecurityFinding objects with proper formatting.
Generates final SecurityFinding objects with secret-finder style messaging and comprehensive remediation guidance.
Finding Generation Features:
Secret-finder style titles: “🔴 CRITICAL: 2 Hard-coded Secrets Found”
Severity-appropriate descriptions: Detailed security implications
Comprehensive remediation steps: 3-5 actionable steps per severity level
Evidence limitation: 10-20 items max to prevent information overload
SecurityFinding Structure:
SecurityFinding(
category="A02:2021-Cryptographic Failures",
severity=AnalysisSeverity.CRITICAL,
title="🔴 CRITICAL: 2 Hard-coded Secrets Found",
description="Found 2 critical severity secrets that pose immediate security risks...",
evidence=[
"🔑 [CRITICAL] AWS Access Key: AKIAIOSFODNN7EXAMPLE (found in config.xml:15)",
"🔑 [CRITICAL] Private Key: -----BEGIN RSA PRIVATE KEY----- (found in key.pem:1)"
],
recommendation="🚨 IMMEDIATE ACTION REQUIRED: Remove all hard-coded secrets...",
remediation_steps=[
"1. Remove hard-coded secrets from source code immediately",
"2. Rotate any exposed credentials (API keys, passwords, tokens)",
"3. Implement environment variables or secure secret management",
"4. Add secrets scanning to CI/CD pipeline",
"5. Audit access logs for unauthorized usage"
]
)
Strategy Pattern Workflow
The complete secret detection workflow using all strategies:
def _assess_crypto_keys_exposure(self, analysis_results: Dict[str, Any]) -> List[SecurityFinding]:
"""Comprehensive secret detection using Strategy Pattern"""
# Phase 1: String Collection
string_collector = StringCollectionStrategy(self.logger)
all_strings = string_collector.collect_strings(analysis_results)
# Phase 2: Deep Analysis Enhancement
deep_analyzer = DeepAnalysisStrategy(self.logger)
enhanced_strings = deep_analyzer.extract_deep_strings(analysis_results, all_strings)
# Phase 3: Pattern Detection
pattern_detector = PatternDetectionStrategy(self.detection_patterns, self.logger)
detected_secrets = pattern_detector.detect_secrets(enhanced_strings)
# Phase 4: Result Classification
result_classifier = ResultClassificationStrategy()
classified_results = result_classifier.classify_by_severity(detected_secrets)
# Phase 5: Finding Generation
finding_generator = FindingGenerationStrategy(self.owasp_category)
return finding_generator.generate_security_findings(classified_results)
Benefits of Strategy Pattern Implementation
Maintainability: - Each strategy has a single, well-defined responsibility - Easy to modify individual detection phases without affecting others - Clear interfaces make the system easy to understand
Extensibility: - New strategies can be added without modifying existing code - Different strategies can be swapped based on configuration - Supports future enhancements like machine learning-based detection
Testability: - Each strategy can be tested in isolation - Mock strategies can be used for testing other components - Integration testing focuses on strategy coordination
Performance: - Strategies can be optimized independently - Resource-intensive strategies can be skipped in fast analysis mode - Parallel execution of independent strategies is possible
Dependency Resolution and Execution Planning
- class dexray_insight.core.analysis_engine.DependencyResolver(registry_instance)[source]
Bases:
object
Resolves module dependencies and creates execution plans for analysis workflows.
This class analyzes the dependency graph between analysis modules and creates optimized execution plans that respect dependencies while maximizing parallel execution opportunities.
Responsibilities: - Parse module dependencies from registered analysis modules - Build dependency graphs and detect circular dependencies - Perform topological sorting to determine execution order - Identify modules that can be executed in parallel - Create structured ExecutionPlan objects for the AnalysisEngine
Design Pattern: Dependency Injection (receives registry) SOLID Principles: Single Responsibility (only handles dependency resolution)
- resolve_dependencies(requested_modules: List[str]) ExecutionPlan [source]
Resolve module dependencies and create execution plan
- Parameters:
requested_modules – List of module names to execute
- Returns:
ExecutionPlan with proper execution order
The DependencyResolver creates optimized execution plans that respect module dependencies while maximizing parallel execution opportunities.
Dependency Resolution Process:
def resolve_dependencies(self, requested_modules):
# Build dependency graph
dependency_graph = {}
all_modules = set(requested_modules)
for module_name in all_modules:
module_class = self.registry.get_module(module_name)
instance = module_class({}) # Temporary instance
deps = instance.get_dependencies()
dependency_graph[module_name] = deps
all_modules.update(deps) # Add dependencies
# Topological sort for execution order
execution_order = self._topological_sort(dependency_graph, all_modules)
# Identify parallel execution opportunities
parallel_groups = self._identify_parallel_groups(dependency_graph, execution_order)
return ExecutionPlan(
modules=list(all_modules),
execution_order=execution_order,
parallel_groups=parallel_groups
)
- class dexray_insight.core.analysis_engine.ExecutionPlan(modules: List[str], tools: List[str], execution_order: List[str], parallel_groups: List[List[str]])[source]
Bases:
object
Represents the execution plan for analysis modules with dependency ordering.
This dataclass encapsulates the complete execution strategy for a set of analysis modules, including dependency-aware ordering and parallelization opportunities.
- parallel_groups
List of lists, each inner list contains modules that can be executed in parallel with each other
- Type:
List[List[str]]
Design Pattern: Data Transfer Object (DTO) Usage: Created by DependencyResolver, consumed by AnalysisEngine
Data structure containing the complete execution strategy for analysis modules.
Parallel Execution Groups:
# Example execution plan
execution_plan = ExecutionPlan(
modules=['apk_overview', 'manifest_analysis', 'string_analysis', 'security_assessment'],
execution_order=['apk_overview', 'manifest_analysis', 'string_analysis', 'security_assessment'],
parallel_groups=[
['apk_overview'], # Must run first
['manifest_analysis', 'permission_analysis'], # Can run in parallel after apk_overview
['string_analysis', 'library_detection'], # Can run in parallel after manifest
['security_assessment'] # Must run after string_analysis
]
)
Enhanced Base Classes
The base classes have been enhanced with comprehensive documentation and improved interfaces.
- class dexray_insight.core.base_classes.AnalysisContext(apk_path: str, config: Dict[str, Any], androguard_obj: Any | None = None, unzip_path: str | None = None, module_results: Dict[str, Any] | None = None, temporal_paths: Any | None = None, jadx_available: bool = False, apktool_available: bool = False)[source]
Bases:
object
Context object passed between modules containing shared data and results.
The AnalysisContext serves as a shared data container that is passed between analysis modules during the analysis workflow. It contains APK information, configuration, and accumulated results from previous modules.
This design enables: - Data sharing between dependent modules - Centralized configuration access - Progressive result accumulation - Temporal directory management
- androguard_obj
Optional pre-loaded Androguard analysis object
- Type:
Any | None
- temporal_paths
Modern temporal directory management object
- Type:
Any | None
Design Pattern: Context Object (shares state between modules) SOLID Principles: Single Responsibility (data container and accessor)
- add_result(module_name: str, result: Any)[source]
Add a module result to the context for use by dependent modules.
This method allows completed modules to store their results in the shared context where they can be accessed by dependent modules.
- Parameters:
module_name – Name of the module storing the result
result – Analysis result object or data structure
- Side Effects:
Modifies self.module_results dictionary
- get_unzipped_dir() str | None [source]
Get path to unzipped APK directory (temporal or legacy).
This method provides backwards compatibility by checking both modern temporal paths and legacy unzip paths.
- Returns:
Path to unzipped APK directory, or None if not available
- Return type:
Design Pattern: Facade (hides complexity of path resolution)
Enhanced context object with temporal directory management and improved data sharing.
Modern vs Legacy Path Handling:
# Modern temporal path access
if context.temporal_paths:
unzipped_dir = context.temporal_paths.unzipped_dir
jadx_dir = context.temporal_paths.jadx_dir
# Legacy path access (deprecated but supported)
unzipped_dir = context.get_unzipped_dir() # Uses temporal_paths if available
Advanced Data Sharing:
# Store analysis results for dependent modules
context.add_result('string_analysis', string_analysis_results)
# Access results from other modules
if 'string_analysis' in context.module_results:
strings = context.module_results['string_analysis']
- class dexray_insight.core.base_classes.AnalysisSeverity(value)[source]
Bases:
Enum
Enumeration of analysis severity levels for security findings.
Used throughout the security assessment framework to classify the severity of detected vulnerabilities and security issues.
- Values:
LOW: Informational findings or minor security concerns MEDIUM: Moderate security issues requiring attention HIGH: Serious security vulnerabilities needing prompt remediation CRITICAL: Severe security issues requiring immediate action
- LOW = 'low'
- MEDIUM = 'medium'
- HIGH = 'high'
- CRITICAL = 'critical'
Enhanced severity enumeration with comprehensive documentation.
- class dexray_insight.core.base_classes.AnalysisStatus(value)[source]
Bases:
Enum
Enumeration of analysis module execution statuses.
Used to track the execution state of individual analysis modules and provide consistent status reporting across the framework.
- Values:
SUCCESS: Module completed successfully with results FAILURE: Module failed to execute due to errors PARTIAL: Module completed with some issues or warnings SKIPPED: Module was not executed (disabled, missing dependencies, etc.)
- SUCCESS = 'success'
- FAILURE = 'failure'
- PARTIAL = 'partial'
- SKIPPED = 'skipped'
Enhanced status enumeration for consistent module execution tracking.
Testing Architecture
The refactored architecture enables comprehensive testing at multiple levels.
Unit Testing Patterns
Strategy Testing:
class TestStringCollectionStrategy:
def test_collect_strings_from_string_analysis(self):
# Test single responsibility in isolation
strategy = StringCollectionStrategy(mock_logger)
result = strategy.collect_strings(mock_analysis_results)
# Focused assertions on single responsibility
assert isinstance(result, list)
assert all('value' in item for item in result)
assert all('location' in item for item in result)
Builder Method Testing:
class TestAnalysisEngineBuilders:
def test_build_apk_overview_with_successful_result(self):
# Test focused method with clear inputs/outputs
engine = AnalysisEngine(config)
module_results = {'apk_overview': mock_successful_result}
apk_overview = engine._build_apk_overview(module_results)
assert apk_overview.general_info == mock_successful_result.general_info
assert apk_overview.permissions == mock_successful_result.permissions
Integration Testing Patterns
Strategy Workflow Testing:
class TestSecurityAssessmentIntegration:
def test_complete_strategy_workflow(self):
# Test strategy coordination without implementation details
assessment = SensitiveDataAssessment(config)
findings = assessment._assess_crypto_keys_exposure(mock_analysis_results)
assert isinstance(findings, list)
assert all(isinstance(f, SecurityFinding) for f in findings)
Result Building Integration:
class TestResultBuildingIntegration:
def test_create_full_results_integration(self):
# Test complete result building workflow
engine = AnalysisEngine(config)
results = engine._create_full_results(
mock_module_results,
mock_tool_results,
mock_security_results,
mock_context
)
assert isinstance(results, FullAnalysisResults)
assert results.apk_overview is not None
assert results.in_depth_analysis is not None
Migration and Upgrade Guide
For developers migrating to the refactored architecture:
Public API Compatibility:
- All public APIs remain unchanged
- AnalysisEngine.analyze_apk()
method signature is identical
- Result structures and JSON output format are preserved
Internal Method Changes: - Large methods have been split into focused methods - Strategy Pattern classes are new implementations - Internal method signatures may have changed
Testing Updates: - New focused testing patterns are available - Legacy integration tests continue to work - New unit testing opportunities for individual strategies
Extension Points: - Strategy Pattern enables easier customization - Builder methods can be overridden for custom result formats - Dependency injection possibilities for better testability