From c37742152d9558627ceffb4dfa0e3207e15a19a3 Mon Sep 17 00:00:00 2001 From: mikecarper Date: Wed, 21 Oct 2026 04:30:03 -0700 Subject: [PATCH] Fix reply bounds and portable browser test fixtures --- examples/simple_repeater/MyMesh.cpp | 4 ++-- test/test_flood_moderation.py | 14 +++++++++++++- test/test_webconfig_ui_runtime.py | 6 ++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 85c087a30..918c5a431 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -8915,7 +8915,7 @@ void MyMesh::setFloodPacketFilter(const char* args, char* reply, char detail[160]; formatFloodPacketFilterDetail(slot, detail, sizeof(detail)); - snprintf(reply, 160, "OK - %s", detail[0] == '>' ? skipFloodFilterSpaces(detail + 1) : detail); + snprintf(reply, 160, "OK - %.154s", detail[0] == '>' ? skipFloodFilterSpaces(detail + 1) : detail); } #endif @@ -10581,7 +10581,7 @@ void MyMesh::setFloodGroupModeration(const char* args, char* reply) { } char detail[160]; formatFloodGroupModerationDetail(slot, detail, sizeof(detail)); - snprintf(reply, 160, "OK - %s", detail[0] == '>' ? skipFloodFilterSpaces(detail + 1) : detail); + snprintf(reply, 160, "OK - %.154s", detail[0] == '>' ? skipFloodFilterSpaces(detail + 1) : detail); } void MyMesh::deleteFloodGroupModeration(const char* args, char* reply) { diff --git a/test/test_flood_moderation.py b/test/test_flood_moderation.py index 3e3c8e645..44645b20b 100644 --- a/test/test_flood_moderation.py +++ b/test/test_flood_moderation.py @@ -132,6 +132,7 @@ namespace FloodFilterPolicy { enum {SCOPE_PATH_NONE=0,SCOPE_PATH_BLACKLIST=1,SCOPE_PATH_BRIDGE_BUCKET_BASE=2}; } static const char FLOOD_CHANNEL_SCOPE_USAGE[]="Err - scope usage"; +static std::string moderation_detail_reply="> saved"; struct MyMesh { @ENTRY@ MockFS* _fs; @@ -148,7 +149,7 @@ struct MyMesh { void setFloodGroupModeration(const char*,char*); void setFloodChannelScope(const char*,char*); uint8_t scope_path=0;bool scope_slow=false; - void formatFloodGroupModerationDetail(int,char* reply,size_t size) const { snprintf(reply,size,"> saved"); } + void formatFloodGroupModerationDetail(int,char* reply,size_t size) const { snprintf(reply,size,"%s",moderation_detail_reply.c_str()); } }; namespace StrHelper { void strncpy(char* dest,const char* source,size_t size) { snprintf(dest,size,"%s",source); } } const uint8_t FLOOD_PUBLIC_CHANNEL_SECRET[16]={}; @@ -349,6 +350,17 @@ void cli() { shortform.setFloodGroupModeration(item.compact,reply);assert(!strncmp(reply,"OK",2)); assert(first.files[target]==second.files[target]); } + // The prefix consumes five bytes. Preserve the existing154-byte detail + // bound, NUL termination, and caller memory for either formatter style. + struct GuardedReply { char text[160]; uint32_t canary=0xA5B6C7D8; } bounded; + for (bool prefixed : {false,true}) { + moderation_detail_reply=(prefixed ? "> " : "")+std::string(159,'X'); + longform.setFloodGroupModeration(" public Alice q=9",bounded.text); + assert(strlen(bounded.text)==159 && !strncmp(bounded.text,"OK - ",5)); + assert(std::string(bounded.text+5)==std::string(154,'X')); + assert(bounded.canary==0xA5B6C7D8); + } + moderation_detail_reply="> saved"; const auto original=second.files[target]; for(const char* invalid : {" public Alice q=1 rate=2/min", " public Alice rate=1/min q=2", " public Alice d q=2", " public Alice q=2 drop", " public Alice q=", " public Alice q=-1", diff --git a/test/test_webconfig_ui_runtime.py b/test/test_webconfig_ui_runtime.py index eaa254c2e..4b43beacc 100644 --- a/test/test_webconfig_ui_runtime.py +++ b/test/test_webconfig_ui_runtime.py @@ -233,8 +233,13 @@ window.addEventListener("load",function(){ self.assertIsNotNone(marker) page = source.replace(marker, prelude + marker, 1) + # Snap Chromium has a private /tmp. Keep the page and profile in the + # shared workspace so every supported browser can read them. + cache_root = ROOT / ".pio" + cache_root.mkdir(exist_ok=True) for attempt in range(2): with tempfile.TemporaryDirectory(prefix="meshcore-webconfig-runtime-", + dir=cache_root, ignore_cleanup_errors=True) as tmp: tmp_path = Path(tmp) html = tmp_path / "index.html" @@ -265,6 +270,7 @@ window.addEventListener("load",function(){ stderr = result.stderr.decode("utf-8", "replace") self.assertEqual(result.returncode, 0, stderr) dom = result.stdout.decode("utf-8", "replace") + self.assertTrue(dom, stderr) self.assertNotIn("data-test-error=", dom) return dom