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:

tuple

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)

__init__(logger)[source]
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)

__init__(logger)[source]
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)

__init__(detection_patterns: Dict[str, Any], logger)[source]
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:

  1. Terminal Display Format: Human-readable with emojis and location info

  2. 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)

__init__(owasp_category: str)[source]
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)

__init__(registry_instance)[source]
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.

modules

List of all modules to be executed (includes dependencies)

Type:

List[str]

tools

List of external tools to be executed

Type:

List[str]

execution_order

Dependency-ordered list of modules (topological sort)

Type:

List[str]

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

modules: List[str]
tools: List[str]
execution_order: List[str]
parallel_groups: List[List[str]]
__init__(modules: List[str], tools: List[str], execution_order: List[str], parallel_groups: List[List[str]]) None

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

apk_path

File path to the APK being analyzed

Type:

str

config

Configuration dictionary from the engine

Type:

Dict[str, Any]

androguard_obj

Optional pre-loaded Androguard analysis object

Type:

Any | None

unzip_path

Legacy field for backwards compatibility (deprecated)

Type:

str | None

module_results

Dictionary storing results from completed modules

Type:

Dict[str, Any]

temporal_paths

Modern temporal directory management object

Type:

Any | None

jadx_available

Flag indicating JADX decompiler availability

Type:

bool

apktool_available

Flag indicating APKTool availability

Type:

bool

Design Pattern: Context Object (shares state between modules) SOLID Principles: Single Responsibility (data container and accessor)

apk_path: str
config: Dict[str, Any]
androguard_obj: Any | None = None
unzip_path: str | None = None
module_results: Dict[str, Any] = None
temporal_paths: Any | None = None
jadx_available: bool = False
apktool_available: bool = False
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:

str

Design Pattern: Facade (hides complexity of path resolution)

get_jadx_dir() str | None[source]

Get path to JADX decompiled directory

get_apktool_dir() str | None[source]

Get path to apktool results directory

get_result(module_name: str) Any | None[source]

Get a result from a previously executed module

__init__(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) None

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