Skip to content

Commit bd94d19

Browse files
authored
Merge pull request #28 from FuzzingLabs/feature/android-workflow-conversion
feat: Android Static Analysis Workflow with ARM64 Support
2 parents e180431 + b0a0d59 commit bd94d19

33 files changed

+3347
-28
lines changed

.github/scripts/validate-workers.sh

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,40 @@ for worker in $WORKERS; do
4747
continue
4848
fi
4949

50-
# Check required files
51-
REQUIRED_FILES=("Dockerfile" "requirements.txt" "worker.py")
50+
# Check Dockerfile (single file or multi-platform pattern)
51+
if [ -f "$WORKER_DIR/Dockerfile" ]; then
52+
# Single Dockerfile
53+
if ! git ls-files --error-unmatch "$WORKER_DIR/Dockerfile" &> /dev/null; then
54+
echo -e "${RED} ❌ File not tracked by git: $WORKER_DIR/Dockerfile${NC}"
55+
echo -e "${YELLOW} Check .gitignore patterns!${NC}"
56+
ERRORS=$((ERRORS + 1))
57+
else
58+
echo -e "${GREEN} ✓ Dockerfile (tracked)${NC}"
59+
fi
60+
elif compgen -G "$WORKER_DIR/Dockerfile.*" > /dev/null; then
61+
# Multi-platform Dockerfiles (e.g., Dockerfile.amd64, Dockerfile.arm64)
62+
PLATFORM_DOCKERFILES=$(ls "$WORKER_DIR"/Dockerfile.* 2>/dev/null)
63+
DOCKERFILE_FOUND=false
64+
for dockerfile in $PLATFORM_DOCKERFILES; do
65+
if git ls-files --error-unmatch "$dockerfile" &> /dev/null; then
66+
echo -e "${GREEN}$(basename "$dockerfile") (tracked)${NC}"
67+
DOCKERFILE_FOUND=true
68+
else
69+
echo -e "${RED} ❌ File not tracked by git: $dockerfile${NC}"
70+
ERRORS=$((ERRORS + 1))
71+
fi
72+
done
73+
if [ "$DOCKERFILE_FOUND" = false ]; then
74+
echo -e "${RED} ❌ No platform-specific Dockerfiles found${NC}"
75+
ERRORS=$((ERRORS + 1))
76+
fi
77+
else
78+
echo -e "${RED} ❌ Missing Dockerfile or Dockerfile.* files${NC}"
79+
ERRORS=$((ERRORS + 1))
80+
fi
81+
82+
# Check other required files
83+
REQUIRED_FILES=("requirements.txt" "worker.py")
5284
for file in "${REQUIRED_FILES[@]}"; do
5385
FILE_PATH="$WORKER_DIR/$file"
5486

CHANGELOG.md

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,93 @@ All notable changes to FuzzForge will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [0.7.0] - 2025-01-16
8+
## [Unreleased]
9+
10+
### 🎯 Major Features
11+
12+
#### Android Static Analysis Workflow
13+
- **Added comprehensive Android security testing workflow** (`android_static_analysis`):
14+
- Jadx decompiler for APK → Java source code decompilation
15+
- OpenGrep/Semgrep static analysis with custom Android security rules
16+
- MobSF integration for comprehensive mobile security scanning
17+
- SARIF report generation with unified findings format
18+
- Test results: Successfully decompiled 4,145 Java files, found 8 security vulnerabilities
19+
- Full workflow completes in ~1.5 minutes
20+
21+
#### Platform-Aware Worker Architecture
22+
- **ARM64 (Apple Silicon) support**:
23+
- Automatic platform detection (ARM64 vs x86_64) in CLI using `platform.machine()`
24+
- Worker metadata convention (`metadata.yaml`) for platform-specific capabilities
25+
- Multi-Dockerfile support: `Dockerfile.amd64` (full toolchain) and `Dockerfile.arm64` (optimized)
26+
- Conditional module imports for graceful degradation (MobSF skips on ARM64)
27+
- Backend path resolution via `FUZZFORGE_HOST_ROOT` for CLI worker management
28+
- **Worker selection logic**:
29+
- CLI automatically selects appropriate Dockerfile based on detected platform
30+
- Multi-strategy path resolution (API → .fuzzforge marker → environment variable)
31+
- Platform-specific tool availability documented in metadata
32+
33+
#### Python SAST Workflow
34+
- **Added Python Static Application Security Testing workflow** (`python_sast`):
35+
- Bandit for Python security linting (SAST)
36+
- MyPy for static type checking
37+
- Safety for dependency vulnerability scanning
38+
- Integrated SARIF reporter for unified findings format
39+
- Auto-start Python worker on-demand
40+
41+
### ✨ Enhancements
42+
43+
#### CI/CD Improvements
44+
- Added automated worker validation in CI pipeline
45+
- Docker build checks for all workers before merge
46+
- Worker file change detection for selective builds
47+
- Optimized Docker layer caching for faster builds
48+
- Dev branch testing workflow triggers
49+
50+
#### CLI Improvements
51+
- Fixed live monitoring bug in `ff monitor live` command
52+
- Enhanced `ff findings` command with better table formatting
53+
- Improved `ff monitor` with clearer status displays
54+
- Auto-start workers on-demand when workflows require them
55+
- Better error messages with actionable manual start commands
56+
57+
#### Worker Management
58+
- Standardized worker service names (`worker-python`, `worker-android`, etc.)
59+
- Added missing `worker-secrets` to repository
60+
- Improved worker naming consistency across codebase
61+
62+
#### LiteLLM Integration
63+
- Centralized LLM provider management with proxy
64+
- Governance and request/response routing
65+
- OTEL collector integration for observability
66+
- Environment-based configurable timeouts
67+
- Optional `.env.litellm` configuration
68+
69+
### 🐛 Bug Fixes
70+
71+
- Fixed MobSF API key generation from secret file (SHA256 hash)
72+
- Corrected Temporal activity names (decompile_with_jadx, scan_with_opengrep, scan_with_mobsf)
73+
- Resolved linter errors across codebase
74+
- Fixed unused import issues to pass CI checks
75+
- Removed deprecated workflow parameters
76+
- Docker Compose version compatibility fixes
77+
78+
### 🔧 Technical Changes
79+
80+
- Conditional import pattern for optional dependencies (MobSF on ARM64)
81+
- Multi-platform Dockerfile architecture
82+
- Worker metadata convention for capability declaration
83+
- Improved CI worker build optimization
84+
- Enhanced storage activity error handling
85+
86+
### 📝 Test Projects
87+
88+
- Added `test_projects/android_test/` with BeetleBug.apk and shopnest.apk
89+
- Android workflow validation with real APK samples
90+
- ARM64 platform testing and validation
91+
92+
---
93+
94+
## [0.7.0] - 2025-10-16
995

1096
### 🎯 Major Features
1197

backend/src/api/system.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Copyright (c) 2025 FuzzingLabs
2+
#
3+
# Licensed under the Business Source License 1.1 (BSL). See the LICENSE file
4+
# at the root of this repository for details.
5+
#
6+
# After the Change Date (four years from publication), this version of the
7+
# Licensed Work will be made available under the Apache License, Version 2.0.
8+
# See the LICENSE-APACHE file or http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Additional attribution and requirements are provided in the NOTICE file.
11+
12+
"""
13+
System information endpoints for FuzzForge API.
14+
15+
Provides system configuration and filesystem paths to CLI for worker management.
16+
"""
17+
18+
import os
19+
from typing import Dict
20+
21+
from fastapi import APIRouter
22+
23+
router = APIRouter(prefix="/system", tags=["system"])
24+
25+
26+
@router.get("/info")
27+
async def get_system_info() -> Dict[str, str]:
28+
"""
29+
Get system information including host filesystem paths.
30+
31+
This endpoint exposes paths needed by the CLI to manage workers via docker-compose.
32+
The FUZZFORGE_HOST_ROOT environment variable is set by docker-compose and points
33+
to the FuzzForge installation directory on the host machine.
34+
35+
Returns:
36+
Dictionary containing:
37+
- host_root: Absolute path to FuzzForge root on host
38+
- docker_compose_path: Path to docker-compose.yml on host
39+
- workers_dir: Path to workers directory on host
40+
"""
41+
host_root = os.getenv("FUZZFORGE_HOST_ROOT", "")
42+
43+
return {
44+
"host_root": host_root,
45+
"docker_compose_path": f"{host_root}/docker-compose.yml" if host_root else "",
46+
"workers_dir": f"{host_root}/workers" if host_root else "",
47+
}

backend/src/main.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
from src.temporal.manager import TemporalManager
2626
from src.core.setup import setup_result_storage, validate_infrastructure
27-
from src.api import workflows, runs, fuzzing
27+
from src.api import workflows, runs, fuzzing, system
2828

2929
from fastmcp import FastMCP
3030

@@ -76,6 +76,7 @@ def as_dict(self) -> Dict[str, Any]:
7676
app.include_router(workflows.router)
7777
app.include_router(runs.router)
7878
app.include_router(fuzzing.router)
79+
app.include_router(system.router)
7980

8081

8182
def get_temporal_status() -> Dict[str, Any]:
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""
2+
Android Security Analysis Modules
3+
4+
Modules for Android application security testing:
5+
- JadxDecompiler: APK decompilation using Jadx
6+
- MobSFScanner: Mobile security analysis using MobSF
7+
- OpenGrepAndroid: Static analysis using OpenGrep/Semgrep with Android-specific rules
8+
"""
9+
10+
# Copyright (c) 2025 FuzzingLabs
11+
#
12+
# Licensed under the Business Source License 1.1 (BSL). See the LICENSE file
13+
# at the root of this repository for details.
14+
#
15+
# After the Change Date (four years from publication), this version of the
16+
# Licensed Work will be made available under the Apache License, Version 2.0.
17+
# See the LICENSE-APACHE file or http://www.apache.org/licenses/LICENSE-2.0
18+
#
19+
# Additional attribution and requirements are provided in the NOTICE file.
20+
21+
from .jadx_decompiler import JadxDecompiler
22+
from .opengrep_android import OpenGrepAndroid
23+
24+
# MobSF is optional (not available on ARM64 platform)
25+
try:
26+
from .mobsf_scanner import MobSFScanner
27+
__all__ = ["JadxDecompiler", "MobSFScanner", "OpenGrepAndroid"]
28+
except ImportError:
29+
# MobSF dependencies not available (e.g., ARM64 platform)
30+
MobSFScanner = None
31+
__all__ = ["JadxDecompiler", "OpenGrepAndroid"]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
rules:
2+
- id: clipboard-sensitive-data
3+
severity: WARNING
4+
languages: [java]
5+
message: "Sensitive data may be copied to the clipboard."
6+
metadata:
7+
authors:
8+
- Guerric ELOI (FuzzingLabs)
9+
category: security
10+
area: clipboard
11+
verification-level: [L1]
12+
paths:
13+
include:
14+
- "**/*.java"
15+
pattern: "$CLIPBOARD.setPrimaryClip($CLIP)"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
rules:
2+
- id: hardcoded-secrets
3+
severity: WARNING
4+
languages: [java]
5+
message: "Possible hardcoded secret found in variable '$NAME'."
6+
metadata:
7+
authors:
8+
- Guerric ELOI (FuzzingLabs)
9+
owasp-mobile: M2
10+
category: secrets
11+
verification-level: [L1]
12+
paths:
13+
include:
14+
- "**/*.java"
15+
patterns:
16+
- pattern-either:
17+
- pattern: 'String $NAME = "$VAL";'
18+
- pattern: 'final String $NAME = "$VAL";'
19+
- pattern: 'private String $NAME = "$VAL";'
20+
- pattern: 'public static String $NAME = "$VAL";'
21+
- pattern: 'static final String $NAME = "$VAL";'
22+
- pattern-regex: "$NAME =~ /(?i).*(api|key|token|secret|pass|auth|session|bearer|access|private).*/"
23+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
rules:
2+
- id: insecure-data-storage
3+
severity: WARNING
4+
languages: [java]
5+
message: "Potential insecure data storage (external storage)."
6+
metadata:
7+
authors:
8+
- Guerric ELOI (FuzzingLabs)
9+
owasp-mobile: M2
10+
category: security
11+
area: storage
12+
verification-level: [L1]
13+
paths:
14+
include:
15+
- "**/*.java"
16+
pattern-either:
17+
- pattern: "$CTX.openFileOutput($NAME, $MODE)"
18+
- pattern: "Environment.getExternalStorageDirectory()"
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
rules:
2+
- id: insecure-deeplink
3+
severity: WARNING
4+
languages: [xml]
5+
message: "Potential insecure deeplink found in intent-filter."
6+
metadata:
7+
authors:
8+
- Guerric ELOI (FuzzingLabs)
9+
category: component
10+
area: manifest
11+
verification-level: [L1]
12+
paths:
13+
include:
14+
- "**/AndroidManifest.xml"
15+
pattern: |
16+
<intent-filter>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
rules:
2+
- id: insecure-logging
3+
severity: WARNING
4+
languages: [java]
5+
message: "Sensitive data logged via Android Log API."
6+
metadata:
7+
authors:
8+
- Guerric ELOI (FuzzingLabs)
9+
owasp-mobile: M2
10+
category: logging
11+
verification-level: [L1]
12+
paths:
13+
include:
14+
- "**/*.java"
15+
patterns:
16+
- pattern-either:
17+
- pattern: "Log.d($TAG, $MSG)"
18+
- pattern: "Log.e($TAG, $MSG)"
19+
- pattern: "System.out.println($MSG)"
20+
- pattern-regex: "$MSG =~ /(?i).*(password|token|secret|api|auth|session).*/"
21+

0 commit comments

Comments
 (0)