Files
ui/_docs/02_document/deployment/environment_strategy.md
T
Oleksandr Bezdieniezhnykh f7dd6c98d8
ci/woodpecker/push/build-arm Pipeline failed
[AZ-501] [AZ-502] Cycle 2 Step 14 security audit + inline fixes
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>
2026-05-12 05:31:11 +03:00

6.2 KiB
Raw Blame History

Azaion UI — Environment Strategy

Synthesis output of /document Step 3d (environment_strategy). Derived from vite.config.ts, nginx.conf, .gitignore, the workspace README.md, and the absence of a workspace .env.example.

1. Environments

Env How it runs API base Auth Tile providers
Development bun run dev (Vite dev server, port 5173) Vite dev proxy: /api → http://localhost:8080 (configured in vite.config.ts) Suite admin/ service running locally (typically via parent suite docker-compose up) Suite-internal satellite-provider via env-configurable VITE_SATELLITE_TILE_URL (defaults to http://localhost:5100/tiles/{z}/{x}/{y} when unset). Cookie auth requires same-origin; running the SPA at localhost:5173 and satellite-provider at localhost:5100 cannot send the auth cookie cross-port — recommend reaching satellite-provider through the suite's local nginx OR running it with auth disabled in dev (per AZ-498 risk #2). mission-planner/ keeps its own independent VITE_SATELLITE_TILE_URL.
Stage nginx in container, ARM image :stage-arm nginx /api/<service>/ → http://<service>:8080/ (intra-cluster) Stage suite admin/ service Suite-internal satellite-provider on the same origin (nginx-fronted); cookie auth attached automatically.
Production nginx in container, ARM image :main-arm nginx /api/<service>/ → http://<service>:8080/ Prod suite admin/ service Same as Stage. Replaces the previously-used external OpenStreetMap and Esri tile providers as of cycle 2 / 2026-05-12 (AZ-498) — production deploy is gated on the cross-workspace satellite-provider cookie-auth ticket landing (autodev Step 16).

2. Configuration model

The SPA bundle is fully static. No env vars are read at runtime by the bundle. Every cross-environment difference is resolved at the deployment edge (nginx) or at the suite-service level.

Concern Where it's set Notes
Backend API URL nginx proxy_pass (nginx.conf) — same nginx config across stage / prod Base URLs are intra-cluster service names (http://annotations:8080, etc.); the URL difference between environments is hidden by the orchestrator's DNS
Auth cookie domain Set by suite admin/ service on Set-Cookie UI does not control
Refresh-token lifetime Set by suite admin/ service UI tolerates any TTL
Satellite tile provider URL (main SPA) .env.example declares VITE_SATELLITE_TILE_URL; resolved at build time via getTileUrl() (src/features/flights/types.ts) with DEFAULT_SATELLITE_TILE_URL fallback. Cycle 2 / AZ-498.
Satellite tile provider URL (mission-planner) mission-planner/.env.example declares its own independent VITE_SATELLITE_TILE_URL mission-planner only; not deployed
OpenWeatherMap API key + base URL (main SPA) .env.example declares VITE_OWM_API_KEY + VITE_OWM_BASE_URL; resolved by getOwmBaseUrl() and the flightPlanUtils.ts builder. Closed AZ-448 / AZ-449 (no longer hardcoded).
OpenWeatherMap API key + base URL (mission-planner) mission-planner/.env.example declares VITE_OWM_API_KEY + VITE_OWM_BASE_URL; WeatherService.getWeatherData(lat, lon) returns null and issues NO outbound fetch when the key is unset (fail-soft). Closed cycle 2 / AZ-499. The previously-committed literal value MUST be revoked at the OWM dashboard (manual deliverable — AC-42 / AZ-499 AC-7); STC-SEC1C defends against re-introduction.
AZAION_REVISION Stamped into image at build time For diagnostics

3. .env strategy

Step 4 testability + cycle 2 added a workspace .env.example (resolved by Vite at build time via import.meta.env.VITE_*). Today it declares: VITE_OWM_API_KEY, VITE_OWM_BASE_URL (AZ-448 / AZ-449), and VITE_SATELLITE_TILE_URL (AZ-498). mission-planner/.env.example mirrors the OWM pair (AZ-499) and keeps its own independent VITE_SATELLITE_TILE_URL.

Trade-off: Vite resolves import.meta.env.VITE_* at build time, so dist/ is environment-specific once a non-empty VITE_OWM_API_KEY is baked in — the OpenWeatherMap key (and any future build-time config) cannot be changed without a rebuild. This trades promotability for the air-gap-friendly pattern that lets a deploy ship with VITE_OWM_API_KEY="" (no OWM call, fail-soft null return) when the deployment must not touch the internet.

Future direction (still open):

  • Move the OpenWeatherMap call server-side (flights/ service) — would eliminate the bundled key entirely; the env-var hardening in cycle 2 reduces the urgency but does not remove the option.
  • Introduce a runtime /config.json that nginx serves — would let ops change feature flags / tile URLs without rebuilding.
  • OR keep the static bundle and continue using Vite's import.meta.env for build-time injection of safe-to-publish values (current approach).

4. Promotability

The same image (:dev-arm, :stage-arm, :main-arm) is built per branch from the same Dockerfile. Theoretically the :dev-arm image is functionally identical to the :main-arm image except for the AZAION_REVISION label.

In practice: branch separation is the gating mechanism. Once dev → stage → main propagation is normalized, the safer pattern is to build ONE image per commit and re-tag it across environments (immutable image promotion). The Woodpecker pipeline does not implement this today; it rebuilds per-branch.

5. Local-dev quirks

  • Vite dev proxy (vite.config.ts) requires the suite to be reachable on http://localhost:8080. If the parent suite's docker-compose binds to a different port, the developer must edit vite.config.ts (no env-driven override today).
  • bun.lock: committed (per package.json's packageManager field). package-lock.json is gitignored.
  • .idea/, .claude/, .superpowers/: gitignored — IDE / agent metadata.
  • Playwright entries in .gitignore: present but aspirational — Playwright is not installed (Step 57 territory).
  • mission-planner: has its own .env.example declaring VITE_SATELLITE_TILE_URL and (cycle 2 / AZ-499) VITE_OWM_API_KEY + VITE_OWM_BASE_URL. Runs as a sibling Vite app; not bundled into the deployed image (per AC-31 / NFT-RES-LIM-04).