mirror of
https://github.com/azaion/ui.git
synced 2026-06-22 02:51:11 +00:00
[AZ-501] [AZ-502] Cycle 2 Step 14 security audit + inline fixes
ci/woodpecker/push/build-arm Pipeline failed
ci/woodpecker/push/build-arm Pipeline failed
Security audit (5 phases) → reports under _docs/05_security/. AZ-501 (F-SAST-1, HIGH): Externalize hardcoded Google Geocode key from mission-planner/src/config.ts to VITE_GOOGLE_GEOCODE_KEY via new GeocodeService.ts; fail-soft warn when unset; STC-SEC1D static deny-list gate; +5 unit tests in tests/mission_planner_geocode.test.ts. AZ-502 (F-DEP-1, HIGH): Force vite>=6.4.2 and postcss>=8.5.10 via package.json overrides in both roots; clean reinstall clears all bun audit advisories. Test-spec sync (Step 12) + Update Docs (Step 13) deltas: AC-43, AC-44, NFT-SEC-09b, FT-P-61, FT-N-17, ripple log, batch_12 report. Pending user actions: revoke Google + OWM keys (AC-6 / AZ-499 AC-7). 229 PASS / 13 SKIP / 0 FAIL on static + fast suites. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -123,8 +123,8 @@ contract beautifully and accessibly".
|
||||
|----------------------|------------------------|
|
||||
| React 19 SPA (`src/`) | Suite backend services (`annotations/`, `flights/`, `admin/`, `detect/`, `loader/`, `gps-denied-{desktop,onboard}/`, `autopilot/`, `resource/`) |
|
||||
| `mission-planner/` port-source (NOT deployed) | Database (PostgreSQL — managed by individual suite services, not the UI) |
|
||||
| Static-bundle Dockerfile + nginx config | OpenWeatherMap public API (consumed directly by the SPA — security finding) |
|
||||
| Woodpecker CI pipeline (`.woodpecker/build-arm.yml`) | Map tile providers (OpenStreetMap, satellite tile URL via env) |
|
||||
| Static-bundle Dockerfile + nginx config | OpenWeatherMap public API (consumed by the main SPA via env-resolved key per AZ-448 / AZ-449; consumed by `mission-planner/` per AZ-499 — env-resolved key, fail-soft on unset, manual revocation of the previously-committed key tracked under AC-42) |
|
||||
| Woodpecker CI pipeline (`.woodpecker/build-arm.yml`) | Suite-internal `satellite-provider` service for map tiles (same-origin via nginx in production; env-resolved URL `VITE_SATELLITE_TILE_URL` per AZ-498). The legacy OpenStreetMap / Esri tile providers are NO LONGER consumed by the main SPA as of cycle 2 / 2026-05-12. |
|
||||
| | Identity provider (suite-internal — Admin API) |
|
||||
|
||||
**External systems**:
|
||||
@@ -139,9 +139,9 @@ contract beautifully and accessibly".
|
||||
| `gps-denied-desktop/`, `gps-denied-onboard/` | REST (via `/api/gps-denied-*/*`) | Outbound | GPS-Denied operations + Test Mode (SITL feed) |
|
||||
| `autopilot/` | REST (via `/api/autopilot/*`) | Outbound | Aircraft autopilot configuration (admin-side) |
|
||||
| `resource/` | REST (via `/api/resource/*`) | Outbound | Static resource fetch (icons, configs not bundled in the SPA) |
|
||||
| OpenStreetMap tile servers | HTTPS (Leaflet TileLayer) | Outbound | Map raster tiles (browser-direct, not via nginx proxy) |
|
||||
| Satellite tile provider | HTTPS (Leaflet TileLayer with env-configured URL) | Outbound | Satellite imagery (only consumed by mission-planner today) |
|
||||
| OpenWeatherMap | HTTPS (`api.openweathermap.org/data/2.5/onecall`) | Outbound | Wind data for flight planning. **Hardcoded API key in `flightPlanUtils.ts:60` — security finding to fix at Step 4.** |
|
||||
| Suite-internal `satellite-provider` service for satellite tiles | HTTPS (Leaflet TileLayer with env-configured URL `VITE_SATELLITE_TILE_URL`); same-origin in production via nginx; cookie auth (`crossOrigin="use-credentials"`) | Outbound (intra-suite) | Satellite map raster tiles. Replaces the previously-used OpenStreetMap and Esri ArcGIS World Imagery tile servers as of cycle 2 / 2026-05-12 (AZ-498) — air-gap restriction E1 satisfied without a stub. |
|
||||
| OpenWeatherMap (main SPA) | HTTPS (`api.openweathermap.org/data/2.5/onecall`) | Outbound | Wind data for flight planning. Env-resolved key + base URL via `VITE_OWM_API_KEY` / `VITE_OWM_BASE_URL` since AZ-448 / AZ-449. |
|
||||
| OpenWeatherMap (mission-planner) | HTTPS (`api.openweathermap.org/data/2.5/weather`) | Outbound | Wind data for the mission-planner port. Env-resolved key + base URL via `VITE_OWM_API_KEY` / `VITE_OWM_BASE_URL` since AZ-499; `getWeatherData(lat, lon)` returns `null` and issues NO fetch when the key is unset (fail-soft contract). The previously-committed literal `335799082893fad97fa36118b131f919` is defended against re-introduction by `STC-SEC1C` and tracked for manual OWM-dashboard revocation under AC-42. |
|
||||
|
||||
## 2. Technology Stack
|
||||
|
||||
@@ -170,7 +170,7 @@ contract beautifully and accessibly".
|
||||
|
||||
- **Static bundle only**: the UI ships zero server-side runtime. nginx serves `dist/` and reverse-proxies `/api/<service>/` to the matching suite service.
|
||||
- **ARM-first**: production target is ARM-class edge devices; CI builds ARM64 only today (no AMD64 image in the pipeline).
|
||||
- **Air-gapped friendly**: the SPA is bundled fully; only OpenWeatherMap and map tiles require internet. Field deployments will need an offline tile cache (not implemented).
|
||||
- **Air-gapped friendly**: the SPA is bundled fully. As of cycle 2 / 2026-05-12 (AZ-498), map tiles are served by the suite-internal `satellite-provider` service on the same origin via nginx — restriction E1 is satisfied for tiles without a stub. The only remaining direct-from-browser external dependency is OpenWeatherMap (env-resolved per AC-42; fail-soft when the key is unset). Field deployments that go fully air-gapped MUST set `VITE_OWM_API_KEY=""` (or omit it) so `getWeatherData` returns `null` instead of attempting an external fetch.
|
||||
- **No test framework**: legacy carry-over; the WPF `Azaion.Test` project tested utilities only; full test infrastructure is being built fresh under autodev.
|
||||
- **Bilingual UI required**: Ukrainian + English are mandatory per the legacy WPF UX. English-only SaaS-style copy is a regression — finding tracked.
|
||||
|
||||
@@ -272,14 +272,14 @@ contract beautifully and accessibly".
|
||||
| `08_admin/AdminPage` | `annotations/` + `admin/` + `flights/` | REST | Request-Response | `GET /api/annotations/classes` (read), `POST /api/admin/classes` (create), `DELETE /api/admin/classes/${id}` (delete — no ConfirmDialog, finding B4), `POST /api/admin/users`, `PATCH /api/admin/users/${id}` (deactivate), `GET /api/flights/aircrafts`, `PATCH /api/flights/aircrafts/${id}`. **Cross-service reads** — admin page reads aircraft from `flights/` and classes from `annotations/`. |
|
||||
| `09_settings/SettingsPage` | `annotations/` + `flights/` | REST | Request-Response | `GET/PUT /api/annotations/settings/system`, `GET/PUT /api/annotations/settings/directories`, `GET /api/flights/aircrafts`, `PATCH /api/flights/aircrafts/${id}`. **Settings endpoints route to `annotations/`**, NOT `admin/` as initially drafted. |
|
||||
| `05_flights/FlightsPage` | `flights/` | REST + SSE | Request-Response + Event | `GET /api/flights/aircrafts`, `GET /api/flights/${id}/waypoints`, **`createSSE('/api/flights/${id}/live-gps', ...)` — live-GPS SSE for aircraft telemetry**, `POST /api/flights`, `DELETE /api/flights/${id}`, `DELETE /api/flights/${id}/waypoints/${wpId}` (loop), `POST /api/flights/${id}/waypoints` (loop, lossy shape — finding #20). |
|
||||
| `05_flights/flightPlanUtils` | OpenWeatherMap (external) | REST | Request-Response | `GET https://api.openweathermap.org/data/2.5/onecall?...` with **hardcoded API key** — security finding. |
|
||||
| `05_flights/flightPlanUtils` | OpenWeatherMap (external) | REST | Request-Response | `GET https://api.openweathermap.org/data/2.5/onecall?...` with env-resolved key + base URL since AZ-448 / AZ-449 (closes the original security finding; see AC-20 + AC-42). |
|
||||
|
||||
### External Integrations
|
||||
|
||||
| External System | Protocol | Auth | Rate Limits | Failure Mode |
|
||||
|----------------|----------|------|-------------|--------------|
|
||||
| OpenStreetMap tiles | HTTPS (Leaflet TileLayer) | None | OSM Tile Usage Policy | Map renders blank / stale; no fallback today |
|
||||
| OpenWeatherMap | HTTPS | **Hardcoded API key in source** | Free-tier 60 calls/min | Errors silently swallowed in `flightPlanUtils.ts` (finding) — wind data missing → battery/duration estimates wrong, no UI surface |
|
||||
| Suite-internal `satellite-provider` for satellite tiles | HTTPS (Leaflet TileLayer); same-origin via nginx in production; cookie auth (`crossOrigin="use-credentials"`) | HttpOnly same-origin cookie set by `admin/` | Bounded by suite ops (no external usage policy) | 401 / 503 on a tile request renders a broken-tile placeholder for the failing cell; rest of the SPA stays interactive (per NFT-RES-11). Cycle 2 / 2026-05-12 — AZ-498. |
|
||||
| OpenWeatherMap | HTTPS | Env-resolved key (`VITE_OWM_API_KEY`); never hardcoded since AZ-448 / AZ-499 | Free-tier 60 calls/min | Errors silently swallowed in main SPA's `flightPlanUtils.ts` (existing finding); mission-planner `WeatherService.getWeatherData` now returns `null` and issues NO outbound fetch when the key is unset (AZ-499 fail-soft contract — AC-42). |
|
||||
| Suite identity provider (admin/) | REST + HttpOnly refresh cookie | JWT bearer + refresh-token rotation | server-enforced | 401 → `ProtectedRoute` redirects to `/login`; refresh-token rotation handled inside `AuthContext` (mostly) |
|
||||
|
||||
## 6. Non-Functional Requirements
|
||||
|
||||
Reference in New Issue
Block a user