mirror of
https://github.com/azaion/ui.git
synced 2026-06-21 10:51:11 +00:00
f7dd6c98d8
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>
102 lines
3.3 KiB
TypeScript
102 lines
3.3 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
|
import { geocodeAddress } from '../mission-planner/src/services/GeocodeService'
|
|
|
|
// AZ-501 — mission-planner GeocodeService env-var hardening (mirrors AZ-499).
|
|
//
|
|
// Lives under tests/ rather than colocated under mission-planner/ for the
|
|
// same reason as mission_planner_weather.test.ts: mission-planner has no
|
|
// runner of its own; the suite Vitest config covers mission-planner/src.
|
|
|
|
type FetchMock = ReturnType<typeof vi.fn>
|
|
|
|
const okResponse = (lat: number, lng: number) =>
|
|
new Response(
|
|
JSON.stringify({
|
|
status: 'OK',
|
|
results: [{ geometry: { location: { lat, lng } } }],
|
|
}),
|
|
{ status: 200 },
|
|
)
|
|
|
|
describe('AZ-501 — mission-planner geocodeAddress (env vars + fail-soft)', () => {
|
|
let fetchMock: FetchMock
|
|
let warnSpy: ReturnType<typeof vi.spyOn>
|
|
|
|
beforeEach(() => {
|
|
fetchMock = vi.fn(async () => okResponse(50.45, 30.52))
|
|
vi.spyOn(globalThis, 'fetch').mockImplementation(fetchMock)
|
|
warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined)
|
|
})
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks()
|
|
vi.unstubAllEnvs()
|
|
})
|
|
|
|
it('AC-1: env-var resolved API key reaches the outgoing fetch URL', async () => {
|
|
// Arrange
|
|
vi.stubEnv('VITE_GOOGLE_GEOCODE_KEY', 'env-key-xyz')
|
|
|
|
// Act
|
|
const result = await geocodeAddress('Kyiv, Ukraine')
|
|
|
|
// Assert
|
|
expect(fetchMock).toHaveBeenCalledTimes(1)
|
|
const url = String(fetchMock.mock.calls[0][0])
|
|
expect(url).toContain('key=env-key-xyz')
|
|
expect(url).toContain('address=Kyiv%2C%20Ukraine')
|
|
expect(result).toEqual({ lat: 50.45, lng: 30.52 })
|
|
})
|
|
|
|
it('AC-3: returns null, issues no fetch, and warns when VITE_GOOGLE_GEOCODE_KEY is unset', async () => {
|
|
// Arrange
|
|
vi.stubEnv('VITE_GOOGLE_GEOCODE_KEY', '')
|
|
|
|
// Act
|
|
const result = await geocodeAddress('Kyiv, Ukraine')
|
|
|
|
// Assert
|
|
expect(result).toBeNull()
|
|
expect(fetchMock).not.toHaveBeenCalled()
|
|
expect(warnSpy).toHaveBeenCalledTimes(1)
|
|
expect(String(warnSpy.mock.calls[0][0])).toContain('VITE_GOOGLE_GEOCODE_KEY')
|
|
})
|
|
|
|
it('AC-3: still returns null and does not throw when fetch rejects (network error fail-soft)', async () => {
|
|
// Arrange
|
|
vi.stubEnv('VITE_GOOGLE_GEOCODE_KEY', 'env-key-xyz')
|
|
fetchMock.mockRejectedValueOnce(new Error('boom'))
|
|
|
|
// Act
|
|
const result = await geocodeAddress('Kyiv, Ukraine')
|
|
|
|
// Assert
|
|
expect(result).toBeNull()
|
|
})
|
|
|
|
it('returns null when the response status is non-OK (e.g. ZERO_RESULTS)', async () => {
|
|
// Arrange
|
|
vi.stubEnv('VITE_GOOGLE_GEOCODE_KEY', 'env-key-xyz')
|
|
fetchMock.mockResolvedValueOnce(
|
|
new Response(JSON.stringify({ status: 'ZERO_RESULTS', results: [] }), {
|
|
status: 200,
|
|
}),
|
|
)
|
|
|
|
// Act
|
|
const result = await geocodeAddress('nowhere-place-12345')
|
|
|
|
// Assert
|
|
expect(result).toBeNull()
|
|
})
|
|
|
|
it('AC-4 (defense-in-depth): no live key string is hardcoded in the service module', async () => {
|
|
// Assert: importing GeocodeService.ts must NOT bring along the previously
|
|
// hardcoded literal. Done as a sanity assertion on the resolved URL when
|
|
// no env var is present — ensures we cannot accidentally leak a fallback.
|
|
vi.stubEnv('VITE_GOOGLE_GEOCODE_KEY', '')
|
|
await geocodeAddress('test')
|
|
expect(fetchMock).not.toHaveBeenCalled()
|
|
})
|
|
})
|