fix(viz): self-DOS guards on sensor URL overrides - #87
Conversation
Address the security review on PRs #85 / #86. URL overrides for world bounds and LiDAR scan params previously accepted any positive finite value; a typo like `?worldGrid=8192` (~2 TB voxel buffer) or `?lidarRange=1e30` (DDA walks every voxel + float precision erosion) would lock up the GPU. Self-DOS only — no server amplification, no cross-origin attack surface — but a sane upper bound prevents "my browser tab died" footguns. Caps: worldGrid ≤ 1024 (1024³ × 4 B = 4 GB voxel buffer ceiling) voxelScale ≤ 256 (1024 × 256 = 256 km cube ceiling) lidarElev/azim ≤ 4096 (the LiDAR manager capacity) lidarRange 0.1–10000 (m; visualization terrain is only 4 km) lidarInterval 0.001–60 (s) Also: truncate `raw` log value to 64 chars (+ `…` ellipsis) so a poisoned URL with megabytes of garbage can't bloat the console or log aggregator. Helpers in both files share the same `_truncRaw` implementation. The lenient `_readPositiveFinite` helper in effects.ts is removed — the two call sites (lidarRange, lidarInterval) now use `_readNumberInRange` with explicit bounds, matching the pattern already used for `lidarFov`. Bundle: main 757.7 → 757.9 KB (+0.2 KB). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 0/1 reviews remaining, refill in 32 minutes and 56 seconds.Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces sanity upper bounds for LiDAR and world grid parameters passed via URL overrides to prevent potential Denial-of-Service (DoS) scenarios and GPU lockups. It also adds a _truncRaw utility to truncate long URL parameter values in warning logs, protecting against log bloat. I have no feedback to provide as there were no review comments to evaluate.
* docs: refresh README for the WebGPU sensor stack + version bumps The README was written before the .NET 10 / Vite 8 / TS 6 upgrade and predates the entire WebGPU sensor arc (PRs #66–#87). Bring it back into sync with reality. - Tech Stack: .NET 9 → 10, Three.js r175 → 0.184, TS 5 + Vite 6 → TS 6 + Vite 8; new rows for the WebGPU sensor primitive and Vitest frontend tests. - Features: add the brick-map raymarcher (mesh-link LoS + per-drone LiDAR off one kernel) and the SignalR lazy chunk. - Project Layout: include `webgpu/` (device, sensors, registry, world, brickmap, los, lidar, rays, shaders/) and `__tests__/`, plus the new `sensorStatsOverlay.ts`. - Keyboard shortcuts: add `i` for the sensor stats overlay. - License footer: 2024 ResQ Technologies Ltd. → 2026 ResQ Systems, Inc. — matches the SPDX headers across the codebase. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: address review feedback on PR #88 - "voxelizes once" was misleading — the brick-map rebuilds when the terrain preset switches or a heightmap override is installed (the `onTerrainChange` path landed in #74). Reword to "voxelizes at boot (and rebuilds on terrain edits)" so the docs match the code. - Drop "(~17 cases, ~380 ms)" from the Vitest row in Tech Stack — machine-specific runtime that drifts with each new test, not a capability claim. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: refresh README for the WebGPU sensor stack + version bumps The README was written before the .NET 10 / Vite 8 / TS 6 upgrade and predates the entire WebGPU sensor arc (PRs #66–#87). Bring it back into sync with reality. - Tech Stack: .NET 9 → 10, Three.js r175 → 0.184, TS 5 + Vite 6 → TS 6 + Vite 8; new rows for the WebGPU sensor primitive and Vitest frontend tests. - Features: add the brick-map raymarcher (mesh-link LoS + per-drone LiDAR off one kernel) and the SignalR lazy chunk. - Project Layout: include `webgpu/` (device, sensors, registry, world, brickmap, los, lidar, rays, shaders/) and `__tests__/`, plus the new `sensorStatsOverlay.ts`. - Keyboard shortcuts: add `i` for the sensor stats overlay. - License footer: 2024 ResQ Technologies Ltd. → 2026 ResQ Systems, Inc. — matches the SPDX headers across the codebase. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: address review feedback on PR #88 - "voxelizes once" was misleading — the brick-map rebuilds when the terrain preset switches or a heightmap override is installed (the `onTerrainChange` path landed in #74). Reword to "voxelizes at boot (and rebuilds on terrain edits)" so the docs match the code. - Drop "(~17 cases, ~380 ms)" from the Vitest row in Tech Stack — machine-specific runtime that drifts with each new test, not a capability claim. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: document missing keyboard shortcuts in README The marketing intro mentioned `5`, `K`, and `Ctrl+Shift+R` but those never appeared in the Keyboard Shortcuts table. The `multi-agency-sar` scenario was also missing from the REST scenarios list, and the camera presets (`Shift+1..5`) plus the drone-strip cycling (`[`/`]`) were undocumented. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: correct wwwroot description (not committed) The Project Layout entry claimed wwwroot/ is "committed for zero-install deploys", but `git ls-files src/ResQ.Viz.Web/wwwroot/` returns 0 files and `.gitignore` excludes index.html, assets/, and .vite/. The zero-install path is actually the CI artifact `viz-wwwroot-{sha}` produced by ci.yml's client/build job, not anything in the repo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: split long WebGPU sensor primitive sentence Addresses gemini-code-assist review feedback on PR #89 — the "voxelizes ... and serves ..." compound was a single 72-word sentence. Splitting at the rebuild-trigger clause keeps the trigger conditions visible while letting the LoS/LiDAR purpose start a fresh sentence. Backticks around `peakSlotDepth`, `raysOutsideWorld`, and `i` were already present in the source; only the bot's suggestion block had stripped them. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: correct the SDK pin, and guard what the compiler cannot CLAUDE.md said the submodule is "pinned to a release tag". It is not. It is pinned to a3f8b89 on release/0.6.x, three commits past v0.6.0, and those three commits (#85-#87) are what added drone attitude, the explicit yaw command, and landing recovery. No tag contains them. The line invited exactly the change that would drop them. Two findings while checking it, one of which corrects an assumption I had been repeating. FIRST, THE SDK's main HAS MOVED PAST US. ResQ.Simulation.Engine, ResQ.Mavlink, ResQ.Mavlink.Dialect and ResQ.Mavlink.Mesh do not exist on main - MAVLink is gone from it entirely, and main carries a different set (Core, Clients, Protocols, Blockchain, Storage, Simulation). All four are ProjectReferences in ResQ.Viz.Web.csproj. So viz is not on a stale pin; it is on a branch main has structurally abandoned, 43 commits back on a divergent line. Reconciling that is an architecture decision for a human, and this commit does not attempt it - it writes it down where the next person will look. SECOND, THE SILENT-REVERT RISK IS NOT REAL, and I had been asserting it was. Both ways of moving the pin fail loudly: v0.6.0 -> compile error; viz calls Hover(yaw) and GoTo(..., yaw:), which that tag has no overloads for main -> the four project references do not resolve at all Measured, not reasoned: checking out v0.6.0 in the submodule produced five CS1501/CS1739 errors in viz's own production code before any test ran. What neither catches is a behaviour that changed without changing a signature. Landing recovery is a re-arm inside ApplyCommand, and attitude integration is the roll/pitch term inside IntegrateAttitude; reverting either compiles cleanly. Verified by doing it: the re-arm revert and the heading-only attitude revert each build green and each fail exactly one of the new tests. So SdkFlightContractTests covers the part that is genuinely silent. Four tests: explicit yaw steers heading, forward flight produces real pitch, a landed drone re-arms and climbs on a non-Land command, and Land still latches so the re-arm did not make HasLanded meaningless. They duplicate tests the SDK already has, on purpose - this is viz asserting the submodule it is pinned to still behaves the way its client and physics assume. 1376 tests green. dotnet format clean. The submodule pin is unchanged and its working tree was restored after every mutation. * test: make the re-arm test cover what its name claims, and drop a stale claim Two review findings, both right. FIRST, the test file's own doc still said moving the pin to v0.6.0 "still builds, still passes every other test, and silently reverts takeoff and rotation". That was the assumption this PR exists to correct, and CLAUDE.md now says the opposite two files away: v0.6.0 is a compile error because viz calls Hover(yaw) and GoTo(..., yaw:). The stale wording survived where the argument for the tests lives, which is the worst place for it. Rewritten to say what was measured, and to say plainly what the tests actually guard - behaviour that changed without changing a signature, which no compiler can see. SECOND, the re-arm test was named "on any non-Land command" and exercised GoTo alone. The re-arm is keyed on command.Type, so a regression that cleared HasLanded for GoTo and not for Hover or RTL would have passed. Now a Theory over GoTo, Hover and RTL. Verified rather than assumed: rewriting the guard to `command.Type == FlightCommandType.GoToWaypoint` fails the Hover and RTL cases and passes GoTo - precisely the regression described, which the old test would have shipped green. The first attempt at that mutation used a FlightCommandType member that does not exist and failed to compile; the result above is from the one that actually applied. Hover asserts the flag rather than a climb, because RTL rewrites to GoTo(LaunchPosition) and has somewhere to go while Hover holds station. Asserting a climb for Hover would assert the wrong contract. 1378 tests green. dotnet format clean. Submodule restored after each mutation.
Summary
Three security follow-up tweaks from the post-merge review of #85 / #86. URL overrides for world bounds and LiDAR scan params previously accepted any positive finite value; a typo like
?worldGrid=8192(~2 TB voxel buffer) or?lidarRange=1e30(DDA walks every voxel + float-precision erosion) would lock up the GPU.Self-DOS only — no server amplification, no cross-origin attack surface — but a sane upper bound prevents "my browser tab died" footguns when an operator typos a test URL.
Caps
worldGridvoxelScalelidarElev/lidarAzimregistry.tslidarRangelidarIntervalLog hygiene
Truncate
rawlog value to 64 chars (+…ellipsis) in all URL warn paths, so a poisoned URL with megabytes of garbage can't bloat the console or log aggregator. Shared_truncRawhelper in both files.The lenient
_readPositiveFinitehelper in effects.ts is removed — the two call sites (lidarRange, lidarInterval) now use_readNumberInRangewith explicit bounds, matching the pattern already used forlidarFov.Bundle
Main 757.7 → 757.9 KB (+0.2 KB; 92.5 % of cap).
Test plan
npm run buildpassestsc --noEmitcleannpm test17/17 green?worldGrid=99999→ warn-and-fall-back?lidarRange=1e30→ warn-and-fall-back?worldGrid=+ 100 KB of garbage → log shows truncated…🤖 Generated with Claude Code