TEST#6
Conversation
…re missing, replaced mentions of the old GitHub by the new repo, fixed the issue Hogjects#200. No AI used.
Please enter the commit message for your changes. Lines starting with '' will be ignored, and an empty message aborts the commit. On branch dev Your branch is up to date with 'origin/dev'. Changes to be committed: modified: src/lufus/gui/dialogs.py modified: src/lufus/gui/gui.py modified: src/lufus/gui/languages/Deutsch.csv modified: src/lufus/gui/languages/English.csv modified: "src/lufus/gui/languages/Espa\303\261ol.csv" modified: "src/lufus/gui/languages/Fran\303\247ais.csv" modified: "src/lufus/gui/languages/Portugue\314\202s Brasileiro.csv" modified: src/lufus/gui/languages/Svenska.csv modified: "src/lufus/gui/languages/\320\240\321\203\321\201\321\201\320\272\320\270\320\271.csv" modified: "src/lufus/gui/languages/\321\203\320\272\321\200\320\260\321\227\320\275\321\201\321\214\320\272\320\260.csv" modified: "src/lufus/gui/languages/\330\271\330\261\330\250\331\212.csv" modified: "src/lufus/gui/languages/\340\246\254\340\246\276\340\246\202\340\246\262\340\246\276.csv"
Please enter the commit message for your changes. Lines starting with '' will be ignored, and an empty message aborts the commit. On branch dev Your branch is ahead of 'origin/dev' by 1 commit. (use "git push" to publish your local commits) Changes to be committed: modified: src/lufus/gui/dialogs.py modified: src/lufus/gui/gui.py modified: "src/lufus/gui/languages/Espa\303\261ol.csv" modified: "src/lufus/gui/languages/\320\240\321\203\321\201\321\201\320\272\320\270\320\271.csv" modified: "src/lufus/gui/languages/\321\203\320\272\321\200\320\260\321\227\320\275\321\201\321\214\320\272\320\260.csv" modified: "src/lufus/gui/languages/\330\271\330\261\330\250\331\212.csv" modified: "src/lufus/gui/languages/\340\246\254\340\246\276\340\246\202\340\246\262\340\246\276.csv"
…d some scaling. Please enter the commit message for your changes. Lines starting with '' will be ignored, and an empty message aborts the commit. On branch dev Your branch is ahead of 'origin/dev' by 2 commits. (use "git push" to publish your local commits) Changes to be committed: new file: src/lufus/browse_freely.py modified: src/lufus/gui/dialogs.py modified: src/lufus/gui/gui.py
Please enter the commit message for your changes. Lines starting with '' will be ignored, and an empty message aborts the commit. On branch dev Your branch is ahead of 'origin/dev' by 4 commits. (use "git push" to publish your local commits) Changes to be committed: new file: tests/test_browse_freely.py
Reviewer's GuideRefactors low-level disk, ISO, and browser handling into pure-Python helpers while adding safer flashing UX (pre-flash warning, bad-block passes), persistent language/theme handling across privilege elevation, and updating all GitHub/org metadata and tests to match the new Hogjects organization. Sequence diagram for updated flashing flow with warning and bad-block checksequenceDiagram
actor User
participant MainWindow as gui.MainWindow
participant FlashWorker as gui.workers.FlashWorker
participant Formatting as drives.formatting
participant FlashUSB as writing.flash_usb
participant BlockOps as block_ops
User->>MainWindow: click btn_start
MainWindow->>MainWindow: perform_flash()
MainWindow->>MainWindow: QMessageBox
alt user cancels
MainWindow->>MainWindow: log_message("Flash aborted by user...")
MainWindow->>User: re-enable Start, reset progress
else user confirms
MainWindow->>FlashWorker: start()
FlashWorker->>FlashWorker: run()
FlashWorker->>Formatting: check_device_bad_blocks(passes=states.bad_blocks_passes)
alt badblocks fails
FlashWorker->>MainWindow: flash_done(False)
else badblocks OK or disabled
FlashWorker->>FlashUSB: flash_image(device_node, iso_path,...)
FlashUSB->>BlockOps: write_device_image(iso_path, device, bs, progress_cb, status_cb)
BlockOps-->>FlashUSB: return code
FlashUSB-->>FlashWorker: success / failure
FlashWorker-->>MainWindow: flash_done(result)
end
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- In
launch_gui_with_usb_data,_load_initial_language()is called both before and afterelevate_privileges(), which means the post-elevation call may read the root user’s config and overwrite the intended user language; consider only initializing language in the non-root context or guarding the second call appropriately. - In
open_url_non_root, when onlySUDO_USERis set you never derive a UID, soXDG_RUNTIME_DIRis left empty; consider resolving the UID forsudo_user(e.g. viapwd.getpwnam) to populate a more accurate environment for GUI apps.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `launch_gui_with_usb_data`, `_load_initial_language()` is called both before and after `elevate_privileges()`, which means the post-elevation call may read the root user’s config and overwrite the intended user language; consider only initializing language in the non-root context or guarding the second call appropriately.
- In `open_url_non_root`, when only `SUDO_USER` is set you never derive a UID, so `XDG_RUNTIME_DIR` is left empty; consider resolving the UID for `sudo_user` (e.g. via `pwd.getpwnam`) to populate a more accurate environment for GUI apps.
## Individual Comments
### Comment 1
<location path="src/lufus/browse_freely.py" line_range="39" />
<code_context>
+
+ # Method 1: Use runuser which is specifically designed for this
+ # We need to preserve the environment for the GUI session
+ env = {
+ "DISPLAY": os.environ.get("DISPLAY", ":0"),
+ "XAUTHORITY": os.environ.get("XAUTHORITY", ""),
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Environment for the spawned browser process does not set HOME, which may cause profile or permission issues.
Since many GUI apps depend on `HOME` for profiles and config, relying only on `DISPLAY`, `XAUTHORITY`, `XDG_RUNTIME_DIR`, `WAYLAND_DISPLAY`, and `PATH` risks using root’s home (or none) when running as another user, especially in the `sudo_user` case without `target_uid`. Please also set `HOME` to the target user’s home directory (e.g. `pwd.getpwnam(target_user).pw_dir`) and add it to `env` when available.
Suggested implementation:
```python
import os
import pwd
```
```python
if target_user:
try:
log.info(f"Attempting to open URL as user {target_user} (UID {target_uid}): {url}")
# Determine the target user's home directory so GUI apps use the correct profile/config
home_dir = None
try:
home_dir = pwd.getpwnam(target_user).pw_dir
except KeyError:
log.warning("Could not determine home directory for user %s", target_user)
# Method 1: Use runuser which is specifically designed for this
# We need to preserve the environment for the GUI session
env = {
"DISPLAY": os.environ.get("DISPLAY", ":0"),
"XAUTHORITY": os.environ.get("XAUTHORITY", ""),
"XDG_RUNTIME_DIR": os.environ.get(
"XDG_RUNTIME_DIR", f"/run/user/{target_uid}" if target_uid else ""
),
"WAYLAND_DISPLAY": os.environ.get("WAYLAND_DISPLAY", ""),
"PATH": "/usr/local/bin:/usr/bin:/bin",
# Ensure HOME is set so GUI apps use the target user's profile and config
"HOME": home_dir or os.environ.get("HOME", ""),
}
# Filter out empty values
env = {k: v for k, v in env.items() if v}
```
If `pwd` is already imported elsewhere in this file, adjust the import edit accordingly to avoid duplicate imports (e.g. by adding it to an existing import line instead of introducing a new one).
</issue_to_address>
### Comment 2
<location path="tests/test_browse_freely.py" line_range="11-20" />
<code_context>
+ self.assertEqual(env.get("DISPLAY"), ":0")
+ self.assertEqual(env.get("XDG_RUNTIME_DIR"), "/run/user/1000")
+
+ @patch("os.geteuid")
+ @patch("os.environ.get")
+ @patch("subprocess.Popen")
+ def test_open_url_as_root_via_sudo(self, mock_popen, mock_env_get, mock_geteuid):
+ # Simulate root (UID 0)
+ mock_geteuid.return_value = 0
</code_context>
<issue_to_address>
**suggestion (testing):** Consider using `patch.dict(os.environ, ...)` instead of patching `os.environ.get` to make the tests more realistic and resilient.
Patching `os.environ.get` with a `side_effect` intercepts every env lookup (e.g. `DISPLAY`, `XAUTHORITY`, `XDG_RUNTIME_DIR`), which couples the tests to the exact way `open_url_non_root` reads the environment. Instead, patching `os.environ` via `patch.dict(os.environ, {"PKEXEC_UID": "1000", ...}, clear=False)` (and similarly for the sudo case) more accurately reflects real usage and keeps the tests resilient to internal changes in environment access.
Suggested implementation:
```python
@patch("os.geteuid")
@patch("subprocess.Popen")
@patch("pwd.getpwuid")
def test_open_url_as_root_via_pkexec(self, mock_getpwuid, mock_popen, mock_geteuid):
```
```python
# Mock environment variables
env_overrides = {
"PKEXEC_UID": "1000",
"DISPLAY": ":0",
"XDG_RUNTIME_DIR": "/run/user/1000",
}
with patch.dict(os.environ, env_overrides, clear=False):
open_url_non_root(self.url)
# Mock pwd info
```
1. Apply a similar refactor to the `test_open_url_as_root_via_sudo` test: remove any `@patch("os.environ.get")` decorator and associated `mock_env_get` parameter, and replace any `side_effect`-based environment mocking with a `with patch.dict(os.environ, {...}, clear=False):` block that sets the sudo-related variables your production code expects (e.g. `SUDO_USER`, `DISPLAY`, `XDG_RUNTIME_DIR`, etc.), wrapping the `open_url_non_root(self.url)` call in that context.
2. If there are other tests in this file that also patch `os.environ.get`, consider converting them to `patch.dict` in the same way to keep the test suite consistent and resilient to internal environment access changes.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| @patch("os.geteuid") | ||
| @patch("webbrowser.open") | ||
| def test_open_url_non_root_as_regular_user(self, mock_webbrowser, mock_geteuid): | ||
| # Simulate regular user (UID 1000) | ||
| mock_geteuid.return_value = 1000 | ||
|
|
||
| open_url_non_root(self.url) | ||
|
|
||
| # Should fallback to standard webbrowser.open | ||
| mock_webbrowser.assert_called_once_with(self.url) |
There was a problem hiding this comment.
suggestion (testing): Consider using patch.dict(os.environ, ...) instead of patching os.environ.get to make the tests more realistic and resilient.
Patching os.environ.get with a side_effect intercepts every env lookup (e.g. DISPLAY, XAUTHORITY, XDG_RUNTIME_DIR), which couples the tests to the exact way open_url_non_root reads the environment. Instead, patching os.environ via patch.dict(os.environ, {"PKEXEC_UID": "1000", ...}, clear=False) (and similarly for the sudo case) more accurately reflects real usage and keeps the tests resilient to internal changes in environment access.
Suggested implementation:
@patch("os.geteuid")
@patch("subprocess.Popen")
@patch("pwd.getpwuid")
def test_open_url_as_root_via_pkexec(self, mock_getpwuid, mock_popen, mock_geteuid): # Mock environment variables
env_overrides = {
"PKEXEC_UID": "1000",
"DISPLAY": ":0",
"XDG_RUNTIME_DIR": "/run/user/1000",
}
with patch.dict(os.environ, env_overrides, clear=False):
open_url_non_root(self.url)
# Mock pwd info- Apply a similar refactor to the
test_open_url_as_root_via_sudotest: remove any@patch("os.environ.get")decorator and associatedmock_env_getparameter, and replace anyside_effect-based environment mocking with awith patch.dict(os.environ, {...}, clear=False):block that sets the sudo-related variables your production code expects (e.g.SUDO_USER,DISPLAY,XDG_RUNTIME_DIR, etc.), wrapping theopen_url_non_root(self.url)call in that context. - If there are other tests in this file that also patch
os.environ.get, consider converting them topatch.dictin the same way to keep the test suite consistent and resilient to internal environment access changes.
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey - I've found 2 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/lufus/gui/i18n.py" line_range="29-38" />
<code_context>
+ Falls back to English if detection fails or no match is found.
+ """
+ try:
+ loc = locale.getdefaultlocale()
+ except Exception:
+ loc = (None, None)
</code_context>
<issue_to_address>
**suggestion:** Using `locale.getdefaultlocale()` may be problematic going forward due to deprecation; consider an alternative approach.
`locale.getdefaultlocale()` is deprecated in recent Python versions and may be removed. Since only the language is needed, consider alternatives such as `locale.getlocale()[0]`, `os.environ.get("LANG")`, or `locale.setlocale(locale.LC_CTYPE, "")` followed by `locale.getlocale()` to avoid relying on a deprecated API.
```suggestion
def detect_system_language() -> str:
"""Detect the system locale and return the matching language name.
Falls back to English if detection fails or no match is found.
"""
try:
# Ensure locale is initialized from the environment, then read current locale.
locale.setlocale(locale.LC_CTYPE, "")
loc = locale.getlocale()
except Exception:
loc = (None, None)
lang_code = (loc[0] or "") or os.environ.get("LANG", "")
```
</issue_to_address>
### Comment 2
<location path="tests/test_flash_usb_and_find_usb_fixes.py" line_range="148-149" />
<code_context>
pass
class FakePipe:
- def readline(self):
+ def read(self, n=-1):
return b""
</code_context>
<issue_to_address>
**suggestion (testing):** Strengthen the fake stderr pipe to assert that `read` is called with the expected chunk size (4096).
`FakePipe.read` currently ignores `n` and always returns `b""`, so the test doesn’t verify that `process.stderr.read(4096)` is actually called with the intended chunk size. Consider recording the passed-in `n` (e.g., `self.last_n = n`) and asserting it is `4096` (or at least `> 0`) after the call to catch regressions like switching back to `readline()` or changing the chunk size.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| class FakePipe: | ||
| def readline(self): | ||
| def read(self, n=-1): |
There was a problem hiding this comment.
suggestion (testing): Strengthen the fake stderr pipe to assert that read is called with the expected chunk size (4096).
FakePipe.read currently ignores n and always returns b"", so the test doesn’t verify that process.stderr.read(4096) is actually called with the intended chunk size. Consider recording the passed-in n (e.g., self.last_n = n) and asserting it is 4096 (or at least > 0) after the call to catch regressions like switching back to readline() or changing the chunk size.
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/lufus/gui/i18n.py" line_range="34-41" />
<code_context>
+ Falls back to English if detection fails or no match is found.
+ """
+ try:
+ # Ensure locale is initialized from the environment, then read current locale.
+ locale.setlocale(locale.LC_CTYPE, "")
+ loc = locale.getlocale()
+ except Exception:
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Calling `locale.setlocale` here mutates global process state and may have unintended side effects.
`locale.setlocale(locale.LC_CTYPE, "")` here mutates the global locale and can unexpectedly impact formatting/parsing and libraries that depend on locale (e.g. Qt). If you only need to detect the system locale, prefer `locale.getdefaultlocale()` or environment variables (e.g. `$LANG`) without changing the active locale, or temporarily change it and immediately restore the original value.
```suggestion
try:
# Read the system locale without mutating global locale state.
loc = locale.getdefaultlocale()
except Exception:
loc = (None, None)
# Fallback to the process locale if the default locale could not be determined.
if not loc or not loc[0]:
try:
loc = locale.getlocale()
except Exception:
loc = (None, None)
lang_code = (loc[0] or "") or os.environ.get("LANG", "")
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
broke smth i think |
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- open_url_non_root() unconditionally calls os.geteuid(), which will raise on platforms without that API (e.g. Windows); consider guarding this with hasattr/os.name checks or a try/except and treating such platforms as non-root so the function safely falls back to webbrowser.open.
- _load_initial_language() swallows all exceptions and may leave state.language unset or stale; it would be safer to explicitly default to 'English' (or another known language) when detection/persistence fails so the GUI always has a predictable language value.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- open_url_non_root() unconditionally calls os.geteuid(), which will raise on platforms without that API (e.g. Windows); consider guarding this with hasattr/os.name checks or a try/except and treating such platforms as non-root so the function safely falls back to webbrowser.open.
- _load_initial_language() swallows all exceptions and may leave state.language unset or stale; it would be safer to explicitly default to 'English' (or another known language) when detection/persistence fails so the GUI always has a predictable language value.
## Individual Comments
### Comment 1
<location path="src/lufus/browse_freely.py" line_range="43-55" />
<code_context>
+
+ # Method 1: Use runuser which is specifically designed for this
+ # We need to preserve the environment for the GUI session
+ env = {
+ "DISPLAY": os.environ.get("DISPLAY", ":0"),
+ "XAUTHORITY": os.environ.get("XAUTHORITY", ""),
+ "XDG_RUNTIME_DIR": os.environ.get(
+ "XDG_RUNTIME_DIR", f"/run/user/{target_uid}" if target_uid else ""
+ ),
+ "WAYLAND_DISPLAY": os.environ.get("WAYLAND_DISPLAY", ""),
+ "PATH": "/usr/local/bin:/usr/bin:/bin",
+ # Ensure HOME is set so GUI apps use the target user's profile and config
+ "HOME": home_dir or os.environ.get("HOME", ""),
+ }
+
</code_context>
<issue_to_address>
**suggestion:** Environment for `runuser` may be missing session-related variables needed by some desktop environments.
For `xdg-open` via `runuser`, some DEs (especially under Wayland) also depend on `DBUS_SESSION_BUS_ADDRESS` and similar session vars. Consider propagating it when present, for example:
```python
env = {
"DISPLAY": os.environ.get("DISPLAY", ":0"),
"XAUTHORITY": os.environ.get("XAUTHORITY", ""),
"XDG_RUNTIME_DIR": os.environ.get(
"XDG_RUNTIME_DIR", f"/run/user/{target_uid}" if target_uid else ""
),
"WAYLAND_DISPLAY": os.environ.get("WAYLAND_DISPLAY", ""),
"DBUS_SESSION_BUS_ADDRESS": os.environ.get("DBUS_SESSION_BUS_ADDRESS", ""),
"PATH": "/usr/local/bin:/usr/bin:/bin",
"HOME": home_dir or os.environ.get("HOME", ""),
}
```
This reduces cases where `xdg-open` fails under certain desktop environments.
```suggestion
# Method 1: Use runuser which is specifically designed for this
# We need to preserve the environment for the GUI session
env = {
"DISPLAY": os.environ.get("DISPLAY", ":0"),
"XAUTHORITY": os.environ.get("XAUTHORITY", ""),
"XDG_RUNTIME_DIR": os.environ.get(
"XDG_RUNTIME_DIR", f"/run/user/{target_uid}" if target_uid else ""
),
"WAYLAND_DISPLAY": os.environ.get("WAYLAND_DISPLAY", ""),
# Propagate DBUS session bus so xdg-open works under more DEs/Wayland sessions
"DBUS_SESSION_BUS_ADDRESS": os.environ.get("DBUS_SESSION_BUS_ADDRESS", ""),
"PATH": "/usr/local/bin:/usr/bin:/bin",
# Ensure HOME is set so GUI apps use the target user's profile and config
"HOME": home_dir or os.environ.get("HOME", ""),
}
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| # Method 1: Use runuser which is specifically designed for this | ||
| # We need to preserve the environment for the GUI session | ||
| env = { | ||
| "DISPLAY": os.environ.get("DISPLAY", ":0"), | ||
| "XAUTHORITY": os.environ.get("XAUTHORITY", ""), | ||
| "XDG_RUNTIME_DIR": os.environ.get( | ||
| "XDG_RUNTIME_DIR", f"/run/user/{target_uid}" if target_uid else "" | ||
| ), | ||
| "WAYLAND_DISPLAY": os.environ.get("WAYLAND_DISPLAY", ""), | ||
| "PATH": "/usr/local/bin:/usr/bin:/bin", | ||
| # Ensure HOME is set so GUI apps use the target user's profile and config | ||
| "HOME": home_dir or os.environ.get("HOME", ""), | ||
| } |
There was a problem hiding this comment.
suggestion: Environment for runuser may be missing session-related variables needed by some desktop environments.
For xdg-open via runuser, some DEs (especially under Wayland) also depend on DBUS_SESSION_BUS_ADDRESS and similar session vars. Consider propagating it when present, for example:
env = {
"DISPLAY": os.environ.get("DISPLAY", ":0"),
"XAUTHORITY": os.environ.get("XAUTHORITY", ""),
"XDG_RUNTIME_DIR": os.environ.get(
"XDG_RUNTIME_DIR", f"/run/user/{target_uid}" if target_uid else ""
),
"WAYLAND_DISPLAY": os.environ.get("WAYLAND_DISPLAY", ""),
"DBUS_SESSION_BUS_ADDRESS": os.environ.get("DBUS_SESSION_BUS_ADDRESS", ""),
"PATH": "/usr/local/bin:/usr/bin:/bin",
"HOME": home_dir or os.environ.get("HOME", ""),
}This reduces cases where xdg-open fails under certain desktop environments.
| # Method 1: Use runuser which is specifically designed for this | |
| # We need to preserve the environment for the GUI session | |
| env = { | |
| "DISPLAY": os.environ.get("DISPLAY", ":0"), | |
| "XAUTHORITY": os.environ.get("XAUTHORITY", ""), | |
| "XDG_RUNTIME_DIR": os.environ.get( | |
| "XDG_RUNTIME_DIR", f"/run/user/{target_uid}" if target_uid else "" | |
| ), | |
| "WAYLAND_DISPLAY": os.environ.get("WAYLAND_DISPLAY", ""), | |
| "PATH": "/usr/local/bin:/usr/bin:/bin", | |
| # Ensure HOME is set so GUI apps use the target user's profile and config | |
| "HOME": home_dir or os.environ.get("HOME", ""), | |
| } | |
| # Method 1: Use runuser which is specifically designed for this | |
| # We need to preserve the environment for the GUI session | |
| env = { | |
| "DISPLAY": os.environ.get("DISPLAY", ":0"), | |
| "XAUTHORITY": os.environ.get("XAUTHORITY", ""), | |
| "XDG_RUNTIME_DIR": os.environ.get( | |
| "XDG_RUNTIME_DIR", f"/run/user/{target_uid}" if target_uid else "" | |
| ), | |
| "WAYLAND_DISPLAY": os.environ.get("WAYLAND_DISPLAY", ""), | |
| # Propagate DBUS session bus so xdg-open works under more DEs/Wayland sessions | |
| "DBUS_SESSION_BUS_ADDRESS": os.environ.get("DBUS_SESSION_BUS_ADDRESS", ""), | |
| "PATH": "/usr/local/bin:/usr/bin:/bin", | |
| # Ensure HOME is set so GUI apps use the target user's profile and config | |
| "HOME": home_dir or os.environ.get("HOME", ""), | |
| } |
|
Dgaf about windows lmao |
|
and Hogjects#184, too |
Please enter the commit message for your changes. Lines starting with '' will be ignored, and an empty message aborts the commit. On branch dev Your branch is up to date with 'origin/dev'. Changes to be committed: new file: src/lufus/block_ops.py modified: src/lufus/drives/find_usb.py modified: src/lufus/drives/formatting.py modified: src/lufus/drives/get_usb_info.py modified: src/lufus/gui/gui.py new file: src/lufus/iso9660.py modified: src/lufus/writing/flash_usb.py modified: src/lufus/writing/install_ventoy.py modified: src/lufus/writing/windows/detect.py modified: src/lufus/writing/windows/flash.py modified: src/lufus/writing/windows/tweaks.py modified: tests/test_find_usb.py modified: tests/test_flash_usb_and_find_usb_fixes.py modified: tests/test_formatting.py modified: tests/test_get_usb_info.py modified: tests/test_get_usb_info_and_detect_windows_fixes.py modified: tests/test_linux_iso_detection.py
|
Gonna test the new DVD stuff later w/ my thinkPad |
Please enter the commit message for your changes. Lines starting with '' will be ignored, and an empty message aborts the commit. On branch dev Your branch is ahead of 'origin/dev' by 1 commit. (use "git push" to publish your local commits) Changes to be committed: modified: src/lufus/drives/formatting.py modified: src/lufus/gui/gui.py modified: src/lufus/gui/workers.py modified: src/lufus/state.py modified: tests/test_states_and_autodetect_fixes.py
|
I think I fixed Hogjects#206 |
| (mkfs.*, wimlib-imagex, package managers). | ||
| """ | ||
| try: | ||
| return subprocess.run(cmd, check=check) |
There was a problem hiding this comment.
security (python.lang.security.audit.dangerous-subprocess-use-audit): Detected subprocess function 'run' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'.
Source: opengrep
… needs testing. Please enter the commit message for your changes. Lines starting with '' will be ignored, and an empty message aborts the commit. On branch dev Your branch is up to date with 'origin/dev'. Changes to be committed: new file: scripts/build-standalone.sh modified: src/lufus/block_ops.py modified: src/lufus/drives/formatting.py modified: src/lufus/gui/workers.py
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey - I've found 1 security issue, 2 other issues, and left some high level feedback:
Security issues:
- Detected subprocess function 'run' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'. (link)
General comments:
- The new
_reset_terminalhelper ingui.pycallstty.setrawand then immediately restores the previous settings; if the goal is astty saneequivalent it would be more robust to explicitly configure canonical/echo flags (and to no-op safely when stdin is not a TTY) rather than toggling raw mode briefly. - The pure-Python ISO 9660 walker in
iso9660.pycurrently only recurses shallowly and has comments about limited edge-case handling; if you expect to handle images with deeper directory trees or more complex layouts, consider either documenting these limits clearly in the detection functions or extending the traversal logic so detection doesn’t silently miss markers in nested paths.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new `_reset_terminal` helper in `gui.py` calls `tty.setraw` and then immediately restores the previous settings; if the goal is a `stty sane` equivalent it would be more robust to explicitly configure canonical/echo flags (and to no-op safely when stdin is not a TTY) rather than toggling raw mode briefly.
- The pure-Python ISO 9660 walker in `iso9660.py` currently only recurses shallowly and has comments about limited edge-case handling; if you expect to handle images with deeper directory trees or more complex layouts, consider either documenting these limits clearly in the detection functions or extending the traversal logic so detection doesn’t silently miss markers in nested paths.
## Individual Comments
### Comment 1
<location path="src/lufus/gui/gui.py" line_range="109-118" />
<code_context>
+ return len(pids)
+
+
+def _reset_terminal() -> None:
+ """Reset terminal to sane settings via termios (replaces stty sane)."""
+ import termios
+ import tty
+
+ fd = sys.stdin.fileno()
+ settings = termios.tcgetattr(fd)
+ # Restore defaults: echo on, canonical mode, etc.
+ tty.setraw(fd, when=termios.TCSAFLUSH)
+ termios.tcsetattr(fd, termios.TCSANOW, settings)
+
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Terminal reset helper likely does nothing useful and may misbehave on non-TTY stdin.
Because you immediately restore `settings` after `tty.setraw`, the raw mode is never actually in effect, so this function doesn’t meaningfully “reset” anything. In addition, `sys.stdin.fileno()` can fail or misbehave when stdin isn’t a TTY (e.g., redirection, some GUI launches).
If this helper is meant to repair a broken terminal, consider targeting `/dev/tty` (or at least guarding with `os.isatty(fd)`) and restoring a known-good canonical/echo configuration captured at program start, rather than briefly toggling raw mode and reverting.
</issue_to_address>
### Comment 2
<location path="src/lufus/block_ops.py" line_range="228-231" />
<code_context>
+_GPT_PARTITIONS_DEFAULT_COUNT = 128 # standard GPT allows up to 128 entries
+
+# Partition type GUIDs (binary, little-endian format)
+_PART_TYPE_GUID = {
+ "data": bytes.fromhex("a2a0d0ebe5b9334487c068b6b72699c7"), # Microsoft Basic Data
+ "efi": bytes.fromhex("28732ac11ff8d211ba4b00a0c93ec93b"), # EFI System
+ "bios": bytes.fromhex("614886496e6f44746961676f6e6100"), # BIOS Boot
+}
+
</code_context>
<issue_to_address>
**issue (bug_risk):** BIOS boot partition type GUID and GPT layout look non-spec-compliant and may confuse firmware or tools.
The GUID and on-disk layout logic need correction:
* The `"bios"` GUID hex (`"614886496e6f44746961676f6e6100"`) is only 30 hex chars (15 bytes) and doesn’t match the standard BIOS Boot type GUID (`21686148-6449-6E6F-744E-656564454649`). `bytes.fromhex` will accept it, but GPT type GUIDs must be 16 bytes; this will create malformed partition entries.
* In `_write_gpt`, the backup header’s `partition_entries_lba` currently points to the primary entries, but you write the backup entries near the end of the disk. The backup header must point to the backup partition entry array, per the GPT spec.
* The protective MBR entry layout is nonstandard: `mbr += struct.pack("<I", 0x00000200)` at offset 446 overwrites the CHS and type fields instead of writing a proper 16‑byte partition entry.
Given that this code prepares real disks, I’d strongly recommend either fixing the GUID constants and strictly following the UEFI GPT/MBR layouts, or delegating partition table creation to a well-tested library/wrapper to avoid subtle on-disk corruption.
</issue_to_address>
### Comment 3
<location path="src/lufus/writing/windows/flash.py" line_range="34" />
<code_context>
return subprocess.run(cmd, check=check)
</code_context>
<issue_to_address>
**security (python.lang.security.audit.dangerous-subprocess-use-audit):** Detected subprocess function 'run' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'.
*Source: opengrep*
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| def _reset_terminal() -> None: | ||
| """Reset terminal to sane settings via termios (replaces stty sane).""" | ||
| import termios | ||
| import tty | ||
|
|
||
| fd = sys.stdin.fileno() | ||
| settings = termios.tcgetattr(fd) | ||
| # Restore defaults: echo on, canonical mode, etc. | ||
| tty.setraw(fd, when=termios.TCSAFLUSH) | ||
| termios.tcsetattr(fd, termios.TCSANOW, settings) |
There was a problem hiding this comment.
issue (bug_risk): Terminal reset helper likely does nothing useful and may misbehave on non-TTY stdin.
Because you immediately restore settings after tty.setraw, the raw mode is never actually in effect, so this function doesn’t meaningfully “reset” anything. In addition, sys.stdin.fileno() can fail or misbehave when stdin isn’t a TTY (e.g., redirection, some GUI launches).
If this helper is meant to repair a broken terminal, consider targeting /dev/tty (or at least guarding with os.isatty(fd)) and restoring a known-good canonical/echo configuration captured at program start, rather than briefly toggling raw mode and reverting.
| _PART_TYPE_GUID = { | ||
| "data": bytes.fromhex("a2a0d0ebe5b9334487c068b6b72699c7"), # Microsoft Basic Data | ||
| "efi": bytes.fromhex("28732ac11ff8d211ba4b00a0c93ec93b"), # EFI System | ||
| "bios": bytes.fromhex("614886496e6f44746961676f6e6100"), # BIOS Boot |
There was a problem hiding this comment.
issue (bug_risk): BIOS boot partition type GUID and GPT layout look non-spec-compliant and may confuse firmware or tools.
The GUID and on-disk layout logic need correction:
- The
"bios"GUID hex ("614886496e6f44746961676f6e6100") is only 30 hex chars (15 bytes) and doesn’t match the standard BIOS Boot type GUID (21686148-6449-6E6F-744E-656564454649).bytes.fromhexwill accept it, but GPT type GUIDs must be 16 bytes; this will create malformed partition entries. - In
_write_gpt, the backup header’spartition_entries_lbacurrently points to the primary entries, but you write the backup entries near the end of the disk. The backup header must point to the backup partition entry array, per the GPT spec. - The protective MBR entry layout is nonstandard:
mbr += struct.pack("<I", 0x00000200)at offset 446 overwrites the CHS and type fields instead of writing a proper 16‑byte partition entry.
Given that this code prepares real disks, I’d strongly recommend either fixing the GUID constants and strictly following the UEFI GPT/MBR layouts, or delegating partition table creation to a well-tested library/wrapper to avoid subtle on-disk corruption.
| (mkfs.*, wimlib-imagex, package managers). | ||
| """ | ||
| try: | ||
| return subprocess.run(cmd, check=check) |
There was a problem hiding this comment.
security (python.lang.security.audit.dangerous-subprocess-use-audit): Detected subprocess function 'run' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'.
Source: opengrep
Summary by Sourcery
Refactor low-level device, filesystem, and ISO handling to use pure Python helpers instead of external utilities, improve UX around flashing and bad block checks, persist and auto-detect language and theme, and update project metadata and links to the new GitHub organization.
New Features:
Bug Fixes:
Enhancements:
Build:
Documentation:
Tests: