What changed, and why it matters
This commit makes small, non-security improvements to how SeedSigner discovers language files and how settings are exported. It removes a script that could write a settings definition file to a microSD card, but that script only ran when a developer manually executed the file. There is no clear security vulnerability being fixed.
No urgent action. Reviewers can treat this as a routine refactor. If the removed __main__ export was relied upon for manufacturing or diagnostics, verify an alternative export path exists.
Security signals we found
Removal of a standalone export script that wrote to /mnt/microsd when executed on the device hostname
Path traversal/reliability improvement: replaces cwd-based path construction with resolved pathlib paths
No explicit security bug, CVE, or vulnerability fix present in the diff
Evidence from the diff
The diff changes language autodetection to use pathlib.Path(file) instead of os.getcwd(), making it more robust across execution contexts. It adds a fallback so SettingsEntry.abbreviated_name defaults to attr_name when empty. It extends get_defaults() with optional flags (use_abbreviated_name, skip_hidden) for test-suite use. Finally, it removes the if name == ‘main’ block that exported settings_definition.json to /mnt/microsd on the device or the local directory otherwise. None of these changes patch an exploitable flaw; they are code-quality and generator-tooling improvements.
Changed components
src/seedsigner/models/settings_definition.pySettingsConstants.get_detected_languages()SettingsEntry.__post_init__()SettingsDefinition.get_defaults()Inspect captured patch +24 / −27
diff --git a/src/seedsigner/models/settings_definition.py b/src/seedsigner/models/settings_definition.py
index e9310d1..8bf534e 100644
--- a/src/seedsigner/models/settings_definition.py
+++ b/src/seedsigner/models/settings_definition.py
@@ -1,4 +1,5 @@
import os
+import pathlib
from dataclasses import dataclass
from typing import Any, List
@@ -182,6 +183,7 @@ class SettingsConstants:
LOCALE__VIETNAMESE: "Tiếng Việt (Vietnamese)",
}
+
@classmethod
def get_detected_languages(cls) -> list[tuple[str, str]]:
"""
@@ -189,22 +191,20 @@ class SettingsConstants:
Scans the filesystem to autodiscover which language codes are onboard.
"""
- # Will normally be the launch dir (where main.py is located)...
- cwd = os.getcwd()
-
- # ...except when running the tests which happens one dir higher
- if "src" not in cwd:
- cwd = os.path.join(cwd, "src")
+ # Back out from the models/ dir to reach the seedsigner root
+ models_dir = pathlib.Path(__file__).parent.resolve()
+ seedsigner_root = models_dir.parent.resolve()
# Pre-load English since there's no "en" entry in the translations folder; also
# it should always appear first in the list anyway.
detected_languages = [(cls.LOCALE__ENGLISH, cls.ALL_LOCALES[cls.LOCALE__ENGLISH])]
locales_present = set()
- for root, dirs, files in os.walk(os.path.join(cwd, "seedsigner", "resources", "seedsigner-translations", "l10n")):
+ for root, dirs, files in os.walk(os.path.join(seedsigner_root, "resources", "seedsigner-translations", "l10n")):
for file in [f for f in files if f.endswith(".mo")]:
# `root` will be [...]seedsigner/resources/seedsigner-translations/l10n/pt_BR/LC_MESSAGES
- locales_present.add(root.split(f"l10n{ os.sep }")[1].split(os.sep)[0])
+ # Isolate the language code from the path
+ locales_present.add(root.rsplit(os.sep, 2)[-2])
for locale in cls.ALL_LOCALES.keys():
if locale in locales_present:
@@ -451,6 +451,9 @@ class SettingsEntry:
elif type(self.default_value) == tuple:
self.default_value = self.default_value[0]
+ if not self.abbreviated_name:
+ self.abbreviated_name = self.attr_name
+
@property
def selection_options_display_names(self) -> List[str]:
@@ -774,15 +777,25 @@ class SettingsDefinition:
@classmethod
- def get_defaults(cls) -> dict:
+ def get_defaults(cls, use_abbreviated_name: bool = False, skip_hidden: bool = False) -> dict:
+ """
+ * use_abbreviated_name: Only used by the test suite.
+ * skip_hidden: Only used by the test suite.
+ """
as_dict = {}
for entry in SettingsDefinition.settings_entries:
+ if skip_hidden and entry.visibility == SettingsConstants.VISIBILITY__HIDDEN:
+ continue
+ if not use_abbreviated_name:
+ attr_name = entry.attr_name
+ else:
+ attr_name = entry.abbreviated_name
if type(entry.default_value) == list:
# Must copy the default_value list, otherwise we'll inadvertently change
# defaults when updating these attrs
- as_dict[entry.attr_name] = list(entry.default_value)
+ as_dict[attr_name] = list(entry.default_value)
else:
- as_dict[entry.attr_name] = entry.default_value
+ as_dict[attr_name] = entry.default_value
return as_dict
@@ -795,19 +808,3 @@ class SettingsDefinition:
output["settings_entries"].append(settings_entry.to_dict())
return output
-
-
-
-if __name__ == "__main__":
- import json
- import os
-
- hostname = os.uname()[1]
-
- if hostname == "seedsigner-os":
- output_file = "/mnt/microsd/settings_definition.json"
- else:
- output_file = "settings_definition.json"
-
- with open(output_file, 'w') as json_file:
- json.dump(SettingsDefinition.to_dict(), json_file, indent=4)
Why this scored 16/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.