From 558d755761b9680020d90d5cc5e490aec46e8132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Thu, 2 Jul 2026 07:19:56 -0400 Subject: [PATCH 01/14] Apply suggested fix to docker/debian/Dockerfile from Copilot Autofix Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> (cherry picked from commit 8e43a8a45978a1439223b531983c415160ca1c78) (cherry picked from commit 747a5748c7fe715b2179c62a906abc6911fa32e8) --- docker/debian/Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile index 9d7801a3fb9..087905a3f88 100644 --- a/docker/debian/Dockerfile +++ b/docker/debian/Dockerfile @@ -191,7 +191,9 @@ ENV GRASS_SKIP_MAPSET_OWNER_CHECK=1 ENV PROJ_NETWORK=ON # Create generic GRASS lib name regardless of version number -RUN ln -sf /usr/local/grass86 /usr/local/grass +RUN GRASS_DIR="$(find /usr/local -maxdepth 1 -type d -name 'grass*' ! -name 'grass' | sort | tail -n 1)" && \ + test -n "$GRASS_DIR" && \ + ln -sfn "$GRASS_DIR" /usr/local/grass # show GRASS, PROJ, GDAL etc versions RUN grass --tmp-project EPSG:4326 --exec g.version -rge && \ From a1b3e129e916ed87bc029fa2f2c7c1c4c9dd02ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Fri, 17 Jul 2026 17:32:43 +0200 Subject: [PATCH 02/14] Apply suggested fix to gui/wxpython/lmgr/layertree.py from Copilot Autofix Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> (cherry picked from commit 03693ae872b72353e3ff59bb01a4355a6e2330fa) (cherry picked from commit 6db17e74eb5e0e97160160423a8e7ba2b999f058) --- gui/wxpython/lmgr/layertree.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/gui/wxpython/lmgr/layertree.py b/gui/wxpython/lmgr/layertree.py index 0b9c042c5c1..0b29db51fa7 100644 --- a/gui/wxpython/lmgr/layertree.py +++ b/gui/wxpython/lmgr/layertree.py @@ -1311,8 +1311,6 @@ def OnPopupGroupOpacityLevel(self, event): if maplayer and ltype != "command": break child = self.GetNextSibling(child) - if child is None: - child, cookie = self.GetNextChild(child, cookie) current_opacity = maplayer.GetOpacity() dlg = SetOpacityDialog( self, From 615addcdd89351da276b339ca8e45a2851f31da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Tue, 14 Jul 2026 22:09:44 +0200 Subject: [PATCH 03/14] Apply suggested fix to python/grass/temporal/metadata.py from Copilot Autofix Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> (cherry picked from commit 2da7b2729f6cfc37f189c93853e83748a5021147) (cherry picked from commit 80eccc9fac1f911f9525fe0d7e3ebc6a4a5d5940) --- python/grass/temporal/metadata.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/grass/temporal/metadata.py b/python/grass/temporal/metadata.py index f892230b00e..6aa3b916073 100644 --- a/python/grass/temporal/metadata.py +++ b/python/grass/temporal/metadata.py @@ -1723,8 +1723,8 @@ def _print_info_body(self, shell: bool = False) -> None: print( " | 3D raster register table:... " + str(self.get_raster3d_register()) ) - print(" | Top-bottom resolution min:.. " + str(self.get_ewres_min())) - print(" | Top-bottom resolution max:.. " + str(self.get_ewres_max())) + print(" | Top-bottom resolution min:.. " + str(self.get_tbres_min())) + print(" | Top-bottom resolution max:.. " + str(self.get_tbres_max())) super()._print_info_body(shell) From bfe96c1ba1aa45cbde616e5e572cf82d63651dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Mon, 22 Jun 2026 12:24:03 -0400 Subject: [PATCH 04/14] Apply suggested fix to scripts/d.correlate/tests/d_correlate_test.py from Copilot Autofix Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> (cherry picked from commit e58bf3efb6e8427d5d41845622226894dc89a0e4) (cherry picked from commit 81d1a360a22b80fb45e5dcfd5ab4c025af8ee2b7) --- scripts/d.correlate/tests/d_correlate_test.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/d.correlate/tests/d_correlate_test.py b/scripts/d.correlate/tests/d_correlate_test.py index a7d05b6e4f3..f570ad365d0 100644 --- a/scripts/d.correlate/tests/d_correlate_test.py +++ b/scripts/d.correlate/tests/d_correlate_test.py @@ -33,6 +33,14 @@ def test_fewer_than_two_maps_is_fatal(xy_raster_dataset_session_mapset, tmp_path tools.d_correlate(map="map_a") +def test_exactly_two_maps_runs(xy_raster_dataset_session_mapset, tmp_path): + """d.correlate handles its primary two-map use case without crashing.""" + tools = render_tools(xy_raster_dataset_session_mapset, tmp_path) + tools.r_mapcalc(expression="map_a = col()") + tools.r_mapcalc(expression="map_b = row()") + tools.d_correlate(map="map_a,map_b") + + def test_more_than_two_maps_runs(xy_raster_dataset_session_mapset, tmp_path): """d.correlate handles more than two maps without crashing. From 86a04a12c0ab31be72fe4be617f2b221bcecc679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Fri, 17 Jul 2026 21:23:28 +0200 Subject: [PATCH 05/14] Apply suggested fix to scripts/r.in.wms/wms_cap_parsers.py from Copilot Autofix Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> (cherry picked from commit 576f29c3821e389eee4d4bf88b23123dfa4eff42) (cherry picked from commit ce14dc122edfc56b1459759b6aa694fda29e28c9) --- scripts/r.in.wms/wms_cap_parsers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/r.in.wms/wms_cap_parsers.py b/scripts/r.in.wms/wms_cap_parsers.py index 5e6d658db11..fe1e5a3d1d9 100644 --- a/scripts/r.in.wms/wms_cap_parsers.py +++ b/scripts/r.in.wms/wms_cap_parsers.py @@ -159,7 +159,7 @@ def _initLayer(self, layer, parent_layer): for element in replaced_elements: elems = layer.findall(self.xml_ns.Ns(element[0])) - if len(elems) != 0 or element[1] == "add": + if len(elems) == 0 or element[1] == "add": for e in parent_layer.findall(self.xml_ns.Ns(element[0])): layer.append(e) From 4007f7d246f7a0aca4ad7e9b133812d9cb716324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sun, 19 Jul 2026 11:25:20 +0200 Subject: [PATCH 06/14] Apply suggested fix to temporal/t.vect.import/tests/t_vect_import_test.py from Copilot Autofix Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> (cherry picked from commit cdbdb08f465e6ab25a89fbd1a5d54000e7612854) (cherry picked from commit 7771c7bc266da3e26765c59b7f87f1bab2e87603) --- temporal/t.vect.import/tests/t_vect_import_test.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/temporal/t.vect.import/tests/t_vect_import_test.py b/temporal/t.vect.import/tests/t_vect_import_test.py index 76f770fe5a5..d9ed2a38c57 100644 --- a/temporal/t.vect.import/tests/t_vect_import_test.py +++ b/temporal/t.vect.import/tests/t_vect_import_test.py @@ -53,6 +53,8 @@ def test_import_formats( ) info = _stvds_tinfo(tools, output) assert info["temporal_type"] == "absolute" + assert info["start_time"] == "2001-01-01 00:00:00" + assert info["end_time"] == "2001-04-01 00:00:00" assert info["number_of_maps"] == 3 From b9294636871dd98e07ce35c347f489c6df4bca91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Thu, 9 Jul 2026 17:37:33 -0400 Subject: [PATCH 07/14] Potential fix for code scanning alert no. 467: Uncontrolled format string Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> (cherry picked from commit 56e5765ad9c5e70590154ea213dda5874b3c617b) (cherry picked from commit 954c4ad8c9c1a89b84eb9b87b6ca36cbd1cc3cb1) --- raster/r.what.color/main.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/raster/r.what.color/main.c b/raster/r.what.color/main.c index e314640d732..0b8c5c340b9 100644 --- a/raster/r.what.color/main.c +++ b/raster/r.what.color/main.c @@ -84,13 +84,8 @@ static int do_value(const char *buf, RASTER_MAP_TYPE type, switch (outputFormat) { case PLAIN: fprintf(stdout, "%d: ", ival); - if (strcmp(fmt, "plain") != 0) { - fprintf(stdout, fmt, red, grn, blu); - } - else { - G_color_to_str(red, grn, blu, colorFormat, color_str); - fprintf(stdout, "%s", color_str); - } + G_color_to_str(red, grn, blu, colorFormat, color_str); + fprintf(stdout, "%s", color_str); fprintf(stdout, "\n"); break; From 3e009a414a7ed3f77f9da2dbd8b60738ca2c911b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Wed, 10 Jun 2026 08:22:23 -0400 Subject: [PATCH 08/14] Fix for File is not always closed Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> (cherry picked from commit 029f79cc42c0141ea930afdee56723bc7d3ae333) (cherry picked from commit 5b1cca05ae80d1abf45ebd04017d90e0cb9a466a) --- scripts/i.oif/i.oif.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/i.oif/i.oif.py b/scripts/i.oif/i.oif.py index d158454bbe0..96dbea55f0a 100755 --- a/scripts/i.oif/i.oif.py +++ b/scripts/i.oif/i.oif.py @@ -142,9 +142,8 @@ def main(): for v, p in oif: sys.stdout.write(fmt % (p + (v,))) else: - outf = open(output, "w") - outf.writelines(fmt % (p + (v,)) for v, p in oif) - outf.close() + with open(output, "w") as outf: + outf.writelines(fmt % (p + (v,)) for v, p in oif) if __name__ == "__main__": From 6395a0b712e10c0196d72ffb0f005be9b0d1ab1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Wed, 10 Jun 2026 11:14:28 -0400 Subject: [PATCH 09/14] Update scripts/m.proj/m.proj.py Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> (cherry picked from commit 4cf2459c538213b71326f173bf55a4aaecf80eb1) (cherry picked from commit 767d24a386908e6817674ac0cac1b7eb8f874254) --- scripts/m.proj/m.proj.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/m.proj/m.proj.py b/scripts/m.proj/m.proj.py index 861472f256c..5627c03fa80 100755 --- a/scripts/m.proj/m.proj.py +++ b/scripts/m.proj/m.proj.py @@ -211,9 +211,7 @@ def main(): if coords: x, y = coords.split(",") tmpfile = gcore.tempfile() - fd = open(tmpfile, "w") - fd.write("%s%s%s\n" % (x, ifs, y)) - fd.close() + Path(tmpfile).write_text("%s%s%s\n" % (x, ifs, y)) inf = open(tmpfile) elif input == "-": infile = None From c03c00e6353955c19dce7a2c17fe7e934a402ccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Wed, 10 Jun 2026 08:24:24 -0400 Subject: [PATCH 10/14] Fix for File is not always closed Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> (cherry picked from commit 3f3f1b2cb1c6736ce993218859adb7ba3273d2cc) (cherry picked from commit c9c21faf464bd1dac2ee7ad0aefad41e6d57b50b) --- scripts/v.import/v.import.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/scripts/v.import/v.import.py b/scripts/v.import/v.import.py index 9a9123e4876..005af9b3c00 100755 --- a/scripts/v.import/v.import.py +++ b/scripts/v.import/v.import.py @@ -251,12 +251,11 @@ def main(): TMPLOC = gs.append_node_pid("tmp_v_import_location") - f = open(SRCGISRC, "w") - f.write("MAPSET: PERMANENT\n") - f.write("GISDBASE: %s\n" % GISDBASE) - f.write("LOCATION_NAME: %s\n" % TMPLOC) - f.write("GUI: text\n") - f.close() + with open(SRCGISRC, "w") as f: + f.write("MAPSET: PERMANENT\n") + f.write("GISDBASE: %s\n" % GISDBASE) + f.write("LOCATION_NAME: %s\n" % TMPLOC) + f.write("GUI: text\n") # create temp location from input without import gs.verbose(_("Creating temporary project for <%s>...") % OGRdatasource) From 2207bca451f26bf7ea0c99406f230401f07a5172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Wed, 10 Jun 2026 08:25:43 -0400 Subject: [PATCH 11/14] Fix for File is not always closed Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> (cherry picked from commit 12640445fedd8f0da40b14d7462ff7a44d5fb852) (cherry picked from commit 835152284b84b4b0a659746854b02000997e3100) --- scripts/r.in.wms/wms_gdal_drv.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/r.in.wms/wms_gdal_drv.py b/scripts/r.in.wms/wms_gdal_drv.py index 2765ccb4ee1..6ec3e3501a9 100644 --- a/scripts/r.in.wms/wms_gdal_drv.py +++ b/scripts/r.in.wms/wms_gdal_drv.py @@ -155,9 +155,8 @@ def _download(self): xml_file = self._createXML() # print xml file content for debug level 1 - file = open(xml_file) - gs.debug("WMS request XML:\n%s" % file.read(), 1) - file.close() + with open(xml_file) as file: + gs.debug("WMS request XML:\n%s" % file.read(), 1) if self.proxy: gdal.SetConfigOption("GDAL_HTTP_PROXY", str(self.proxy)) From 91cb4f8f23f4e65de3abcf382986ce0ba0d6ce28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Wed, 15 Jul 2026 07:11:34 +0200 Subject: [PATCH 12/14] Apply suggested fix to lib/raster3d/tilewrite.c from Copilot Autofix Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> (cherry picked from commit f98c0a5d5243f87206fef88722a91ee5d6efdb00) --- lib/raster3d/tilewrite.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/raster3d/tilewrite.c b/lib/raster3d/tilewrite.c index 6f2c646c5d0..f348a41659e 100644 --- a/lib/raster3d/tilewrite.c +++ b/lib/raster3d/tilewrite.c @@ -132,7 +132,7 @@ int Rast3d_write_tile(RASTER3D_Map *map, int tileIndex, const void *tile, int rows, cols, depths, xRedundant, yRedundant, zRedundant, nofNum; /* valid tileIndex ? */ - if ((tileIndex > map->nTiles) || (tileIndex < 0)) + if ((tileIndex >= map->nTiles) || (tileIndex < 0)) Rast3d_fatal_error("Rast3d_write_tile: tileIndex out of range"); /* already written ? */ From 11c57bcc7cefbf3c4b5c084a6dbe5fdc90cf3f7d Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Fri, 17 Jul 2026 13:01:33 -0400 Subject: [PATCH 13/14] lib/raster3d: Add test for Rast3d_write_tile tile index bounds check Add a pytest test covering the tileIndex bounds check in Rast3d_write_tile: an index equal to nTiles must be rejected as out of range, and the last valid index must be accepted. The invalid call runs in a subprocess using the grass.lib.raster3d ctypes bindings because the rejection is a fatal error which exits the calling process. The out-of-range test fails without the bounds check change in this branch and passes with it. The test was written by Claude Code using the Claude Fable 5 model. (cherry picked from commit 46933580b8137b7c02594ad6d449ecb1ede295de) --- .../tests/lib_raster3d_tilewrite_test.py | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 lib/raster3d/tests/lib_raster3d_tilewrite_test.py diff --git a/lib/raster3d/tests/lib_raster3d_tilewrite_test.py b/lib/raster3d/tests/lib_raster3d_tilewrite_test.py new file mode 100644 index 00000000000..d8b59bfda4e --- /dev/null +++ b/lib/raster3d/tests/lib_raster3d_tilewrite_test.py @@ -0,0 +1,94 @@ +"""Test tile index bounds checking in Rast3d_write_tile""" + +import os +import subprocess +import sys + +import pytest + +import grass.script as gs + +WRITE_TILE_SCRIPT = """\ +import sys +from ctypes import POINTER, byref, c_float, cast + +from grass.lib.gis import G_gisinit +from grass.lib.raster import FCELL_TYPE +from grass.lib.raster3d import ( + RASTER3D_NO_CACHE, + RASTER3D_Map, + RASTER3D_Region, + Rast3d_adjust_region, + Rast3d_init_defaults, + Rast3d_open_cell_new, + Rast3d_write_tile, +) + +index_offset = int(sys.argv[1]) + +G_gisinit("test") +Rast3d_init_defaults() + +region = RASTER3D_Region() +region.north = 100 +region.south = 0 +region.east = 100 +region.west = 0 +region.top = 100 +region.bottom = 0 +region.rows = 10 +region.cols = 10 +region.depths = 10 +Rast3d_adjust_region(byref(region)) + +handle = Rast3d_open_cell_new( + "bounds_check_3d", FCELL_TYPE, RASTER3D_NO_CACHE, byref(region) +) +if not handle: + sys.exit("Rast3d_open_cell_new failed") +map_ptr = cast(handle, POINTER(RASTER3D_Map)) +tile = (c_float * map_ptr.contents.tileSize)() +Rast3d_write_tile(map_ptr, map_ptr.contents.nTiles + index_offset, tile, FCELL_TYPE) +print("tile write accepted") +""" + + +@pytest.fixture +def session(tmp_path): + """Active session in an XY project (scope: function)""" + project = tmp_path / "xy_test" + gs.create_project(project) + with gs.setup.init(project, env=os.environ.copy()) as session: + yield session + + +def write_tile(index_offset, session, tmp_path): + """Call Rast3d_write_tile with tile index nTiles + index_offset. + + Runs in a subprocess because an invalid index triggers a fatal error + which exits the calling process. + """ + script = tmp_path / "write_tile.py" + script.write_text(WRITE_TILE_SCRIPT, encoding="utf-8") + return subprocess.run( + [sys.executable, str(script), str(index_offset)], + env=session.env, + capture_output=True, + text=True, + timeout=60, + check=False, + ) + + +def test_write_tile_accepts_last_index(session, tmp_path): + """Writing the last valid tile index (nTiles - 1) is accepted""" + result = write_tile(-1, session, tmp_path) + assert result.returncode == 0, result.stderr + assert "tile write accepted" in result.stdout + + +def test_write_tile_rejects_index_past_end(session, tmp_path): + """A tile index equal to nTiles is rejected as out of range""" + result = write_tile(0, session, tmp_path) + assert result.returncode != 0, "out-of-range tile index was accepted" + assert "tileIndex out of range" in result.stderr From d71b06a2c98ab2e37bd65839ce7b1476a5770ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Wed, 15 Jul 2026 07:15:46 +0200 Subject: [PATCH 14/14] Apply suggested fix to lib/cairodriver/draw_bitmap.c from Copilot Autofix Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> (cherry picked from commit 8ec6ef9321dec6e3e74928a3936802262fa2ddaf) --- lib/cairodriver/draw_bitmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/cairodriver/draw_bitmap.c b/lib/cairodriver/draw_bitmap.c index d745578817a..058d493b2ac 100644 --- a/lib/cairodriver/draw_bitmap.c +++ b/lib/cairodriver/draw_bitmap.c @@ -12,6 +12,7 @@ */ #include +#include #include "cairodriver.h" @@ -37,7 +38,7 @@ void Cairo_Bitmap(int ncols, int nrows, int threshold, const unsigned char *buf) #define MULTIPLE 4 stride = (ncols + (MULTIPLE - 1)) / MULTIPLE * MULTIPLE; #endif - data = malloc((size_t)stride * nrows); + data = G_malloc((size_t)stride * nrows); surf = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_A8, ncols, nrows, stride);