diff --git a/SONAR-REVIEW-17.md b/SONAR-REVIEW-17.md new file mode 100644 index 0000000..7347e86 --- /dev/null +++ b/SONAR-REVIEW-17.md @@ -0,0 +1,53 @@ +# SonarQube-Auswertung vom 3. Oktober 2026 + +Basis: Export `Wegwichtel-sonarqube-export(17).json`, Repository `cf4170f`. +Von 119 exportierten Issues sind fünf offen; die übrigen sind bereits geschlossen. + +## Code-Korrekturen + +- `javascript:S7773`, `public/js/local-routes.js`: beide globalen `NaN` durch + `Number.NaN` ersetzt. Fehlende Positionen bleiben weiterhin ungültige Zahlen + und werden als GPS-Lücken gespeichert. +- `javascript:S3358`, `src/services/gpx.js`: Auswahl der Punkte für die + Metrikberechnung in eine eigene Variable ausgelagert. Keine verschachtelte + bedingte Operation mehr; die bisherigen Fälle bleiben erhalten. +- `javascript:S1481`, `src/services/gpx.js`: die beiden unbenutzten Variablen + `_oldWaypoints` und `_oldPending` entfernt. Alte Wegpunkte und unvollständige + Stationen werden gezielt entfernt, bevor die aktuelle Stationsliste entsteht. + Andere Erweiterungen bleiben erhalten. + +Das bereits korrigierte Moderationsskript bleibt unverändert. + +## Security-Hotspot mit notwendiger Bewertung in SonarQube + +- Schlüssel: `7854386c-ec53-4e14-b374-d7d356accf23` +- Datei: `src/services/gpx.js` +- Regel: `javascript:S5332` +- Meldung: Verwendung des HTTP-Protokolls +- Empfohlene Bewertung nach Prüfung: **Safe** + +Begründung zum Einfügen in SonarQube: + +> Die Zeichenfolge `http://www.topografix.com/GPX/1/1` ist der offizielle +> XML-Namespace von GPX 1.1. Die Funktion schreibt sie als xmlns-Attribut in die +> erzeugte GPX-Datei. Sie stellt keine HTTP-Verbindung her und überträgt keine +> Daten an diese Adresse. Ein Wechsel zu https würde einen anderen Namespace +> erzeugen und die GPX-Kompatibilität beeinträchtigen. Daher besteht an dieser +> Stelle kein unverschlüsselter Datentransport. + +Offizielle Referenz: https://www.topografix.com/GPX/1/1/ + +Der gleiche Namespace in `public/js/local-routes.js` wurde laut Export bereits +als **Safe** bewertet. Der neue Hotspot ist weiterhin **TO_REVIEW**; ein +Code-Kommentar oder dieses Dokument ändert seinen Status in SonarQube nicht. +Es wurden keine Regeln deaktiviert und keine Findings per Suppression verborgen. + +## Quality Gate laut Export + +- Neue Coverage: 87,8 %, bestanden (mindestens 80 %). +- Neue Duplikate: rund 0,35 %, bestanden (höchstens 3 %). +- Neue offene Findings: fünf, durch die Code-Korrekturen adressiert. +- Geprüfte Security-Hotspots: 50 %, noch nicht bestanden (erforderlich 100 %). + +Die abschließende Bewertung des Quality Gates benötigt einen neuen Scan und +die Bewertung des genannten Hotspots in SonarQube. diff --git a/public/js/local-routes.js b/public/js/local-routes.js index da6e00e..5ee0fb0 100644 --- a/public/js/local-routes.js +++ b/public/js/local-routes.js @@ -409,8 +409,8 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {}; } function appendPosition(document, position, routeName) { - const lat = position.lat == null ? NaN : Number(position.lat); - const lon = position.lon == null ? NaN : Number(position.lon); + const lat = position.lat == null ? Number.NaN : Number(position.lat); + const lon = position.lon == null ? Number.NaN : Number(position.lon); const timestamp = new Date(position.timestamp ?? Date.now()).toISOString(); if (!Number.isFinite(lat) || !Number.isFinite(lon) || Math.abs(lat) > 90 || Math.abs(lon) > 180) { const root = document.documentElement; diff --git a/src/services/gpx.js b/src/services/gpx.js index ca581fa..b23857b 100644 --- a/src/services/gpx.js +++ b/src/services/gpx.js @@ -52,7 +52,8 @@ export function parseGpx(xml, replacementPoints = null) { const points = replacementPoints ?? (routed.length ? routed : simplifyTrack(recorded)); const waypoints = validPoints(asList(gpx.wpt)); if (!points.length && !waypoints.length && !gpx.extensions?.['wegwichtel:gpsGap'] && !gpx.extensions?.['wegwichtel:pendingWaypoint']) throw new HttpError(400, 'Die GPX-Datei enthält keine verwertbaren Punkte.'); - const metrics = points.length || waypoints.length ? routeMetrics(points.length ? points : waypoints) : { + const metricPoints = points.length ? points : waypoints; + const metrics = metricPoints.length ? routeMetrics(metricPoints) : { startLat: null, startLon: null, centerLat: null, centerLon: null, minLat: null, minLon: null, maxLat: null, maxLon: null, distanceM: 0, elevationGainM: 0, pointCount: 0 @@ -63,6 +64,8 @@ export function parseGpx(xml, replacementPoints = null) { delete gpx.rte; // GPX 1.1 order: metadata, waypoints, route, extensions. const { extensions, ...base } = gpx; + // GPX 1.1 namespace identifier: this URI is written into XML, never fetched. + // Its exact spelling is part of the GPX standard; HTTPS would be another namespace. const normalized = { ...base, '@_version': '1.1', '@_creator': 'Wegwichtel', '@_xmlns': 'http://www.topografix.com/GPX/1/1' }; if (points.length) normalized.rte = { ...(name ? { name } : {}), rtept: points.map(point => ({ '@_lat': point.lat, '@_lon': point.lon, @@ -75,13 +78,15 @@ export function parseGpx(xml, replacementPoints = null) { export function gpxWithWaypoints(xml, pois) { const gpx = parseXml(xml).gpx; - const { wpt: _oldWaypoints, rte, trk, extensions = {}, ...base } = gpx; + delete gpx.wpt; + const { rte, trk, extensions = {}, ...base } = gpx; const waypoint = poi => ({ '@_lat': poi.lat, '@_lon': poi.lon, name: poi.title, ...(poi.description ? { desc: poi.description } : {}), extensions: { 'wegwichtel:poiId': poi.id } }); const located = pois.filter(poi => Number.isFinite(poi.lat) && Number.isFinite(poi.lon)); const pending = pois.filter(poi => !Number.isFinite(poi.lat) || !Number.isFinite(poi.lon)); - const { 'wegwichtel:pendingWaypoint': _oldPending, ...extra } = extensions; + const extra = { ...extensions }; + delete extra['wegwichtel:pendingWaypoint']; if (pending.length) extra['wegwichtel:pendingWaypoint'] = pending.map(poi => ({ name: poi.title, ...(poi.description ? { desc: poi.description } : {}), extensions: { 'wegwichtel:poiId': poi.id } })); const normalized = { ...base, '@_xmlns:wegwichtel': 'urn:wegwichtel:poi',