mirror of
https://github.com/ruvnet/RuView
synced 2026-07-28 18:21:42 +00:00
chore(repo): move v1/ → archive/v1/ + add archive/README.md (#430)
The Rust port at v2/ has been the primary codebase since the rename in #427. The Python implementation at v1/ is no longer the active target; the only load-bearing path is the deterministic proof bundle at v1/data/proof/ (per ADR-011 / ADR-028 witness verification). Move the whole Python tree into archive/v1/ and document the policy in archive/README.md: no new features, bug fixes only when they affect a still-load-bearing path (currently just the proof), CI continues to verify the proof on every push and PR. Path references updated in 26 files via path-pattern sed (only matches v1/<known-child> patterns, never bare v1 or API URLs like /api/v1/). Two double-prefix typos (archive/archive/v1/) caught and hand-fixed in verify-pipeline.yml and ADR-011. Validated: - Python proof verify.py imports cleanly at archive/v1/data/proof/ (numpy/scipy still required; CI installs requirements-lock.txt from archive/v1/ now) - cargo test --workspace --no-default-features → 1,539 passed, 0 failed, 8 ignored (unaffected by Python tree relocation) - ESP32-S3 on COM7 untouched (no firmware paths changed) After-merge: contributors should re-run any local `python v1/...` commands as `python archive/v1/...` (CLAUDE.md and CHANGELOG already updated).
This commit is contained in:
@@ -38,7 +38,7 @@ The project implements WiFi-based human pose estimation using Channel State Info
|
||||
| Architecture Decision Records | Strong | 79 ADRs documented in `docs/adr/` |
|
||||
| CI/CD pipelines | Strong | 8 GitHub Actions workflows (CI, CD, security scan, firmware CI, QEMU, desktop release, verify pipeline, submodules) |
|
||||
| Security scanning | Strong | Dedicated `security-scan.yml` with Bandit, Semgrep, Safety; runs daily on schedule |
|
||||
| Deterministic verification | Strong | SHA-256 proof pipeline (`v1/data/proof/verify.py`) with witness bundles (ADR-028) |
|
||||
| Deterministic verification | Strong | SHA-256 proof pipeline (`archive/v1/data/proof/verify.py`) with witness bundles (ADR-028) |
|
||||
| Code formatting | Moderate | Black/Flake8 enforced for Python in CI; no `rustfmt.toml` found for Rust |
|
||||
| Type checking | Moderate | MyPy configured in CI for Python; Rust has native type safety |
|
||||
| Dependency management | Strong | Workspace-level Cargo.toml with pinned versions; `requirements.txt` for Python |
|
||||
|
||||
@@ -368,7 +368,7 @@ or macro-based approach would reduce this to a fraction of the code.
|
||||
| wifi-densepose-wifiscan | 75/100 | EASY | Platform-specific but well-abstracted |
|
||||
| wifi-densepose-sensing-server | 32/100 | VERY DIFFICULT | God object, coupled state, async |
|
||||
| wifi-densepose-wasm-edge | 55/100 | MODERATE | Repetitive but self-contained |
|
||||
| v1/src (Python) | 70/100 | MODERATE | Good DI, some tight coupling |
|
||||
| archive/v1/src (Python) | 70/100 | MODERATE | Good DI, some tight coupling |
|
||||
| firmware (C) | 40/100 | DIFFICULT | Hardware deps, global state |
|
||||
| ui/mobile (TypeScript) | 72/100 | MODERATE | Component isolation is good |
|
||||
|
||||
|
||||
@@ -35,20 +35,20 @@ This security review examined all security-sensitive code across the wifi-densep
|
||||
**Severity:** HIGH
|
||||
**OWASP:** A07:2021 -- Identification and Authentication Failures
|
||||
**Files:**
|
||||
- `v1/src/api/routers/stream.py:74` (WebSocket `token` query parameter)
|
||||
- `v1/src/middleware/auth.py:243` (fallback to `request.query_params.get("token")`)
|
||||
- `v1/src/api/middleware/auth.py:173` (`request.query_params.get("token")`)
|
||||
- `archive/v1/src/api/routers/stream.py:74` (WebSocket `token` query parameter)
|
||||
- `archive/v1/src/middleware/auth.py:243` (fallback to `request.query_params.get("token")`)
|
||||
- `archive/v1/src/api/middleware/auth.py:173` (`request.query_params.get("token")`)
|
||||
|
||||
**Description:**
|
||||
JWT tokens are accepted via URL query parameters for WebSocket connections. URL parameters are logged in web server access logs, browser history, proxy logs, and HTTP Referer headers. This creates multiple credential leakage vectors.
|
||||
|
||||
```python
|
||||
# v1/src/api/routers/stream.py:74
|
||||
# archive/v1/src/api/routers/stream.py:74
|
||||
token: Optional[str] = Query(None, description="Authentication token")
|
||||
```
|
||||
|
||||
```python
|
||||
# v1/src/middleware/auth.py:243
|
||||
# archive/v1/src/middleware/auth.py:243
|
||||
if request.url.path.startswith("/ws"):
|
||||
token = request.query_params.get("token")
|
||||
```
|
||||
@@ -66,13 +66,13 @@ if request.url.path.startswith("/ws"):
|
||||
|
||||
**Severity:** HIGH
|
||||
**OWASP:** A05:2021 -- Security Misconfiguration
|
||||
**File:** `v1/src/middleware/rate_limit.py:200-206`
|
||||
**File:** `archive/v1/src/middleware/rate_limit.py:200-206`
|
||||
|
||||
**Description:**
|
||||
The `_get_client_ip` method trusts the `X-Forwarded-For` header without any validation. An attacker can spoof this header to bypass IP-based rate limiting entirely by rotating forged IP addresses on each request.
|
||||
|
||||
```python
|
||||
# v1/src/middleware/rate_limit.py:200-206
|
||||
# archive/v1/src/middleware/rate_limit.py:200-206
|
||||
def _get_client_ip(self, request: Request) -> str:
|
||||
forwarded_for = request.headers.get("X-Forwarded-For")
|
||||
if forwarded_for:
|
||||
@@ -99,17 +99,17 @@ def _get_client_ip(self, request: Request) -> str:
|
||||
**Severity:** HIGH
|
||||
**OWASP:** A09:2021 -- Security Logging and Monitoring Failures
|
||||
**Files:**
|
||||
- `v1/src/api/routers/pose.py:140-141` -- `detail=f"Pose estimation failed: {str(e)}"`
|
||||
- `v1/src/api/routers/pose.py:176-177` -- `detail=f"Pose analysis failed: {str(e)}"`
|
||||
- `v1/src/api/routers/stream.py:297` -- `detail=f"Failed to get stream status: {str(e)}"`
|
||||
- All exception handlers in `v1/src/api/routers/stream.py` (lines 326, 351, 404, 442, 463)
|
||||
- `v1/src/middleware/error_handler.py:101-104` -- traceback in development mode
|
||||
- `archive/v1/src/api/routers/pose.py:140-141` -- `detail=f"Pose estimation failed: {str(e)}"`
|
||||
- `archive/v1/src/api/routers/pose.py:176-177` -- `detail=f"Pose analysis failed: {str(e)}"`
|
||||
- `archive/v1/src/api/routers/stream.py:297` -- `detail=f"Failed to get stream status: {str(e)}"`
|
||||
- All exception handlers in `archive/v1/src/api/routers/stream.py` (lines 326, 351, 404, 442, 463)
|
||||
- `archive/v1/src/middleware/error_handler.py:101-104` -- traceback in development mode
|
||||
|
||||
**Description:**
|
||||
Multiple API endpoints directly interpolate Python exception messages into HTTP error responses. While the global error handler in `error_handler.py` correctly suppresses details in production, the per-endpoint `HTTPException` handlers bypass this and always expose `str(e)` regardless of environment.
|
||||
|
||||
```python
|
||||
# v1/src/api/routers/pose.py:140-141
|
||||
# archive/v1/src/api/routers/pose.py:140-141
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Pose estimation failed: {str(e)}"
|
||||
@@ -130,14 +130,14 @@ raise HTTPException(
|
||||
**Severity:** MEDIUM
|
||||
**OWASP:** A05:2021 -- Security Misconfiguration
|
||||
**Files:**
|
||||
- `v1/src/config/settings.py:33-34` -- defaults: `cors_origins=["*"]`, `cors_allow_credentials=True`
|
||||
- `v1/src/middleware/cors.py:255-256` -- development config combines `allow_origins=["*"]` + `allow_credentials=True`
|
||||
- `archive/v1/src/config/settings.py:33-34` -- defaults: `cors_origins=["*"]`, `cors_allow_credentials=True`
|
||||
- `archive/v1/src/middleware/cors.py:255-256` -- development config combines `allow_origins=["*"]` + `allow_credentials=True`
|
||||
|
||||
**Description:**
|
||||
The default settings allow CORS from all origins (`*`) with credentials (`allow_credentials=True`). Per the CORS specification, `Access-Control-Allow-Origin: *` cannot be used with `Access-Control-Allow-Credentials: true`. However, the `CORSMiddleware` implementation echoes the requesting origin header verbatim, effectively granting credentialed access from any origin.
|
||||
|
||||
```python
|
||||
# v1/src/middleware/cors.py:255-256 (development_config)
|
||||
# archive/v1/src/middleware/cors.py:255-256 (development_config)
|
||||
"allow_origins": ["*"],
|
||||
"allow_credentials": True,
|
||||
```
|
||||
@@ -158,8 +158,8 @@ The `validate_cors_config` function at line 354 correctly flags this combination
|
||||
**Severity:** MEDIUM
|
||||
**OWASP:** A04:2021 -- Insecure Design
|
||||
**Files:**
|
||||
- `v1/src/api/routers/stream.py:127-128` -- `message = await websocket.receive_text()` with no size limit
|
||||
- `v1/src/api/websocket/connection_manager.py` -- no `max_size` configuration
|
||||
- `archive/v1/src/api/routers/stream.py:127-128` -- `message = await websocket.receive_text()` with no size limit
|
||||
- `archive/v1/src/api/websocket/connection_manager.py` -- no `max_size` configuration
|
||||
|
||||
**Description:**
|
||||
WebSocket endpoints accept incoming messages of arbitrary size. The `receive_text()` call at `stream.py:127` has no size limit, allowing a client to send extremely large messages that consume server memory.
|
||||
@@ -179,7 +179,7 @@ Additionally, the `ConnectionManager` does not enforce a maximum number of conne
|
||||
|
||||
**Severity:** MEDIUM
|
||||
**OWASP:** A07:2021 -- Identification and Authentication Failures
|
||||
**File:** `v1/src/api/middleware/auth.py:246-252`
|
||||
**File:** `archive/v1/src/api/middleware/auth.py:246-252`
|
||||
|
||||
**Description:**
|
||||
The `TokenBlacklist` class clears all blacklisted tokens every hour, regardless of their actual expiry time. This means:
|
||||
@@ -187,7 +187,7 @@ The `TokenBlacklist` class clears all blacklisted tokens every hour, regardless
|
||||
2. Tokens revoked just before a clear cycle have nearly zero effective blacklist time.
|
||||
|
||||
```python
|
||||
# v1/src/api/middleware/auth.py:246-252
|
||||
# archive/v1/src/api/middleware/auth.py:246-252
|
||||
def _cleanup_if_needed(self):
|
||||
now = datetime.utcnow()
|
||||
if (now - self._last_cleanup).total_seconds() > self._cleanup_interval:
|
||||
@@ -306,8 +306,8 @@ if (s_cfg.seed_token[0] != '\0') {
|
||||
**Severity:** MEDIUM
|
||||
**OWASP:** A04:2021 -- Insecure Design
|
||||
**Files:**
|
||||
- `v1/src/api/middleware/rate_limit.py:28-29` -- `self.request_counts = defaultdict(lambda: deque())`
|
||||
- `v1/src/middleware/rate_limit.py:132` -- `self._sliding_windows: Dict[str, SlidingWindowCounter] = {}`
|
||||
- `archive/v1/src/api/middleware/rate_limit.py:28-29` -- `self.request_counts = defaultdict(lambda: deque())`
|
||||
- `archive/v1/src/middleware/rate_limit.py:132` -- `self._sliding_windows: Dict[str, SlidingWindowCounter] = {}`
|
||||
|
||||
**Description:**
|
||||
Both rate limiter implementations store per-client sliding window data in unbounded in-memory dictionaries. An attacker sending requests from many spoofed IPs (see HIGH-002) can create millions of entries, each containing a `deque` of timestamps. The cleanup tasks run only periodically (every 5 minutes or on-demand) and cannot keep pace with a high-rate attack.
|
||||
@@ -349,8 +349,8 @@ While marked with a comment indicating it should be changed, this file is checke
|
||||
**Severity:** LOW
|
||||
**OWASP:** A01:2021 -- Broken Access Control
|
||||
**Files:**
|
||||
- `v1/src/middleware/auth.py:298-299` -- `response.headers["X-User"] = user_info["username"]` and `response.headers["X-User-Roles"] = ",".join(user_info["roles"])`
|
||||
- `v1/src/api/middleware/auth.py:111` -- `response.headers["X-User-ID"] = request.state.user.get("id", "")`
|
||||
- `archive/v1/src/middleware/auth.py:298-299` -- `response.headers["X-User"] = user_info["username"]` and `response.headers["X-User-Roles"] = ",".join(user_info["roles"])`
|
||||
- `archive/v1/src/api/middleware/auth.py:111` -- `response.headers["X-User-ID"] = request.state.user.get("id", "")`
|
||||
|
||||
**Description:**
|
||||
Authenticated user information (username, roles, user ID) is included in HTTP response headers. These headers are visible to any intermediary (CDN, reverse proxy, browser extensions) and in browser developer tools.
|
||||
@@ -380,7 +380,7 @@ Replace all instances of `datetime.utcnow()` with `datetime.now(datetime.timezon
|
||||
|
||||
**Severity:** LOW
|
||||
**OWASP:** A02:2021 -- Cryptographic Failures
|
||||
**File:** `v1/src/config/settings.py:30` -- `jwt_algorithm: str = Field(default="HS256")`
|
||||
**File:** `archive/v1/src/config/settings.py:30` -- `jwt_algorithm: str = Field(default="HS256")`
|
||||
|
||||
**Description:**
|
||||
The default JWT algorithm is HS256 (HMAC-SHA256), a symmetric algorithm. This means the same secret is used for both signing and verification, requiring the secret to be distributed to every service that needs to verify tokens. For multi-service architectures, asymmetric algorithms (RS256, ES256) are preferred.
|
||||
@@ -398,7 +398,7 @@ Additionally, the `jwt_algorithm` setting is not validated against a safe algori
|
||||
|
||||
**Severity:** LOW
|
||||
**OWASP:** A07:2021 -- Identification and Authentication Failures
|
||||
**File:** `v1/src/middleware/auth.py:115` -- `create_user()` method
|
||||
**File:** `archive/v1/src/middleware/auth.py:115` -- `create_user()` method
|
||||
|
||||
**Description:**
|
||||
The `create_user()` method accepts any password without minimum length, complexity, or entropy requirements. Test credentials in `v1/test_auth_rate_limit.py:21-23` demonstrate weak passwords ("admin123", "user123").
|
||||
@@ -460,7 +460,7 @@ This is a positive finding reflecting good security practices.
|
||||
| `paramiko>=3.0.0` | LOW -- SSH library. Ensure latest minor version for CVE patches. |
|
||||
| `fastapi>=0.95.0` | LOW -- Version floor is old. Pin to latest stable for security patches. |
|
||||
|
||||
**Recommendation:** Run `pip audit` or `safety check` against the locked dependency file (`v1/requirements-lock.txt`) to identify known CVEs.
|
||||
**Recommendation:** Run `pip audit` or `safety check` against the locked dependency file (`archive/v1/requirements-lock.txt`) to identify known CVEs.
|
||||
|
||||
### Rust Dependencies (`Cargo.toml`)
|
||||
|
||||
@@ -484,11 +484,11 @@ The following areas demonstrate security-conscious design:
|
||||
|
||||
3. **RVF build hash validation** (`firmware/esp32-csi-node/main/rvf_parser.c:126-137`): SHA-256 hash of the WASM payload is verified against the manifest before loading, preventing tampered module execution.
|
||||
|
||||
4. **Password hashing with bcrypt** (`v1/src/middleware/auth.py:21`): Proper use of `passlib` with `bcrypt` scheme.
|
||||
4. **Password hashing with bcrypt** (`archive/v1/src/middleware/auth.py:21`): Proper use of `passlib` with `bcrypt` scheme.
|
||||
|
||||
5. **Protected user fields** (`v1/src/middleware/auth.py:139`): `update_user()` prevents modification of `username`, `created_at`, and `hashed_password`.
|
||||
5. **Protected user fields** (`archive/v1/src/middleware/auth.py:139`): `update_user()` prevents modification of `username`, `created_at`, and `hashed_password`.
|
||||
|
||||
6. **Production error suppression** (`v1/src/middleware/error_handler.py:214-218`): The centralized error handler correctly suppresses internal details in production mode.
|
||||
6. **Production error suppression** (`archive/v1/src/middleware/error_handler.py:214-218`): The centralized error handler correctly suppresses internal details in production mode.
|
||||
|
||||
7. **No hardcoded secrets in source** (verified via entropy-based search across entire repository): No API keys, passwords, or tokens found in source files (the test script placeholder at `test_auth_rate_limit.py:26` is marked as requiring replacement).
|
||||
|
||||
@@ -502,20 +502,20 @@ The following areas demonstrate security-conscious design:
|
||||
|
||||
## Files Examined
|
||||
|
||||
### Python (v1/src/)
|
||||
- `v1/src/middleware/auth.py` (457 lines) -- JWT auth, user management, middleware
|
||||
- `v1/src/middleware/rate_limit.py` (465 lines) -- Rate limiting with sliding window
|
||||
- `v1/src/middleware/cors.py` (375 lines) -- CORS middleware and validation
|
||||
- `v1/src/middleware/error_handler.py` (505 lines) -- Error handling middleware
|
||||
- `v1/src/api/middleware/auth.py` (303 lines) -- API-layer JWT auth
|
||||
- `v1/src/api/middleware/rate_limit.py` (326 lines) -- API-layer rate limiting
|
||||
- `v1/src/api/websocket/connection_manager.py` (461 lines) -- WebSocket manager
|
||||
- `v1/src/api/websocket/pose_stream.py` (384 lines) -- Pose streaming handler
|
||||
- `v1/src/api/routers/pose.py` (420 lines) -- Pose API endpoints
|
||||
- `v1/src/api/routers/stream.py` (465 lines) -- Streaming API endpoints
|
||||
- `v1/src/config/settings.py` (436 lines) -- Application settings
|
||||
- `v1/src/sensing/rssi_collector.py` (partial) -- Subprocess usage review
|
||||
- `v1/src/tasks/backup.py` (partial) -- Subprocess command construction
|
||||
### Python (archive/v1/src/)
|
||||
- `archive/v1/src/middleware/auth.py` (457 lines) -- JWT auth, user management, middleware
|
||||
- `archive/v1/src/middleware/rate_limit.py` (465 lines) -- Rate limiting with sliding window
|
||||
- `archive/v1/src/middleware/cors.py` (375 lines) -- CORS middleware and validation
|
||||
- `archive/v1/src/middleware/error_handler.py` (505 lines) -- Error handling middleware
|
||||
- `archive/v1/src/api/middleware/auth.py` (303 lines) -- API-layer JWT auth
|
||||
- `archive/v1/src/api/middleware/rate_limit.py` (326 lines) -- API-layer rate limiting
|
||||
- `archive/v1/src/api/websocket/connection_manager.py` (461 lines) -- WebSocket manager
|
||||
- `archive/v1/src/api/websocket/pose_stream.py` (384 lines) -- Pose streaming handler
|
||||
- `archive/v1/src/api/routers/pose.py` (420 lines) -- Pose API endpoints
|
||||
- `archive/v1/src/api/routers/stream.py` (465 lines) -- Streaming API endpoints
|
||||
- `archive/v1/src/config/settings.py` (436 lines) -- Application settings
|
||||
- `archive/v1/src/sensing/rssi_collector.py` (partial) -- Subprocess usage review
|
||||
- `archive/v1/src/tasks/backup.py` (partial) -- Subprocess command construction
|
||||
- `v1/test_auth_rate_limit.py` (partial) -- Test credentials review
|
||||
|
||||
### Rust (v2/)
|
||||
|
||||
@@ -352,16 +352,16 @@ pub fn run(&self, csi_input: &Tensor) -> NnResult<DensePoseOutput> {
|
||||
|
||||
| File | Lines | Role |
|
||||
|------|-------|------|
|
||||
| `v1/src/core/csi_processor.py` | 467 | CSI processing pipeline |
|
||||
| `v1/src/services/pose_service.py` | 200+ | Pose estimation service |
|
||||
| `v1/src/api/websocket/connection_manager.py` | 461 | WebSocket management |
|
||||
| `v1/src/sensing/feature_extractor.py` | 150+ | RSSI feature extraction |
|
||||
| `archive/v1/src/core/csi_processor.py` | 467 | CSI processing pipeline |
|
||||
| `archive/v1/src/services/pose_service.py` | 200+ | Pose estimation service |
|
||||
| `archive/v1/src/api/websocket/connection_manager.py` | 461 | WebSocket management |
|
||||
| `archive/v1/src/sensing/feature_extractor.py` | 150+ | RSSI feature extraction |
|
||||
|
||||
---
|
||||
|
||||
### FINDING PERF-PY01: Doppler Feature Extraction -- list() Conversion of deque [CRITICAL]
|
||||
|
||||
**File**: `v1/src/core/csi_processor.py`
|
||||
**File**: `archive/v1/src/core/csi_processor.py`
|
||||
**Lines**: 412-414
|
||||
|
||||
```python
|
||||
@@ -391,7 +391,7 @@ class CircularBuffer:
|
||||
|
||||
### FINDING PERF-PY02: CSI Preprocessing Creates 3 New CSIData Objects per Frame [HIGH]
|
||||
|
||||
**File**: `v1/src/core/csi_processor.py`
|
||||
**File**: `archive/v1/src/core/csi_processor.py`
|
||||
**Lines**: 118-377
|
||||
|
||||
The preprocessing pipeline creates a new CSIData object at each step:
|
||||
@@ -417,7 +417,7 @@ Each CSIData construction copies metadata via `{**csi_data.metadata, 'key': True
|
||||
|
||||
### FINDING PERF-PY03: Correlation Matrix -- Full np.corrcoef on Every Frame [MEDIUM]
|
||||
|
||||
**File**: `v1/src/core/csi_processor.py`
|
||||
**File**: `archive/v1/src/core/csi_processor.py`
|
||||
**Lines**: 391-395
|
||||
|
||||
```python
|
||||
@@ -436,7 +436,7 @@ def _extract_correlation_features(self, csi_data: CSIData) -> np.ndarray:
|
||||
|
||||
### FINDING PERF-PY04: WebSocket Broadcast -- Sequential Send to All Clients [MEDIUM]
|
||||
|
||||
**File**: `v1/src/api/websocket/connection_manager.py`
|
||||
**File**: `archive/v1/src/api/websocket/connection_manager.py`
|
||||
**Lines**: 230-264
|
||||
|
||||
```python
|
||||
@@ -461,7 +461,7 @@ results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
|
||||
### FINDING PERF-PY05: get_recent_history -- Copies Entire History [LOW]
|
||||
|
||||
**File**: `v1/src/core/csi_processor.py`
|
||||
**File**: `archive/v1/src/core/csi_processor.py`
|
||||
**Lines**: 284-297
|
||||
|
||||
```python
|
||||
|
||||
@@ -14,7 +14,7 @@ The wifi-densepose project contains **3,353 total test functions** across three
|
||||
| Stack | Test Functions | Files | Frameworks |
|
||||
|-------|---------------|-------|------------|
|
||||
| Rust (inline + integration) | 2,658 | 292 source files + 16 integration test files | `#[test]`, Rust built-in |
|
||||
| Python (v1/tests/) | 491 | 30 test files | pytest, pytest-asyncio |
|
||||
| Python (archive/v1/tests/) | 491 | 30 test files | pytest, pytest-asyncio |
|
||||
| Mobile (ui/mobile) | 204 | 25 test files | Jest, React Testing Library |
|
||||
| **Total** | **3,353** | **363** | |
|
||||
|
||||
@@ -26,7 +26,7 @@ The wifi-densepose project contains **3,353 total test functions** across three
|
||||
|
||||
---
|
||||
|
||||
## 1. Python Test Suite Analysis (v1/tests/)
|
||||
## 1. Python Test Suite Analysis (archive/v1/tests/)
|
||||
|
||||
### 1.1 Test Distribution
|
||||
|
||||
@@ -229,7 +229,7 @@ All 14 tests use `MockPoseModel` with `asyncio.sleep()` simulating inference tim
|
||||
|
||||
### 1.10 Test Infrastructure Quality
|
||||
|
||||
**Fixtures (`v1/tests/fixtures/csi_data.py`):**
|
||||
**Fixtures (`archive/v1/tests/fixtures/csi_data.py`):**
|
||||
|
||||
Well-designed `CSIDataGenerator` class (487 lines) with:
|
||||
- Multiple scenario generators (empty room, single person, multi-person)
|
||||
@@ -238,7 +238,7 @@ Well-designed `CSIDataGenerator` class (487 lines) with:
|
||||
- Time series generation
|
||||
- Validation utilities (`validate_csi_sample`)
|
||||
|
||||
**Mocks (`v1/tests/mocks/hardware_mocks.py`):**
|
||||
**Mocks (`archive/v1/tests/mocks/hardware_mocks.py`):**
|
||||
|
||||
Comprehensive mock infrastructure (716 lines) including:
|
||||
- `MockWiFiRouter` with realistic CSI streaming
|
||||
@@ -448,9 +448,9 @@ This is the best-tested service in the mobile suite.
|
||||
|
||||
**High maintenance cost files:**
|
||||
|
||||
1. `v1/tests/mocks/hardware_mocks.py` (716 lines) -- Complex mock infrastructure that must evolve with the production code. Any hardware interface change requires updating this file.
|
||||
1. `archive/v1/tests/mocks/hardware_mocks.py` (716 lines) -- Complex mock infrastructure that must evolve with the production code. Any hardware interface change requires updating this file.
|
||||
|
||||
2. `v1/tests/fixtures/csi_data.py` (487 lines) -- Rich data generation but duplicates some logic from the production `SimulatedCollector`.
|
||||
2. `archive/v1/tests/fixtures/csi_data.py` (487 lines) -- Rich data generation but duplicates some logic from the production `SimulatedCollector`.
|
||||
|
||||
3. The 5 CSI extractor test files collectively contain ~3,000 lines of test code for a single module. Merging to one file would reduce this to ~600 lines.
|
||||
|
||||
@@ -468,8 +468,8 @@ This is the best-tested service in the mobile suite.
|
||||
|
||||
| File | Why It's Good |
|
||||
|------|---------------|
|
||||
| `v1/tests/unit/test_sensing.py` | 45 tests with mathematical rigor, known-signal validation, domain-specific edge cases, cross-receiver agreement, band isolation. No mocks for core logic. |
|
||||
| `v1/tests/unit/test_esp32_binary_parser.py` | Real UDP socket testing, struct-level binary validation, ADR-018 compliance. Tests actual I/Q to amplitude/phase math. |
|
||||
| `archive/v1/tests/unit/test_sensing.py` | 45 tests with mathematical rigor, known-signal validation, domain-specific edge cases, cross-receiver agreement, band isolation. No mocks for core logic. |
|
||||
| `archive/v1/tests/unit/test_esp32_binary_parser.py` | Real UDP socket testing, struct-level binary validation, ADR-018 compliance. Tests actual I/Q to amplitude/phase math. |
|
||||
| `v2/.../tests/validation_test.rs` | Physics-based validation (Doppler, phase unwrapping, spectral analysis). Tests prove algorithm correctness, not just non-failure. |
|
||||
| `v2/.../tests/test_losses.rs` | Deterministic data, feature-gated, tests mathematical properties (zero loss for identical inputs, non-zero for mismatched). |
|
||||
| `ui/mobile/.../utils/ringBuffer.test.ts` | Comprehensive boundary testing (NaN, Infinity, 0, negative, overflow). Tests copy semantics. |
|
||||
@@ -478,10 +478,10 @@ This is the best-tested service in the mobile suite.
|
||||
|
||||
| File | Issues |
|
||||
|------|--------|
|
||||
| `v1/tests/performance/test_inference_speed.py` | Tests `asyncio.sleep()` accuracy, not model performance. `MockPoseModel` simulates inference with sleep. |
|
||||
| `v1/tests/e2e/test_healthcare_scenario.py` | Not a real E2E test -- defines its own mock classes. Test names contain stale "should_fail_initially" text. |
|
||||
| `v1/tests/unit/test_csi_processor_tdd.py` | 14/25 tests mock the SUT's own private methods. Tests verify mock calls, not behavior. |
|
||||
| `v1/tests/unit/test_phase_sanitizer_tdd.py` | 12/31 tests mock internal methods. Same anti-pattern as csi_processor_tdd. |
|
||||
| `archive/v1/tests/performance/test_inference_speed.py` | Tests `asyncio.sleep()` accuracy, not model performance. `MockPoseModel` simulates inference with sleep. |
|
||||
| `archive/v1/tests/e2e/test_healthcare_scenario.py` | Not a real E2E test -- defines its own mock classes. Test names contain stale "should_fail_initially" text. |
|
||||
| `archive/v1/tests/unit/test_csi_processor_tdd.py` | 14/25 tests mock the SUT's own private methods. Tests verify mock calls, not behavior. |
|
||||
| `archive/v1/tests/unit/test_phase_sanitizer_tdd.py` | 12/31 tests mock internal methods. Same anti-pattern as csi_processor_tdd. |
|
||||
| `ui/mobile/.../components/GaugeArc.test.tsx` | All 4 tests are `expect(toJSON()).not.toBeNull()` -- smoke tests with no behavioral verification. |
|
||||
|
||||
---
|
||||
|
||||
@@ -31,18 +31,18 @@ The WiFi-DensePose system demonstrates strong architectural foundations with a w
|
||||
### Key Findings
|
||||
|
||||
**Strengths:**
|
||||
- Comprehensive error handling middleware with structured error responses, request IDs, and environment-aware detail levels (`v1/src/middleware/error_handler.py`)
|
||||
- Comprehensive error handling middleware with structured error responses, request IDs, and environment-aware detail levels (`archive/v1/src/middleware/error_handler.py`)
|
||||
- Robust WebSocket reconnection with exponential backoff and automatic simulation fallback in the mobile app (`ui/mobile/src/services/ws.service.ts`)
|
||||
- Well-designed health check architecture with component-level status, readiness probes, and liveness endpoints (`v1/src/api/routers/health.py`)
|
||||
- Strong input validation on API models with Pydantic, including range constraints and clear field descriptions (`v1/src/api/routers/pose.py`)
|
||||
- Well-designed health check architecture with component-level status, readiness probes, and liveness endpoints (`archive/v1/src/api/routers/health.py`)
|
||||
- Strong input validation on API models with Pydantic, including range constraints and clear field descriptions (`archive/v1/src/api/routers/pose.py`)
|
||||
- Persistent settings with AsyncStorage in the mobile app, surviving app restarts (`ui/mobile/src/stores/settingsStore.ts`)
|
||||
- Server URL validation with test-before-save workflow in mobile settings (`ui/mobile/src/screens/SettingsScreen/ServerUrlInput.tsx`)
|
||||
|
||||
**Critical Issues:**
|
||||
- API documentation is disabled in production (`docs_url=None`, `redoc_url=None` when `is_production=True`), leaving production API consumers without discoverability (in `v1/src/api/main.py` line 146-148)
|
||||
- No user-facing progress indicator during calibration -- the calibration endpoint returns an estimated duration but there is no polling endpoint progress beyond percentage (`v1/src/api/routers/pose.py` lines 320-361)
|
||||
- Rate limit responses lack a human-readable `Retry-After` message body; the client receives a bare `"Rate limit exceeded"` string with retry information only in HTTP headers (`v1/src/middleware/rate_limit.py` line 323)
|
||||
- CLI `status` command uses emoji/Unicode characters that break in terminals without UTF-8 support (`v1/src/commands/status.py` lines 360-474)
|
||||
- API documentation is disabled in production (`docs_url=None`, `redoc_url=None` when `is_production=True`), leaving production API consumers without discoverability (in `archive/v1/src/api/main.py` line 146-148)
|
||||
- No user-facing progress indicator during calibration -- the calibration endpoint returns an estimated duration but there is no polling endpoint progress beyond percentage (`archive/v1/src/api/routers/pose.py` lines 320-361)
|
||||
- Rate limit responses lack a human-readable `Retry-After` message body; the client receives a bare `"Rate limit exceeded"` string with retry information only in HTTP headers (`archive/v1/src/middleware/rate_limit.py` line 323)
|
||||
- CLI `status` command uses emoji/Unicode characters that break in terminals without UTF-8 support (`archive/v1/src/commands/status.py` lines 360-474)
|
||||
- Mobile app `MainTabs.tsx` passes an inline arrow function as the `component` prop to `Tab.Screen` (line 130), causing unnecessary re-renders on every parent render cycle
|
||||
|
||||
**Top 3 Recommendations:**
|
||||
@@ -166,7 +166,7 @@ WS /api/v1/stream/events - Event stream
|
||||
|
||||
### 4.2 Error Handling (Score: 85/100)
|
||||
|
||||
The `ErrorHandler` class in `v1/src/middleware/error_handler.py` is well-designed:
|
||||
The `ErrorHandler` class in `archive/v1/src/middleware/error_handler.py` is well-designed:
|
||||
|
||||
**Strengths:**
|
||||
- Structured error responses with consistent format: `{ "error": { "code": "...", "message": "...", "timestamp": "...", "request_id": "..." } }`
|
||||
@@ -401,7 +401,7 @@ The `ServerUrlInput` component in the Settings screen provides:
|
||||
|
||||
**Strengths:**
|
||||
- Rust workspace has 1,031+ tests with a single command: `cargo test --workspace --no-default-features`
|
||||
- Deterministic proof verification via `python v1/data/proof/verify.py` with SHA-256 hash checking
|
||||
- Deterministic proof verification via `python archive/v1/data/proof/verify.py` with SHA-256 hash checking
|
||||
- Mobile app has comprehensive test coverage with tests for components, hooks, screens, services, stores, and utilities
|
||||
- Witness bundle verification with `VERIFY.sh` providing 7/7 pass/fail attestation
|
||||
|
||||
@@ -706,20 +706,20 @@ The `provision.py` script in `firmware/esp32-csi-node/` handles WiFi credential
|
||||
This Quality Experience analysis was performed by examining source code across all touchpoints of the WiFi-DensePose system. Files analyzed include:
|
||||
|
||||
**API Layer (9 files):**
|
||||
- `v1/src/api/main.py` -- FastAPI application setup, middleware configuration, exception handlers
|
||||
- `v1/src/api/routers/health.py` -- Health check endpoints
|
||||
- `v1/src/api/routers/pose.py` -- Pose estimation endpoints
|
||||
- `v1/src/api/routers/stream.py` -- WebSocket streaming endpoints
|
||||
- `v1/src/api/websocket/connection_manager.py` -- WebSocket connection lifecycle
|
||||
- `v1/src/api/dependencies.py` -- Dependency injection, authentication, authorization
|
||||
- `v1/src/middleware/error_handler.py` -- Error handling middleware
|
||||
- `v1/src/middleware/rate_limit.py` -- Rate limiting middleware
|
||||
- `archive/v1/src/api/main.py` -- FastAPI application setup, middleware configuration, exception handlers
|
||||
- `archive/v1/src/api/routers/health.py` -- Health check endpoints
|
||||
- `archive/v1/src/api/routers/pose.py` -- Pose estimation endpoints
|
||||
- `archive/v1/src/api/routers/stream.py` -- WebSocket streaming endpoints
|
||||
- `archive/v1/src/api/websocket/connection_manager.py` -- WebSocket connection lifecycle
|
||||
- `archive/v1/src/api/dependencies.py` -- Dependency injection, authentication, authorization
|
||||
- `archive/v1/src/middleware/error_handler.py` -- Error handling middleware
|
||||
- `archive/v1/src/middleware/rate_limit.py` -- Rate limiting middleware
|
||||
|
||||
**CLI Layer (4 files):**
|
||||
- `v1/src/cli.py` -- Click CLI entry point
|
||||
- `v1/src/commands/start.py` -- Server start command
|
||||
- `v1/src/commands/stop.py` -- Server stop command
|
||||
- `v1/src/commands/status.py` -- Server status command
|
||||
- `archive/v1/src/cli.py` -- Click CLI entry point
|
||||
- `archive/v1/src/commands/start.py` -- Server start command
|
||||
- `archive/v1/src/commands/stop.py` -- Server stop command
|
||||
- `archive/v1/src/commands/status.py` -- Server status command
|
||||
|
||||
**Mobile Layer (15 files):**
|
||||
- `ui/mobile/src/screens/LiveScreen/index.tsx` -- Live visualization screen
|
||||
|
||||
@@ -75,7 +75,7 @@ The wifi-densepose project is an ambitious WiFi-based human pose estimation syst
|
||||
**Test Ideas:**
|
||||
| # | Priority | Test Idea | Automation |
|
||||
|---|----------|-----------|------------|
|
||||
| S-08 | P0 | Run `python v1/data/proof/verify.py` in CI on every PR that touches `v1/src/core/` or `v1/src/hardware/` to catch proof-breaking changes | CI |
|
||||
| S-08 | P0 | Run `python archive/v1/data/proof/verify.py` in CI on every PR that touches `archive/v1/src/core/` or `archive/v1/src/hardware/` to catch proof-breaking changes | CI |
|
||||
| S-09 | P2 | Pin numpy/scipy versions in requirements.txt and confirm `verify.py --generate-hash` produces the same hash across Python 3.10, 3.11, and 3.12 | Integration |
|
||||
|
||||
---
|
||||
@@ -222,7 +222,7 @@ The Rust `Esp32CsiParser::parse_frame` takes raw bytes and returns structured `C
|
||||
|
||||
#### D3: Proof Data Integrity
|
||||
|
||||
**Finding:** The proof-of-reality system (`v1/data/proof/verify.py`) is a deterministic pipeline verification tool. It feeds 1,000 synthetic CSI frames through the production CSI processor, hashes the output with SHA-256, and compares against a published hash. This is a strong engineering practice.
|
||||
**Finding:** The proof-of-reality system (`archive/v1/data/proof/verify.py`) is a deterministic pipeline verification tool. It feeds 1,000 synthetic CSI frames through the production CSI processor, hashes the output with SHA-256, and compares against a published hash. This is a strong engineering practice.
|
||||
|
||||
**Risk: LOW**
|
||||
- The proof only exercises the Python v1 pipeline. The Rust port has no equivalent proof-of-reality check.
|
||||
@@ -448,7 +448,7 @@ The ESP32-S3 is the primary sensing node. The mmWave sensors are auxiliary.
|
||||
**Test Ideas:**
|
||||
| # | Priority | Test Idea | Automation |
|
||||
|---|----------|-----------|------------|
|
||||
| O-06 | P0 | Run the complete developer setup workflow from a clean Ubuntu 22.04 VM: clone, install deps, `cargo test --workspace --no-default-features`, `python v1/data/proof/verify.py` -- measure total setup time and document any manual steps | Human Exploration |
|
||||
| O-06 | P0 | Run the complete developer setup workflow from a clean Ubuntu 22.04 VM: clone, install deps, `cargo test --workspace --no-default-features`, `python archive/v1/data/proof/verify.py` -- measure total setup time and document any manual steps | Human Exploration |
|
||||
| O-07 | P1 | Simulate a MAT scan with 5 survivors at varying signal strengths (strong, weak, borderline) and confirm the triage classification matches expected START protocol categories | Integration |
|
||||
|
||||
#### O4: Extreme Use
|
||||
|
||||
@@ -287,22 +287,22 @@
|
||||
| 1 | `firmware/main/wasm_runtime.c` | Firmware | 867 | **Critical** | 0.98 | WASM execution on embedded device, untested attack surface |
|
||||
| 2 | `firmware/main/ota_update.c` | Firmware | 266 | **Critical** | 0.97 | OTA firmware update -- integrity/authentication critical |
|
||||
| 3 | `firmware/main/swarm_bridge.c` | Firmware | 327 | **Critical** | 0.96 | Multi-node mesh networking, untested protocol |
|
||||
| 4 | `v1/src/services/pose_service.py` | Python | 855 | **Critical** | 0.95 | Core production path, highest complexity, no unit tests |
|
||||
| 5 | `v1/src/middleware/auth.py` | Python | 456 | **Critical** | 0.94 | Authentication -- security-critical, no unit tests |
|
||||
| 6 | `v1/src/api/websocket/connection_manager.py` | Python | 460 | **Critical** | 0.93 | WebSocket lifecycle, connection state, no tests |
|
||||
| 4 | `archive/v1/src/services/pose_service.py` | Python | 855 | **Critical** | 0.95 | Core production path, highest complexity, no unit tests |
|
||||
| 5 | `archive/v1/src/middleware/auth.py` | Python | 456 | **Critical** | 0.94 | Authentication -- security-critical, no unit tests |
|
||||
| 6 | `archive/v1/src/api/websocket/connection_manager.py` | Python | 460 | **Critical** | 0.93 | WebSocket lifecycle, connection state, no tests |
|
||||
| 7 | `firmware/main/mmwave_sensor.c` | Firmware | 571 | **Critical** | 0.92 | 60GHz FMCW sensor driver, hardware-critical |
|
||||
| 8 | `firmware/main/wasm_upload.c` | Firmware | 432 | **Critical** | 0.91 | OTA WASM upload, code injection risk |
|
||||
| 9 | `v1/src/services/orchestrator.py` | Python | 394 | **Critical** | 0.90 | Service lifecycle management, no tests |
|
||||
| 10 | `v1/src/database/connection.py` | Python | 639 | **Critical** | 0.89 | DB + Redis connection management, pooling |
|
||||
| 11 | `v1/src/middleware/error_handler.py` | Python | 504 | **High** | 0.87 | Global error handler, affects all requests |
|
||||
| 12 | `v1/src/tasks/monitoring.py` | Python | 771 | **High** | 0.86 | System monitoring, DB queries, async tasks |
|
||||
| 13 | `v1/src/services/hardware_service.py` | Python | 481 | **High** | 0.85 | Hardware abstraction, device management |
|
||||
| 14 | `v1/src/middleware/rate_limit.py` | Python | 464 | **High** | 0.84 | Rate limiting -- DoS protection |
|
||||
| 15 | `v1/src/services/health_check.py` | Python | 464 | **High** | 0.83 | Health monitoring, dependency checks |
|
||||
| 16 | `v1/src/tasks/backup.py` | Python | 609 | **High** | 0.82 | Data backup operations |
|
||||
| 17 | `v1/src/tasks/cleanup.py` | Python | 597 | **High** | 0.81 | Data retention, cleanup logic |
|
||||
| 9 | `archive/v1/src/services/orchestrator.py` | Python | 394 | **Critical** | 0.90 | Service lifecycle management, no tests |
|
||||
| 10 | `archive/v1/src/database/connection.py` | Python | 639 | **Critical** | 0.89 | DB + Redis connection management, pooling |
|
||||
| 11 | `archive/v1/src/middleware/error_handler.py` | Python | 504 | **High** | 0.87 | Global error handler, affects all requests |
|
||||
| 12 | `archive/v1/src/tasks/monitoring.py` | Python | 771 | **High** | 0.86 | System monitoring, DB queries, async tasks |
|
||||
| 13 | `archive/v1/src/services/hardware_service.py` | Python | 481 | **High** | 0.85 | Hardware abstraction, device management |
|
||||
| 14 | `archive/v1/src/middleware/rate_limit.py` | Python | 464 | **High** | 0.84 | Rate limiting -- DoS protection |
|
||||
| 15 | `archive/v1/src/services/health_check.py` | Python | 464 | **High** | 0.83 | Health monitoring, dependency checks |
|
||||
| 16 | `archive/v1/src/tasks/backup.py` | Python | 609 | **High** | 0.82 | Data backup operations |
|
||||
| 17 | `archive/v1/src/tasks/cleanup.py` | Python | 597 | **High** | 0.81 | Data retention, cleanup logic |
|
||||
| 18 | `firmware/main/rvf_parser.c` | Firmware | 239 | **High** | 0.80 | Binary format parsing -- buffer overflow risk |
|
||||
| 19 | `v1/src/api/routers/pose.py` | Python | 419 | **High** | 0.79 | Pose API endpoint handlers |
|
||||
| 19 | `archive/v1/src/api/routers/pose.py` | Python | 419 | **High** | 0.79 | Pose API endpoint handlers |
|
||||
| 20 | `mobile/hooks/useWebViewBridge.ts` | Mobile | 30 | **High** | 0.78 | Native-WebView IPC bridge |
|
||||
|
||||
---
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
|
||||
| # | Issue | File(s) | Impact |
|
||||
|---|-------|---------|--------|
|
||||
| 1 | **Rate limiter bypass** -- trusts `X-Forwarded-For` without validation | `v1/src/middleware/rate_limit.py:200-206` | Any client can bypass rate limits via header spoofing |
|
||||
| 2 | **Exception details leaked** in HTTP responses regardless of environment | `v1/src/api/routers/pose.py:140`, `stream.py:297`, +5 others | Stack traces visible to attackers |
|
||||
| 3 | **WebSocket JWT in URL** -- tokens visible in logs, browser history, proxies | `v1/src/api/routers/stream.py:74`, `v1/src/middleware/auth.py:243` | Token exposure (CWE-598) |
|
||||
| 1 | **Rate limiter bypass** -- trusts `X-Forwarded-For` without validation | `archive/v1/src/middleware/rate_limit.py:200-206` | Any client can bypass rate limits via header spoofing |
|
||||
| 2 | **Exception details leaked** in HTTP responses regardless of environment | `archive/v1/src/api/routers/pose.py:140`, `stream.py:297`, +5 others | Stack traces visible to attackers |
|
||||
| 3 | **WebSocket JWT in URL** -- tokens visible in logs, browser history, proxies | `archive/v1/src/api/routers/stream.py:74`, `archive/v1/src/middleware/auth.py:243` | Token exposure (CWE-598) |
|
||||
| 4 | **Rust tests not in CI** -- 2,618 tests in largest codebase never run in pipeline | No `cargo test` in any GitHub Actions workflow | Regressions ship undetected |
|
||||
| 5 | **WebSocket path mismatch** -- mobile app sends to wrong endpoint | `ui/mobile/src/services/ws.service.ts:104` vs `constants/websocket.ts:1` | Mobile WebSocket connections fail silently |
|
||||
|
||||
@@ -39,16 +39,16 @@
|
||||
| 7 | **O(L*V) tomography voxel scan** per frame | `ruvsense/tomography.rs:345-383` | ~10ms wasted per frame; use DDA ray march for 5-10x speedup |
|
||||
| 8 | **Sequential neural inference** -- defeats GPU batching | `wifi-densepose-nn inference.rs:334-336` | 2-4x latency penalty |
|
||||
| 9 | **720 `.unwrap()` calls** in Rust production code | Across entire Rust workspace | Each is a potential panic in real-time/safety-critical paths |
|
||||
| 10 | **Python Doppler: 112KB alloc per frame** at 20Hz | `v1/src/core/csi_processor.py:412-414` | Converts deque -> list -> numpy every frame |
|
||||
| 10 | **Python Doppler: 112KB alloc per frame** at 20Hz | `archive/v1/src/core/csi_processor.py:412-414` | Converts deque -> list -> numpy every frame |
|
||||
|
||||
## P2 -- Fix This Quarter (Coverage + Safety)
|
||||
|
||||
| # | Issue | File(s) | Impact |
|
||||
|---|-------|---------|--------|
|
||||
| 11 | **11/12 Python modules untested** -- only CSI extraction has unit tests | `v1/src/services/`, `middleware/`, `database/`, `tasks/` | 12,280 LOC with zero unit tests |
|
||||
| 11 | **11/12 Python modules untested** -- only CSI extraction has unit tests | `archive/v1/src/services/`, `middleware/`, `database/`, `tasks/` | 12,280 LOC with zero unit tests |
|
||||
| 12 | **Firmware at 19% coverage** -- WASM runtime, OTA, swarm bridge untested | `firmware/esp32-csi-node/main/wasm_runtime.c` (867 LOC) | Security-critical code with no tests |
|
||||
| 13 | **MAT simulation fallback** -- disaster tool auto-falls back to simulated data | `ui/mobile/src/screens/MATScreen/index.tsx` | Risk of operators monitoring fake data during real incidents |
|
||||
| 14 | **Token blacklist never consulted** during auth | `v1/src/api/middleware/auth.py:246-252` | Revoked tokens remain valid |
|
||||
| 14 | **Token blacklist never consulted** during auth | `archive/v1/src/api/middleware/auth.py:246-252` | Revoked tokens remain valid |
|
||||
| 15 | **50ms frame budget never benchmarked** -- no latency CI gate | No benchmark harness exists | Real-time requirement is aspirational, not verified |
|
||||
|
||||
## P3 -- Technical Debt
|
||||
|
||||
Reference in New Issue
Block a user