fix: report OpenSky Basic and auto modes accurately

This commit is contained in:
Sameh Khamis committed 2026-09-20 16:43:16 -07:00
1 parent a716b059b8
commit 9ad64112dc
5 files changed
+50 -12

No files matched your search

+4 -3
View File
@@ -268,9 +268,10 @@ of current runtime behavior, see [`docs/CURRENT-STATE.md`](docs/CURRENT-STATE.md
### Fixed
- Make `npm run doctor` report keyless anonymous OpenSky access for explicit
`OPENSKY_AUTH_MODE=anon` and missing OAuth client pairs while retaining the
existing OAuth-pair capability wording. OpenSky proxy authentication is
unchanged.
`OPENSKY_AUTH_MODE=anon` and OAuth mode without a client pair, retain the
existing OAuth-pair capability wording, and identify selected Basic or auto
modes without guessing their eventual credential choice. OpenSky proxy
authentication is unchanged.
- Bikeshare stations load again. The extracted station source addressed the
proxy as `/api/gbfs?url=`, but the proxy reads its upstream target from the
path, so every request answered 400 and the layer reported a fetch error for
+5 -4
View File
@@ -414,10 +414,11 @@ Add these if you need higher polling allowances.
where each configured provider was found without printing credential values.
On macOS its Keychain-aware result previews `./scripts/dev-fresh.sh`; plain
`npm run dev` reads only explicit environment and Vite dotenv values. The
OpenSky summary reports keyless anonymous access for explicit `anon` or when
no OAuth client pair is present, and retains presence-only wording for a
complete OAuth pair unless `anon` is selected. Basic and credentials-file
modes remain advanced `dev-fresh.sh` configuration.
OpenSky summary reports keyless anonymous access for explicit `anon` or an
OAuth mode without a client pair, retains presence-only wording for a complete
OAuth pair, and identifies selected Basic or auto mode without guessing which
credentials runtime will accept. Basic and credentials-file modes remain
advanced `dev-fresh.sh` configuration.
<details>
<summary>Advanced setup: environment variables and macOS Keychain</summary>
+1 -1
View File
@@ -3557,7 +3557,7 @@ are omitted rather than framing the wrong part of the globe.
- Build gate: `npm run build`
- Network access: local-only by default (`HOST=localhost` in dev-fresh.sh); LAN is an explicit opt-in via `HOST=0.0.0.0` (launcher prints a key-exposure warning + LAN URL; see SECURITY.md)
- OpenSky default mode: OAuth (`OPENSKY_AUTH_MODE=oauth`; `anon` works without credentials)
- Setup doctor resolves `OPENSKY_AUTH_MODE` from the environment and dotenv files. Explicit `anon` and a missing OAuth client pair report keyless anonymous access (rate-limited); a complete OAuth pair retains the existing presence-only capability wording unless `anon` is selected. The proxy's auth behavior is unchanged.
- Setup doctor resolves `OPENSKY_AUTH_MODE` from the environment and dotenv files. Explicit `anon` and OAuth mode without a client pair report keyless anonymous access (rate-limited); a complete OAuth pair retains the existing presence-only capability wording. Basic and auto modes report the selected mode without guessing which credentials runtime will accept. The proxy's auth behavior is unchanged.
- Google key expected in Keychain service `google-maps-api` (or `GOOGLE_MAPS_API_KEY`, or `.env`)
- OpenSky credentials expected in Keychain service `opensky-network` (or env, or `.env`); `OPENSKY_AUTH_MODE` and `OPENSKY_CREDENTIALS_FILE` read from `.env` too
- Optional-key precedence in `dev-fresh.sh` is uniform — explicit shell env, then `.env`, then Keychain: `OPENAI_API_KEY` (Keychain `openai-api`/`api-key` — voice + HUD summary), `AISSTREAM_API_KEY` (`aisstream-api`/`api-key` — live vessels), `CESIUM_ION_TOKEN` (`cesium-ion`/`token` — Bing stacks), `TOMTOM_API_KEY` (`tomtom-api`/`api-key` — live traffic flow), `FIRMS_MAP_KEY` (`firms-map`/`map-key` — live fires), `LL2_API_TOKEN` (`.env` only)
+14 -4
View File
@@ -151,7 +151,19 @@ export function buildCapabilitySummary(
) {
const configured = (name) => credentials[name]?.configured === true;
const hasOAuthCredentials = configured('OPENSKY_CLIENT_ID') && configured('OPENSKY_CLIENT_SECRET');
const anonymousOpenSkyMode = String(openSkyAuthMode || '').trim().toLowerCase() === 'anon';
const requestedOpenSkyMode = String(openSkyAuthMode || '').trim().toLowerCase();
const openSkyMode = OPENSKY_AUTH_MODES.has(requestedOpenSkyMode)
? requestedOpenSkyMode
: OPENSKY_AUTH_MODE_DEFAULT;
const flights = openSkyMode === 'anon'
? 'OpenSky keyless anonymous access (rate-limited)'
: openSkyMode === 'basic'
? 'OpenSky Basic mode selected (credential presence and validity not verified)'
: openSkyMode === 'auto'
? 'OpenSky auto mode selected (runtime credential choice and validity not verified)'
: hasOAuthCredentials
? 'OpenSky OAuth credentials present (runtime mode and validity not verified)'
: 'OpenSky keyless anonymous access (rate-limited)';
const route = selectMapStartupRoute({
googleApiKey: configured('GOOGLE_MAPS_API_KEY') ? 'configured' : '',
cesiumToken: configured('CESIUM_ION_TOKEN') ? 'configured' : '',
@@ -162,9 +174,7 @@ export function buildCapabilitySummary(
: route === 'google-ion'
? 'Google Photorealistic 3D Tiles through Cesium ion; Bing and world-terrain stacks available'
: 'Esri World Imagery (keyless satellite basemap) with keyless terrain',
flights: hasOAuthCredentials && !anonymousOpenSkyMode
? 'OpenSky OAuth credentials present (runtime mode and validity not verified)'
: 'OpenSky keyless anonymous access (rate-limited)',
flights,
voice: configured('OPENAI_API_KEY') ? 'available' : 'off until an OpenAI key is added',
vessels: configured('AISSTREAM_API_KEY') ? 'live AISStream feed' : 'off until an AISStream key is added',
fires: configured('FIRMS_MAP_KEY') ? 'live NASA FIRMS feed' : 'off until a FIRMS key is added',
+26
View File
@@ -181,6 +181,32 @@ test('doctor retains OAuth capability wording for a complete client pair', () =>
);
});
test('doctor reports Basic mode without inferring runtime auth from OAuth credentials', () => {
const oauthCredentials = {
OPENSKY_CLIENT_ID: { configured: true },
OPENSKY_CLIENT_SECRET: { configured: true },
};
for (const credentials of [{}, oauthCredentials]) {
assert.equal(
buildCapabilitySummary(credentials, { openSkyAuthMode: 'basic' }).flights,
'OpenSky Basic mode selected (credential presence and validity not verified)',
);
}
});
test('doctor reports auto mode without assuming its eventual credential choice', () => {
const oauthCredentials = {
OPENSKY_CLIENT_ID: { configured: true },
OPENSKY_CLIENT_SECRET: { configured: true },
};
for (const credentials of [{}, oauthCredentials]) {
assert.equal(
buildCapabilitySummary(credentials, { openSkyAuthMode: 'auto' }).flights,
'OpenSky auto mode selected (runtime credential choice and validity not verified)',
);
}
});
test('doctor describes the credential ladder without exposing values', () => {
const credentials = {
GOOGLE_MAPS_API_KEY: { configured: false },