mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
chore(sonar): keep only categorical issue suppressions
Instance-specific findings (S2245 singles, S4790, S5332, S2819, S7767, S4158 sessionManager, S8786, S6825) are resolved server-side as false positive / accepted / reviewed-safe instead, so future violations of the same rule in the same file still surface. Narrow the i18n secrets scope to the locale directories so top-level code files stay fully scanned, and drop the comment claims the code contradicts.
This commit is contained in:
+43
-152
@@ -50,6 +50,7 @@ sonar.coverage.exclusions=\
|
||||
server/src/db/seeds.ts,\
|
||||
server/src/demo/**,\
|
||||
server/src/nest/plugins/runtime/plugin-host-entry.ts,\
|
||||
server/assets/**,\
|
||||
client/src/main.tsx,\
|
||||
client/src/types.ts,\
|
||||
shared/src/plugin-permissions.ts,\
|
||||
@@ -60,169 +61,59 @@ sonar.coverage.exclusions=\
|
||||
# Locale files are large near-identical literal objects — keep them out of duplication metrics
|
||||
sonar.cpd.exclusions=shared/src/i18n/**
|
||||
|
||||
# Locale files are UI copy — strings like "Password", "API key", "token" are labels,
|
||||
# not credentials, and the secret detectors false-positive on them constantly.
|
||||
# Ignore the secrets analyzer and the hard-coded-credential rules on i18n only.
|
||||
sonar.issue.ignore.multicriteria=i18nsec1,i18nsec2,i18nsec3,rand1,rand2,rand3,rand4,rand5,rand6,cli1,hash1,hash2,hash3,hash4,hash5,hash6,hash7,hash8,ns1,ns2,frame1,empty1,empty2,canvas1,wiki1,tar1
|
||||
sonar.issue.ignore.multicriteria.i18nsec1.ruleKey=secrets:*
|
||||
sonar.issue.ignore.multicriteria.i18nsec1.resourceKey=shared/src/i18n/**
|
||||
sonar.issue.ignore.multicriteria.i18nsec2.ruleKey=typescript:S2068
|
||||
sonar.issue.ignore.multicriteria.i18nsec2.resourceKey=shared/src/i18n/**
|
||||
sonar.issue.ignore.multicriteria.i18nsec3.ruleKey=typescript:S6418
|
||||
sonar.issue.ignore.multicriteria.i18nsec3.resourceKey=shared/src/i18n/**
|
||||
|
||||
# S2245 (Math.random in a security context) — scoped per file, never globally, so
|
||||
# a future Math.random() on an auth, token or crypto path still fails the gate.
|
||||
# The two places where the value DID reach something that matters — the two
|
||||
# idempotency-key producers — were fixed instead of listed here; they now share
|
||||
# client/src/utils/randomId.ts.
|
||||
#
|
||||
# Studio + studioStore: element and spread ids inside a photo-book document. The
|
||||
# whole document is stored and fetched as one blob scoped by journey id, so an
|
||||
# element id is never a URL, a lookup key or an authorization subject. Worst case
|
||||
# of a collision is documented in studioStore itself: two elements would share a
|
||||
# selection.
|
||||
# Only categorical, path-wide suppressions live here — cases where the rule can
|
||||
# never meaningfully apply to anything in the path. Instance-specific findings
|
||||
# (a handful of flagged lines in one file) are resolved as false positive /
|
||||
# accepted / reviewed-safe on SonarCloud instead, so a future violation of the
|
||||
# same rule in the same file still surfaces.
|
||||
sonar.issue.ignore.multicriteria=i18nsec1,i18nsec2,i18nsec3,rand1,rand2,path1,empty2
|
||||
|
||||
|
||||
# Locale files are UI copy — strings like "Password", "API key", "token" are
|
||||
# labels, not credentials, and the secret detectors false-positive on them
|
||||
# constantly. Ignore the secrets analyzer and the hard-coded-credential rules on
|
||||
# the locale directories only (shared/src/i18n/*/** — the top-level code files
|
||||
# such as languages.ts stay fully scanned).
|
||||
|
||||
sonar.issue.ignore.multicriteria.i18nsec1.ruleKey=secrets:*
|
||||
sonar.issue.ignore.multicriteria.i18nsec1.resourceKey=shared/src/i18n/*/**
|
||||
sonar.issue.ignore.multicriteria.i18nsec2.ruleKey=typescript:S2068
|
||||
sonar.issue.ignore.multicriteria.i18nsec2.resourceKey=shared/src/i18n/*/**
|
||||
sonar.issue.ignore.multicriteria.i18nsec3.ruleKey=typescript:S6418
|
||||
sonar.issue.ignore.multicriteria.i18nsec3.resourceKey=shared/src/i18n/*/**
|
||||
|
||||
|
||||
# S2245 (Math.random in a security context) — Studio + studioStore only: minting
|
||||
# element and spread ids with Math.random is pervasive by design there (uid()
|
||||
# helpers across the whole component tree), so per-instance marks would recur on
|
||||
# every refactor. The ids live inside the photo-book document, stored and
|
||||
# fetched as one blob scoped by journey id — the server never indexes, looks up
|
||||
# or authorizes on an element or spread id. Worst case of a collision is
|
||||
# documented in studioStore itself: two elements would share a selection.
|
||||
|
||||
sonar.issue.ignore.multicriteria.rand1.ruleKey=typescript:S2245
|
||||
sonar.issue.ignore.multicriteria.rand1.resourceKey=client/src/components/Studio/**
|
||||
sonar.issue.ignore.multicriteria.rand2.ruleKey=typescript:S2245
|
||||
sonar.issue.ignore.multicriteria.rand2.resourceKey=client/src/store/studioStore.ts
|
||||
# LoginWorld: canvas animation parameters — arc endpoints, flight speed, spawn
|
||||
# delays. Nothing crosses a trust boundary; nothing leaves the browser.
|
||||
sonar.issue.ignore.multicriteria.rand3.ruleKey=typescript:S2245
|
||||
sonar.issue.ignore.multicriteria.rand3.resourceKey=client/src/pages/login/LoginWorld.tsx
|
||||
# placesSession: a Google Places session token. It is a BILLING correlator, not a
|
||||
# credential — Google groups requests by (API key, token) for pricing. Suggestions
|
||||
# derive from the typed input, never from the token, so a guessed value cannot
|
||||
# pull another user's results. The Math.random rung is also the third fallback,
|
||||
# reached only where Web Crypto is absent entirely.
|
||||
sonar.issue.ignore.multicriteria.rand4.ruleKey=typescript:S2245
|
||||
sonar.issue.ignore.multicriteria.rand4.resourceKey=client/src/utils/placesSession.ts
|
||||
# Cost-split rows: React list keys for ephemeral ticket rows, dropped before the
|
||||
# payload is serialised (see writeTicketItems) so they never reach the API or DB.
|
||||
sonar.issue.ignore.multicriteria.rand5.ruleKey=typescript:S2245
|
||||
sonar.issue.ignore.multicriteria.rand5.resourceKey=client/src/components/Budget/CostsPanel.tsx
|
||||
sonar.issue.ignore.multicriteria.cli1.ruleKey=typescript:S2245
|
||||
sonar.issue.ignore.multicriteria.cli1.resourceKey=client/src/mobile/screens/trip/sheets/MCostSheet.tsx
|
||||
|
||||
# S4790 (weak hash) — every one of these derives a cache key or a filename, never
|
||||
# a token, signature or integrity check, and the digest never reaches a client:
|
||||
# the public URLs carry the plain placeId/photoId. Every genuine security hash in
|
||||
# the server is already sha256 (backup codes, tokens, PKCE, the plugin audit
|
||||
# chain). Swapping these would only orphan existing cached files — thumbnail.ts
|
||||
# says so in its own comment.
|
||||
sonar.issue.ignore.multicriteria.hash1.ruleKey=typescript:S4790
|
||||
sonar.issue.ignore.multicriteria.hash1.resourceKey=server/src/nest/memories/**
|
||||
sonar.issue.ignore.multicriteria.hash2.ruleKey=typescript:S4790
|
||||
sonar.issue.ignore.multicriteria.hash2.resourceKey=server/src/nest/place-photos/**
|
||||
sonar.issue.ignore.multicriteria.hash3.ruleKey=typescript:S4790
|
||||
sonar.issue.ignore.multicriteria.hash3.resourceKey=server/src/nest/place-enrichment/**
|
||||
|
||||
# S4036 (OS command via PATH) — the plugin SDK is a CLI a plugin author runs on
|
||||
# their own machine, and reaching git/npm through the developer's own PATH is the
|
||||
# point of it. Every invocation passes an argv array, so nothing is shell-parsed.
|
||||
# The one server-side site was NOT suppressed: it now resolves its binary to an
|
||||
# absolute path (see kitinerary-extractor.service.ts).
|
||||
sonar.issue.ignore.multicriteria.hash4.ruleKey=typescript:S4036
|
||||
sonar.issue.ignore.multicriteria.hash4.resourceKey=plugin-sdk/src/cli/**
|
||||
# their own machine, and reaching git/gh/npm through the developer's own PATH is
|
||||
# the point of it. Every child-process invocation passes an argv array with no
|
||||
# shell, so nothing is shell-parsed. The one server-side site was NOT
|
||||
# suppressed: it resolves its binary to an absolute path before spawning
|
||||
# (see server/src/nest/booking-import/kitinerary-extractor.service.ts).
|
||||
|
||||
# S5332 (clear-text protocol) — neither site opens a connection.
|
||||
# gpx-export: the GPX and XSI namespace URIs plus the schemaLocation pair. A
|
||||
# namespace is an exact identifier fixed by the schema, so rewriting it to
|
||||
# https:// would produce GPX that other tools reject.
|
||||
sonar.issue.ignore.multicriteria.ns1.ruleKey=typescript:S5332
|
||||
sonar.issue.ignore.multicriteria.ns1.resourceKey=server/src/nest/places/gpx-export.helpers.ts
|
||||
# host-surface: 'http://x.invalid' is a throwaway base handed to new URL() so a
|
||||
# relative path can be parsed — the very next line rejects the value if it
|
||||
# resolved anywhere else. The string is part of the guard, not a destination, and
|
||||
# .invalid is reserved by RFC 2606 precisely so it can never resolve.
|
||||
sonar.issue.ignore.multicriteria.ns2.ruleKey=typescript:S5332
|
||||
sonar.issue.ignore.multicriteria.ns2.resourceKey=server/src/nest/plugins/host/rpc/host-surface.rpc.ts
|
||||
sonar.issue.ignore.multicriteria.path1.ruleKey=typescript:S4036
|
||||
sonar.issue.ignore.multicriteria.path1.resourceKey=plugin-sdk/src/cli/**
|
||||
|
||||
# S2819 (postMessage target origin) — the plugin frame is embedded with
|
||||
# sandbox="allow-scripts allow-forms" and deliberately WITHOUT allow-same-origin,
|
||||
# so the document inside has an opaque origin. There is no origin string that
|
||||
# would match it: '*' is the only value that works, which makes the rule
|
||||
# unsatisfiable here rather than unsatisfied. The receiving side authenticates on
|
||||
# event.source instead.
|
||||
sonar.issue.ignore.multicriteria.frame1.ruleKey=typescript:S2819
|
||||
sonar.issue.ignore.multicriteria.frame1.resourceKey=client/src/components/Plugins/PluginFrame.tsx
|
||||
# randomId is the module that MINTS idempotency keys, and its first two rungs are
|
||||
# crypto.randomUUID and crypto.getRandomValues. The Math.random line is the third,
|
||||
# reached only by a runtime with no Web Crypto at all, and the value it produces is
|
||||
# a deduplication key the server scopes per (user, method, path) — not a token, not
|
||||
# a secret. Replacing it is not possible: there is no stronger primitive left at
|
||||
# that point, and deleting the rung would leave such a runtime with no key.
|
||||
sonar.issue.ignore.multicriteria.rand6.ruleKey=typescript:S2245
|
||||
sonar.issue.ignore.multicriteria.rand6.resourceKey=client/src/utils/randomId.ts
|
||||
|
||||
# S7767 (bitwise truncation) — Math.trunc is NOT equivalent to `| 0`, and all four
|
||||
# sites depend on a difference the rule does not model.
|
||||
#
|
||||
# packingListPanel.helpers and todoListModel hold the same djb2-variant string
|
||||
# hash, `h = ((h << 5) - h + chr) | 0`, whose only job is to stay bounded while it
|
||||
# folds a category name into a colour index. Math.trunc would let h grow past 2^53,
|
||||
# lose precision, and hand out different colours for the same names.
|
||||
#
|
||||
# BudgetPanel.helpers and TravelerPicker look like plain truncation of a user row
|
||||
# id, but `| 0` is also coercing there: it turns undefined and NaN into 0, while
|
||||
# Math.trunc returns NaN and the array lookup then yields undefined. That is not
|
||||
# theoretical — the settlement `flows` the API returns carry a username and an
|
||||
# avatar but no user_id, so colorForUserId(undefined) is the normal path for that
|
||||
# section. Swapping it crashed two BudgetPanel tests on `.gradient` of undefined.
|
||||
sonar.issue.ignore.multicriteria.hash5.ruleKey=typescript:S7767
|
||||
sonar.issue.ignore.multicriteria.hash5.resourceKey=client/src/components/Packing/packingListPanel.helpers.ts
|
||||
sonar.issue.ignore.multicriteria.hash6.ruleKey=typescript:S7767
|
||||
sonar.issue.ignore.multicriteria.hash6.resourceKey=client/src/components/Todo/todoListModel.ts
|
||||
sonar.issue.ignore.multicriteria.hash7.ruleKey=typescript:S7767
|
||||
sonar.issue.ignore.multicriteria.hash7.resourceKey=client/src/components/Budget/BudgetPanel.helpers.ts
|
||||
sonar.issue.ignore.multicriteria.hash8.ruleKey=typescript:S7767
|
||||
sonar.issue.ignore.multicriteria.hash8.resourceKey=client/src/components/Planner/TravelerPicker.tsx
|
||||
# S4158 (empty collection accessed) — client/src/managed is a build-time seam:
|
||||
# the arrays are empty in this repo and in every build of it, and an operator
|
||||
# shipping extra screens replaces the file. Its header comment makes reading
|
||||
# them unconditionally a rule, so the public build takes the same code path as
|
||||
# a managed one.
|
||||
|
||||
# S4158 (empty collection accessed) — two places where the analyser cannot see
|
||||
# who fills the collection, and where acting on it would delete working code.
|
||||
#
|
||||
# mcp/sessionManager declares `export const sessions = new Map()` and never
|
||||
# writes to it in that file; every insert comes from
|
||||
# nest/mcp-transport/mcp-transport.service.ts. The four findings are the eviction
|
||||
# loop, the two revocation loops and the per-user cap scan — so "removing the
|
||||
# dead code" would leak every MCP session and leave a revoked OAuth client with
|
||||
# live ones. It is only ever empty at process start.
|
||||
sonar.issue.ignore.multicriteria.empty1.ruleKey=typescript:S4158
|
||||
sonar.issue.ignore.multicriteria.empty1.resourceKey=server/src/mcp/sessionManager.ts
|
||||
# client/src/managed is a build-time seam: the arrays are empty in this repo and
|
||||
# in every build of it, and an operator shipping extra screens replaces the file.
|
||||
# Its header comment makes reading them unconditionally a rule, so the public
|
||||
# build takes the same code path as a managed one.
|
||||
sonar.issue.ignore.multicriteria.empty2.ruleKey=typescript:S4158
|
||||
sonar.issue.ignore.multicriteria.empty2.resourceKey=client/src/managed/**
|
||||
|
||||
# S8786 (non-linear backtracking) on the wiki renderer — the two link patterns
|
||||
# have NO overlapping quantifier pair: each `[^\]]+` / `[^)\s]+` is followed by a
|
||||
# literal its own class excludes, and they are separated by `](`. What is
|
||||
# quadratic is only the unanchored global scan over a long run of `[`, and the
|
||||
# way to stop that is to exclude `[` from the link-text class — which would stop
|
||||
# `[see [1]](url)` being rewritten at all. The subject is not user input either:
|
||||
# the content is the `wiki/**` directory shipped with the app, the same files CI
|
||||
# mirrors to the public GitHub wiki. Changing link parsing to satisfy a rule
|
||||
# about untrusted input, on input that is not untrusted, is the wrong trade.
|
||||
sonar.issue.ignore.multicriteria.wiki1.ruleKey=typescript:S8786
|
||||
sonar.issue.ignore.multicriteria.wiki1.resourceKey=server/src/nest/help/wiki.ts
|
||||
# S8786 on the tar reader — `/\0.*$/` trims the NUL padding out of a header
|
||||
# field, and it does backtrack, but the subject is a fixed-size slice the tar
|
||||
# format defines: 100 bytes for the name, 155 for the prefix, 12 for the size.
|
||||
# The quadratic factor is bounded at ~10^4 character comparisons per member and
|
||||
# an attacker cannot grow it. The rewrite that would clear the rule
|
||||
# (`\0[^\0\n\r]*$`) stops matching NUL runs, which changes what gets truncated on
|
||||
# the path-traversal guard — not a trade worth making for a lint finding. The two
|
||||
# tag strippers that WERE reachable (uploaded KML, Commons metadata) were fixed
|
||||
# instead, in common/stripHtmlTags.ts.
|
||||
sonar.issue.ignore.multicriteria.tar1.ruleKey=typescript:S8786
|
||||
sonar.issue.ignore.multicriteria.tar1.resourceKey=server/src/nest/plugins/install/safe-extract.ts
|
||||
|
||||
# S6825 on LoginWorld — the element is a decorative animated background:
|
||||
# <canvas aria-hidden pointer-events:none>, no tabIndex, no children, no role.
|
||||
# aria-hidden is the correct markup for it. Both ways to satisfy the rule make
|
||||
# things worse: dropping aria-hidden exposes a contentless canvas to a screen
|
||||
# reader, and adding tabIndex={-1} makes it focusable for the linter's benefit.
|
||||
sonar.issue.ignore.multicriteria.canvas1.ruleKey=typescript:S6825
|
||||
sonar.issue.ignore.multicriteria.canvas1.resourceKey=client/src/pages/login/LoginWorld.tsx
|
||||
|
||||
Reference in New Issue
Block a user