[AZ-501] [AZ-502] Cycle 2 Step 14 security audit + inline fixes
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:
Oleksandr Bezdieniezhnykh
2026-05-12 05:31:11 +03:00
parent b016fd8207
commit f7dd6c98d8
32 changed files with 1833 additions and 502 deletions
-1
View File
@@ -1,2 +1 @@
export const COORDINATE_PRECISION = 8;
export const GOOGLE_GEOCODE_KEY = 'AIzaSyAhvDeYukuyWVrQYbRhuv91bsi_jj5_Iys';
@@ -12,7 +12,7 @@ import './LeftBoard.css';
import { actionModes } from '../constants/actionModes';
import { DashedAreaIcon, HideSidebarIcon, ShowSidebarIcon } from '../icons/SidebarIcons';
import { FaLocationDot } from 'react-icons/fa6';
import { GOOGLE_GEOCODE_KEY } from '../config';
import { geocodeAddress } from '../services/GeocodeService';
import type { FlightPoint, CalculatedPointInfo, AircraftParams, LatLngPosition } from '../types';
interface LeftBoardProps {
@@ -108,23 +108,6 @@ export default function LeftBoard({
return null;
};
const geocodeAddress = async (address: string): Promise<LatLngPosition | null> => {
try {
const response = await fetch(
`https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(address)}&key=${GOOGLE_GEOCODE_KEY}`
);
const data = await response.json();
if (data.status === 'OK' && data.results.length > 0) {
const location = data.results[0].geometry.location;
return { lat: location.lat, lng: location.lng };
}
} catch {
return null;
}
return null;
};
return (
<>
{isShowed ?
@@ -0,0 +1,36 @@
import type { LatLngPosition } from '../types';
// AZ-501 — Google Geocode lookup, mirrors the WeatherService pattern from
// AZ-499: build-time env var, fail-soft when unset, fail-soft on network errors.
// Extracted from LeftBoard.tsx so the env-resolution and fail-soft contract
// can be unit-tested in isolation.
const ENDPOINT = 'https://maps.googleapis.com/maps/api/geocode/json';
export const geocodeAddress = async (
address: string,
): Promise<LatLngPosition | null> => {
const apiKey = import.meta.env.VITE_GOOGLE_GEOCODE_KEY;
if (!apiKey) {
// Surface the misconfiguration — geocode is user-triggered (per "Enter"
// keypress) so a single warn per call is informative, not spammy.
console.warn(
'[geocodeAddress] VITE_GOOGLE_GEOCODE_KEY is not set; skipping lookup',
);
return null;
}
const url = `${ENDPOINT}?address=${encodeURIComponent(address)}&key=${apiKey}`;
try {
const response = await fetch(url);
const data = await response.json();
if (data.status === 'OK' && data.results.length > 0) {
const location = data.results[0].geometry.location;
return { lat: location.lat, lng: location.lng };
}
} catch {
return null;
}
return null;
};
+1
View File
@@ -4,6 +4,7 @@ interface ImportMetaEnv {
readonly VITE_OWM_API_KEY?: string;
readonly VITE_OWM_BASE_URL?: string;
readonly VITE_SATELLITE_TILE_URL?: string;
readonly VITE_GOOGLE_GEOCODE_KEY?: string;
}
interface ImportMeta {