Skip to content

Conversation

@nathan818fr
Copy link

@nathan818fr nathan818fr commented Jul 6, 2025

Proposed change

The current firmware version check requires write+policy+reboot access.
This prevents some features from working when only read+api access are granted (e.g. #381).

This method appears to be compatible with both RouterOS 6 and 7 (according to the MikroTik documentation), but I have only tested it on RouterOS 7.

Type of change

  • Bugfix
  • New feature
  • Code quality improvements to existing code or addition of tests
  • Documentation

Checklist

  • The code change is tested and works locally.
  • The code has been formatted using Black.
  • Tests have been added to verify that the new code works.
  • Documentation added/updated if required.

Summary by Sourcery

Enable firmware version checks using only read and API access by introducing a read-only retrieval method and removing write-dependent parsing

New Features:

  • Add get_firmware_version method to fetch and parse firmware version from the read-only system resource endpoint
  • Invoke firmware version retrieval in get_firmware_update before requiring write permissions

Enhancements:

  • Remove legacy version-parsing logic that depended on write access to the fw-update response

@sourcery-ai
Copy link

sourcery-ai bot commented Jul 6, 2025

Reviewer's Guide

This PR refactors firmware version handling by introducing a dedicated, read-only method to fetch and parse the RouterOS version, ensuring version checks work without write access, and updates the firmware update workflow accordingly.

Sequence diagram for firmware version check in firmware update process

sequenceDiagram
    participant Coordinator
    participant MikroTikAPI
    Coordinator->>Coordinator: get_firmware_update()
    Coordinator->>Coordinator: get_firmware_version()
    Coordinator->>MikroTikAPI: query /system/resource
    MikroTikAPI-->>Coordinator: version string
    Coordinator->>Coordinator: Parse version, set major/minor
    Coordinator->>Coordinator: Continue firmware update logic
Loading

Class diagram for firmware version handling refactor

classDiagram
    class Coordinator {
        +get_firmware_version()
        +get_firmware_update()
        major_fw_version
        minor_fw_version
    }
    Coordinator : - get_firmware_version() is a new method
    Coordinator : - get_firmware_update() now calls get_firmware_version()
    Coordinator : - major_fw_version and minor_fw_version are set by get_firmware_version()
Loading

File-Level Changes

Change Details Files
Decouple firmware version extraction into a read-only API call and streamline update check
  • Add get_firmware_version method using parse_api and regex to retrieve major/minor version with error handling
  • Invoke get_firmware_version at the start of get_firmware_update to support read-only access
  • Remove legacy version parsing block from get_firmware_update
  • Adjust logging accordingly
custom_components/mikrotik_router/coordinator.py

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @nathan818fr - I've reviewed your changes - here's some feedback:

  • After failing to parse the version, you don't reset major_fw_version/minor_fw_version—set explicit defaults there to avoid carrying over stale values.
  • The try/except around version parsing catches all exceptions; narrow it to ValueError (or specific parsing errors) so you don’t mask unexpected failures.
  • The custom regex may not cover all RouterOS version strings—consider using a standard version‐parsing utility or extending the pattern to handle suffixes and patch numbers.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- After failing to parse the version, you don't reset major_fw_version/minor_fw_version—set explicit defaults there to avoid carrying over stale values.
- The try/except around version parsing catches all exceptions; narrow it to ValueError (or specific parsing errors) so you don’t mask unexpected failures.
- The custom regex may not cover all RouterOS version strings—consider using a standard version‐parsing utility or extending the pattern to handle suffixes and patch numbers.

## Individual Comments

### Comment 1
<location> `custom_components/mikrotik_router/coordinator.py:1580` </location>
<code_context>
+
+        full_version = resources["version"]
+        try:
+            version_match = re.match(r"^(\d+)\.(\d+)\.(\d+)", full_version)
+            if not version_match:
+                raise ValueError("Version format is not recognized")
+            version_major = int(version_match.group(1))
+            version_minor = int(version_match.group(2))
+        except Exception as e:
+            _LOGGER.error(
</code_context>

<issue_to_address>
Regex may not match all valid version formats.

The current regex may not handle versions like '7.12beta3'. Please update it to support such cases or add explicit handling.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
        try:
            version_match = re.match(r"^(\d+)\.(\d+)\.(\d+)", full_version)
            if not version_match:
                raise ValueError("Version format is not recognized")
            version_major = int(version_match.group(1))
            version_minor = int(version_match.group(2))
        except Exception as e:
=======
        try:
            # Match versions like 7.12.1, 7.12beta3, 7.12, etc.
            version_match = re.match(r"^(\d+)\.(\d+)", full_version)
            if not version_match:
                raise ValueError("Version format is not recognized")
            version_major = int(version_match.group(1))
            version_minor = int(version_match.group(2))
        except Exception as e:
>>>>>>> REPLACE

</suggested_fix>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines 1579 to 1585
try:
version_match = re.match(r"^(\d+)\.(\d+)\.(\d+)", full_version)
if not version_match:
raise ValueError("Version format is not recognized")
version_major = int(version_match.group(1))
version_minor = int(version_match.group(2))
except Exception as e:
Copy link

Choose a reason for hiding this comment

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

suggestion: Regex may not match all valid version formats.

The current regex may not handle versions like '7.12beta3'. Please update it to support such cases or add explicit handling.

Suggested change
try:
version_match = re.match(r"^(\d+)\.(\d+)\.(\d+)", full_version)
if not version_match:
raise ValueError("Version format is not recognized")
version_major = int(version_match.group(1))
version_minor = int(version_match.group(2))
except Exception as e:
try:
# Match versions like 7.12.1, 7.12beta3, 7.12, etc.
version_match = re.match(r"^(\d+)\.(\d+)", full_version)
if not version_match:
raise ValueError("Version format is not recognized")
version_major = int(version_match.group(1))
version_minor = int(version_match.group(2))
except Exception as e:

e.g. "7.10beta1", "7.10rc1"
Repository owner deleted a comment from sourcery-ai bot Jul 6, 2025
@tomaae
Copy link
Owner

tomaae commented Jul 6, 2025

pretty sure this would just enable update entity which needs write access to function.
did you tested while update workflow this way?

@nathan818fr
Copy link
Author

nathan818fr commented Jul 7, 2025

From what I understand, major_fw_version and minor_fw_version are only used by this integration to detect which features are supported depending on the RouterOS version.
I've checked all the places where these two variables are used, and I can't see any other use for them, so nothing related to the update entity.

This commit only changes how these two variables are set, but does not affect the fw-update states used by the update entity.

For me, this change allowed some features that were not working before to function properly (specifically those that depend on a version check):

  • client traffic sensors
  • system health sensors (note: for this one, I also had to removed the access check at the beginning of get_system_health since read+api access is enough to get all health sensors in my case)

@github-actions github-actions bot added the stale label Jul 21, 2025
Repository owner deleted a comment from github-actions bot Jul 21, 2025
@tomaae tomaae added planned To be implemented in future release and removed stale labels Jul 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

planned To be implemented in future release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants