From f124e5cfc69adb8623d844a427745d4ceeb09783 Mon Sep 17 00:00:00 2001 From: Dhevenddra K G <121691114+Dhevenddra@users.noreply.github.com> Date: Sun, 2 Aug 2026 11:38:30 +0530 Subject: [PATCH] test: fix the install-flags structural guard failing on main (#3116) Two defects, the second hidden behind the first. CI runs ruff only, so neither shows up there. The generic-403 guard counted the copy across all of js/common.js while its docstring describes exactly the two occurrences inside handle403Response. A third, unrelated use at line 722 builds the batch-uninstall error message, so the file-wide count tripped on it. Scoped the count to the handle403Response block via the existing _js_function_block helper. This part is not platform-specific; the count is 3 on Linux and Windows alike. With that passing, the test reached a loop calling js_file.read_text() with no encoding. That uses the locale encoding, so on cp1252 Windows it raises UnicodeDecodeError on the four js files containing emoji. Passed encoding="utf-8" explicitly, and did the same for the other four read_text calls in the file, which read ASCII sources today and so pass by luck. --- tests/test_install_flags_structural.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/test_install_flags_structural.py b/tests/test_install_flags_structural.py index 20e7d89c3..e5653105a 100644 --- a/tests/test_install_flags_structural.py +++ b/tests/test_install_flags_structural.py @@ -54,7 +54,7 @@ class JsCopyStructuralTest(unittest.TestCase): @classmethod def setUpClass(cls): - cls.common_src = JS_COMMON_PATH.read_text() + cls.common_src = JS_COMMON_PATH.read_text(encoding="utf-8") def test_surface_messages_name_their_flag(self): """Both install 403 branches pass a flag-naming defaultMessage.""" @@ -76,14 +76,19 @@ class JsCopyStructuralTest(unittest.TestCase): """The generic fallback copy stays (exactly its two occurrences in handle403Response), and no other handle403Response caller across js/ gains a defaultMessage.""" - self.assertEqual(self.common_src.count(GENERIC_403_COPY), 2) + # Count inside handle403Response rather than file-wide. The same + # sentence is legitimately reused elsewhere in common.js to build a + # batch-uninstall error message, which is not a caller of + # handle403Response and so is outside this guard's contract. + handle_block = _js_function_block(self.common_src, "handle403Response") + self.assertEqual(handle_block.count(GENERIC_403_COPY), 2) surface_blocks = "".join( _js_function_block(self.common_src, name) for name in ("install_pip", "install_via_git_url") ) allowed_two_arg = {a for a in _handle403_call_args(surface_blocks) if "," in a} for js_file in sorted((REPO_ROOT / "js").glob("*.js")): - source = js_file.read_text() + source = js_file.read_text(encoding="utf-8") for args in _handle403_call_args(source): if "," in args: self.assertIn( @@ -98,7 +103,7 @@ class StructuralSecurityGuardsTest(unittest.TestCase): def test_no_new_install_route_surface(self): """No new HTTP surface for git-URL/pip install.""" - source = MANAGER_SERVER_PATH.read_text() + source = MANAGER_SERVER_PATH.read_text(encoding="utf-8") routes = set(re.findall(r"@routes\.post\(\"([^\"]+)\"\)", source)) expected_surfaces = { "/customnode/install/git_url", @@ -117,14 +122,14 @@ class StructuralSecurityGuardsTest(unittest.TestCase): def test_cm_cli_ungated(self): """cm-cli stays a local operator tool — no gate, no flag lookup.""" - source = CM_CLI_PATH.read_text() + source = CM_CLI_PATH.read_text(encoding="utf-8") for token in FLAG_TOKENS + ("is_allowed_security_level", "is_dedicated_install_allowed"): self.assertNotIn(token, source, "cm-cli.py must stay ungated") def test_no_autoseed_in_migration(self): """The migration module never references the flags (explicit opt-in only — no auto-seed from security_level).""" - source = MANAGER_MIGRATION_PATH.read_text() + source = MANAGER_MIGRATION_PATH.read_text(encoding="utf-8") for token in FLAG_TOKENS: self.assertNotIn( token, source,