Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Propagate CLI arguments when updating #16937

Merged
merged 10 commits into from
Aug 7, 2024
Merged

Propagate CLI arguments when updating #16937

merged 10 commits into from
Aug 7, 2024

Conversation

SaschaCowley
Copy link
Member

@SaschaCowley SaschaCowley commented Aug 1, 2024

Link to issue number:

None

Summary of the issue:

When updating NVDA, command line arguments are not passed from the running copy to the temporary copy. This may have security implications for arguments such as -c or --disable-addons.

Description of user facing changes

The -c/--config-path and --disable-addons arguments are now propagated to the temporary copy of NVDA when an update is started from within NVDA.

Description of development approach

Refactored updateCheck._executeUpdate to use a helper function to generate the parameters to call the launcher with. In addition to the parameters that were already passed, the following parameters are now passed:

  • If globalVars.appArgs.disableAddons is True, the --disable-addons flag is passed.
  • The --config-path argument is passed with the current configuration directory. We do not directly pass the path that NVDA was called with because:
    • If -c wasn't specified at the CLI, it will be the default config path, which is what NVDA would have defaulted to anyway.
    • If it was specified at the CLI, it will be what was specified there, as the only change we make to it is to absolutise it.
    • Sniffing sys.argv to find -c or --config-path adds a performance overhead (and code complexity) for no benefit, because anyone fiddling around to change globalVars.appArgs.configPath or NVDAState.WritePaths.ConfigDir can change sys.argv too.

Testing strategy:

Set buildVersion.version_major = 1, and built a launcher with updateVersionType=stable (since the current stable version is 2024.2).

Created a dummy add-on that beeps at NVDA start-up.

For each of the following test cases, I installed the dummy add-on and changed the synthesiser to eSpeak so it was easy to tell if the test cases were working as expected. The test cases were performed on installed and portable copies of NVDA as created with the launcher generated above.

The following tests were performed:

  • Ran nvda.exe. Updated NVDA and observed the add-on was run and customised settings were used.
  • Ran nvda.exe --disable-addons. Updated NVDA and observed the add-on was not run but customised settings were used.
  • Ran nvda.exe -c c:\test (nonexistant directory). Updated NVDA and observed the add-on was not run and default settings were used.

Known issues with pull request:

NVDA should ideally be refactored so that there is a single source of truth for its CLI args, as they're currently repeated in multiple places (nvda.pyw, globalVars.py, updateCheck.py and possibly others).

Code Review Checklist:

  • Documentation:
    • Change log entry
    • User Documentation
    • Developer / Technical Documentation
    • Context sensitive help for GUI changes
  • Testing:
    • Unit tests
    • System (end to end) tests
    • Manual testing
  • UX of all users considered:
    • Speech
    • Braille
    • Low Vision
    • Different web browsers
    • Localization in other languages / culture than English
  • API is compatible with existing add-ons.
  • Security precautions taken.

Summary by CodeRabbit

  • New Features

    • Enhanced command line options for NVDA, improving update controls with respect to configuration paths and add-ons.
    • Added functionality for generating execution parameters during installation, facilitating better handling of custom configurations.
  • Bug Fixes

    • Restored NVDA's reliance on events for caret movement, improving responsiveness and accuracy in tracking.
  • Refactor

    • Improved error handling and parameter generation for the update process, ensuring a valid path is provided before execution.

SaschaCowley and others added 7 commits July 31, 2024 13:51
… than strings directly, so we can set flags or options multiple times without worrying about duplicates
- Refactored the command line argument generation into a helper function.
- Fixed a typo where command line options were included twice and flags weren't included.
- Added type hints
- Added docstrings and comments
- Renamed some variables
- Raise `valueError` if `destPath` isn't passed to `_executeUpdate`
- Linted
@SaschaCowley SaschaCowley marked this pull request as ready for review August 1, 2024 04:31
@SaschaCowley SaschaCowley requested a review from a team as a code owner August 1, 2024 04:31
Copy link
Contributor

coderabbitai bot commented Aug 1, 2024

Walkthrough

The recent updates enhance the functionality and maintainability of the NVDA application. Key improvements include refined error handling in the update process, ensuring valid paths are provided, and introducing a new function for generating update parameters. Additionally, command line options now fully respect user configurations during updates, while a bug fix improves caret movement tracking, aligning it with user expectations and improving overall responsiveness.

Changes

File Change Summary
source/speech/commands.py Minor formatting change in the __repr__ method of CancellableSpeech, improving string interpolation without altering functionality.
source/updateCheck.py Enhanced _executeUpdate with better error handling, introduced _generate_updateParameters for clarity, and restructured parameter construction for flexibility.
user_docs/en/changes.md Updated command line options for NVDA to respect -c/--config-path and --disable-addons, along with a bug fix restoring event-based caret movement.
source/gui/installerGui.py Added _generate_executionParameters method to construct command-line parameters for NVDA, improving code clarity and maintainability.

Recent review details

Configuration used: .coderabbit.yml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between ab16271 and 03be8a3.

Files selected for processing (2)
  • source/gui/installerGui.py (3 hunks)
  • source/updateCheck.py (2 hunks)
Additional context used
Path-based instructions (2)
source/gui/installerGui.py (2)

Pattern **/*: Focus on code smells, logic errors, edge cases, missing test cases, security flaws and serious issues. Avoid commenting on minor issues such as linting, formatting and style issues. This project uses tabs instead of spaces, do not suggest usage of spaces over tabs. Are there any 'red flags' in this code that might warrant closer investigation from a security standpoint? Explain what makes them suspicious. When providing code suggestions, particularly when requested, ensure GitHub's suggestion format is used, i.e.: suggestion <code changes>


Pattern **/*.py: _, pgettext, ngettext, and ngettext are defined globally, errors for this being undefined can be ignored.

source/updateCheck.py (2)

Pattern **/*: Focus on code smells, logic errors, edge cases, missing test cases, security flaws and serious issues. Avoid commenting on minor issues such as linting, formatting and style issues. This project uses tabs instead of spaces, do not suggest usage of spaces over tabs. Are there any 'red flags' in this code that might warrant closer investigation from a security standpoint? Explain what makes them suspicious. When providing code suggestions, particularly when requested, ensure GitHub's suggestion format is used, i.e.: suggestion <code changes>


Pattern **/*.py: _, pgettext, ngettext, and ngettext are defined globally, errors for this being undefined can be ignored.

Additional comments not posted (5)
source/gui/installerGui.py (3)

136-138: LGTM! Verify the usage of _generate_executionParameters.

The changes improve maintainability by centralizing parameter generation.

Verification successful

LGTM! Verify the usage of _generate_executionParameters.

The changes improve maintainability by centralizing parameter generation.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of `_generate_executionParameters` in the codebase.

# Test: Search for the function usage. Expect: Only occurrences of the new function.
rg --type python -A 5 $'_generate_executionParameters'

Length of output: 84


Script:

#!/bin/bash
# Description: Verify the usage of `_generate_executionParameters` in the codebase.

# Test: Search for the function usage. Expect: Only occurrences of the new function.
rg --type py -A 5 '_generate_executionParameters'

Length of output: 1191


625-627: LGTM! Verify the usage of _generate_executionParameters.

The changes improve maintainability by centralizing parameter generation.

Verification successful

LGTM! The usage of _generate_executionParameters is verified and correctly implemented.

The changes improve maintainability by centralizing parameter generation.

  • _generate_executionParameters is defined and used within source/gui/installerGui.py.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of `_generate_executionParameters` in the codebase.

# Test: Search for the function usage. Expect: Only occurrences of the new function.
rg --type python -A 5 $'_generate_executionParameters'

Length of output: 84


Script:

#!/bin/bash
# Description: Verify the usage of `_generate_executionParameters` in the codebase.

# Test: Search for the function usage. Expect: Only occurrences of the new function.
rg --type py -A 5 '_generate_executionParameters'

Length of output: 1191


142-158: LGTM! Verify the correctness of the logic.

The function correctly generates command-line parameters based on specific conditions.

Verification successful

Verified: The function _generate_executionParameters correctly generates command-line parameters based on specific conditions.

  • The logic for checking disableAddons and retrieving the configuration path from sys.argv is correctly implemented.
  • The function ensures that parameters are formatted appropriately for execution.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the correctness of the logic in `_generate_executionParameters`.

# Test: Ensure the function generates correct parameters based on specific conditions.
ast-grep --lang python --pattern $'def _generate_executionParameters() -> str {
  executeParams: list[str] = []
  if globalVars.appArgs.disableAddons {
    executeParams.append("--disable-addons")
  }
  for i in range(len(sys.argv) - 2, 0, -1) {
    if sys.argv[i] in ("-c", "--config-path") {
      executeParams.extend(("--config-path", sys.argv[i + 1]))
      break
    }
  }
  return subprocess.list2cmdline(executeParams)
}'

Length of output: 775


Script:

#!/bin/bash
# Locate the function _generate_executionParameters in the file source/gui/installerGui.py and verify its correctness.
rg '_generate_executionParameters' -A 20 source/gui/installerGui.py

Length of output: 1586

source/updateCheck.py (2)

241-254: LGTM! Verify the usage of _generate_updateParameters.

The changes improve robustness and maintainability by including error handling and centralizing parameter generation.

Verification successful

Verified the usage of _generate_updateParameters.

The function _generate_updateParameters is defined and used within source/updateCheck.py, confirming that the changes are correctly implemented.

  • source/updateCheck.py: Definition and usage of _generate_updateParameters.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of `_generate_updateParameters` in the codebase.

# Test: Search for the function usage. Expect: Only occurrences of the new function.
rg --type python -A 5 $'_generate_updateParameters'

Length of output: 81


Script:

#!/bin/bash
# Description: Verify the usage of `_generate_updateParameters` in the codebase.

# Search for the function definition of `_generate_updateParameters`.
ast-grep --lang python --pattern 'def _generate_updateParameters($_): $$$'

# Search for calls to `_generate_updateParameters` in the codebase.
ast-grep --lang python --pattern '_generate_updateParameters($_)'

Length of output: 144


Script:

#!/bin/bash
# Description: Verify the usage of `_generate_updateParameters` in the codebase.

# Search for `_generate_updateParameters` in the codebase without specifying the file type.
rg '_generate_updateParameters'

Length of output: 208


256-281: LGTM! Verify the correctness of the logic.

The function correctly generates parameters based on specific conditions.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

user_docs/en/changes.md Show resolved Hide resolved
source/updateCheck.py Outdated Show resolved Hide resolved
Copy link
Member

@seanbudd seanbudd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approach generally looks good to me, nice work on this

source/updateCheck.py Outdated Show resolved Hide resolved
source/updateCheck.py Outdated Show resolved Hide resolved
source/updateCheck.py Outdated Show resolved Hide resolved
source/updateCheck.py Outdated Show resolved Hide resolved
@seanbudd seanbudd added conceptApproved Similar 'triaged' for issues, PR accepted in theory, implementation needs review. merge-early Merge Early in a developer cycle labels Aug 1, 2024
@michaelDCurran
Copy link
Member

When the update is complete and the newly installed NVDA starts, should it also receive the same commandline parameters?
This would need to be handled in source/gui/installerGui.py, line 132 I think.

@SaschaCowley
Copy link
Member Author

@michaelDCurran

When the update is complete and the newly installed NVDA starts, should it also receive the same commandline parameters?

There isn't the same risk here, as the new copy will not be running as administrator. However, if you still think the arguments should be propagated, I'm happy to do so.

@seanbudd
Copy link
Member

seanbudd commented Aug 1, 2024

pre-commit.ci run

@michaelDCurran
Copy link
Member

@michaelDCurran

When the update is complete and the newly installed NVDA starts, should it also receive the same commandline parameters?

There isn't the same risk here, as the new copy will not be running as administrator. However, if you still think the arguments should be propagated, I'm happy to do so.
What are your thoughts on this @CyrilleB79?

@LeonarddeR
Copy link
Collaborator

There isn't the same risk here, as the new copy will not be running as administrator.

I'm puzzled. Even when updating, NVDA itself doesn't run as admin, only nvda_slave will be running elevated.

I would personally also force the command line parameters on the copy after update, that is, as long as this is also done on a normal restart using the restart dialog.

@SaschaCowley
Copy link
Member Author

SaschaCowley commented Aug 4, 2024

I'm puzzled. Even when updating, NVDA itself doesn't run as admin, only nvda_slave will be running elevated.

Apologies, this comment was based on a misunderstanding of mine.

I would personally also force the command line parameters on the copy after update, that is, as long as this is also done on a normal restart using the restart dialog.

We currently propagate most arguments when restarting, with the notable exception of --disable-addons. I agree that, with this in mind, we should definitely propagate -c. The --disable-addons case is a pickle, however: the assumption at the moment seems to be that it is only ever wanted as a temporary state that should not be persisted. Whether or not this should be the case is out of scope for this issue, but I am slightly worried that propagating it throughout the update process may be confusing since users may expect that after NVDA restarts (which it audibly does when updating) that their add-ons will be back online. I'd appreciate your feedback on this before proceeding, @LeonarddeR , @michaelDCurran, @CyrilleB79

@SaschaCowley
Copy link
Member Author

I have now updated the installer to propagate the --disable-addons flag and the -c/--config-path option. This turned out to be more difficult than anticipated, since the config path in use when running from the launcher may be a temporary directory. As such, I have used the value from sys.argv directly in this case. To test that this works as expected, I followed the build and install steps above. When checking for updates, I allowed NVDA to download the new version, then, before allowing the update to proceed, replaced the new version's launcher with the custom launcher I created (IE copy nvda_snapshot_2024.1.exe to %temp, delete %temp%\nvda_update_XXXXXXXX.exe and rename %temp%\nvda_snapshot_2024.1.exe to %temp%\nvda_update_XXXXXXXX.exe).

@SaschaCowley
Copy link
Member Author

@coderabbitai review

Copy link
Member

@seanbudd seanbudd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice approach for _generate_executionParameters!

@seanbudd seanbudd merged commit b4c8693 into master Aug 7, 2024
4 checks passed
@seanbudd seanbudd deleted the propagateCliArgs branch August 7, 2024 06:10
@github-actions github-actions bot added this to the 2024.4 milestone Aug 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
conceptApproved Similar 'triaged' for issues, PR accepted in theory, implementation needs review. merge-early Merge Early in a developer cycle
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants