From 350ba1f0ba7f9f6709449094cdcb51d250174318 Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Sat, 25 Apr 2026 12:42:59 -0700 Subject: [PATCH] Record edge_detection security sweep result No CRITICAL/HIGH findings. The five public functions delegate to convolve_2d with hard-coded 3x3 kernels, so kernel-memory blowup is not reachable from this module. One MEDIUM noted for follow-up: the public entry points do not call _validate_raster, which only affects error-message UX (wrong results are not silent because _promote_float normalises integer dtype downstream). --- .claude/sweep-security-state.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.claude/sweep-security-state.json b/.claude/sweep-security-state.json index 38a23f13..b8a37499 100644 --- a/.claude/sweep-security-state.json +++ b/.claude/sweep-security-state.json @@ -153,6 +153,13 @@ "severity_max": null, "categories_found": [], "notes": "Clean. Small (271 LOC) module computing 3x3 second-derivative stencil. Cat 1: only single output buffer matching input shape (np.empty at line 37, cupy.empty at line 101) -- bounded by caller, per audit guidance not a finding. Cat 2: _cpu numba kernel uses range(1, rows-1)/range(1, cols-1) with simple (y, x) indices; no flat indexing or queue arrays; numba range loops produce int64. Cat 3: division by cellsize*cellsize on line 44 -- cellsize comes from get_dataarray_resolution() (raster property, not user-direct); cellsize=0 is unrealistic and would produce inf consistently across backends. NaN inputs propagate correctly through float arithmetic. Cat 4: _run_gpu (line 79-86) has full bounds guard via 'i + di <= out.shape[0] - 1 and j + dj <= out.shape[1] - 1' which guarantees i < shape[0] and j < shape[1] before the out[i, j] write; no shared memory; out is pre-filled with NaN at line 102 so threads outside the guard correctly leave NaN. Cat 5: no file I/O. Cat 6: curvature() calls _validate_raster at line 253; all four backend paths explicitly cast to float32 (lines 51, 62, 97, 112) so dtype is normalized before any computation; tests cover int32/int64/uint32/uint64/float32/float64 across numpy/cupy/dask+numpy/dask+cupy." + }, + "edge_detection": { + "last_inspected": "2026-04-25", + "issue": null, + "severity_max": "MEDIUM", + "categories_found": [6], + "notes": "No CRITICAL/HIGH findings. Tiny (167 LOC) module with five public functions (sobel_x, sobel_y, laplacian, prewitt_x, prewitt_y) that all delegate to convolve_2d() with a hard-coded 3x3 kernel (SOBEL_X/Y, PREWITT_X/Y, LAPLACIAN_KERNEL declared as module-level np.float64 constants). Cat 1: kernel is fixed 3x3, never user-supplied, so the convolution.py kernel-memory guard (#1241) is not strictly required here; the only allocation is the same-shape output via convolve_2d, bounded by caller. Cat 2: no flat-index math; numba kernel ranges are int64. Cat 3: NaN propagation is correct (multiply+accumulate over a 3x3 neighborhood with any NaN input yields NaN); tests verify (test_nan_in_input_propagates, test_all_nan_input). No divisions in this module; no log/sqrt. Boundary='nan' explicitly fills edges with NaN. Cat 4: no @cuda.jit in edge_detection.py; the underlying _convolve_2d_cuda in convolution.py has a bounds guard at lines 418-420. Cat 5: no file I/O. Cat 6 (MEDIUM, unfixed): the five public functions do not call _validate_raster on agg. They access agg.data, agg.coords, agg.dims, agg.attrs directly, so a non-DataArray raises AttributeError instead of a clean TypeError, and a non-numeric or wrong-ndim DataArray fails downstream inside numba/cupy with a confusing error. Wrong results are NOT silent: convolve_2d's _promote_float casts integer dtypes to float32 so the math is well-defined; the only issue is error-message UX. Per the security-sweep one-fix-per-PR policy, this is recorded as a deferred MEDIUM rather than fixed." } } }