Skip to content

fix: Migrate missing fixes from dev-1.2.7#619

Merged
PeterJhongLinksys merged 2 commits intodev-2.0.0from
fix/migrate-1.2.7-missing-items
Feb 6, 2026
Merged

fix: Migrate missing fixes from dev-1.2.7#619
PeterJhongLinksys merged 2 commits intodev-2.0.0from
fix/migrate-1.2.7-missing-items

Conversation

@AustinChangLinksys
Copy link
Collaborator

@AustinChangLinksys AustinChangLinksys commented Feb 6, 2026

Summary

Migrates two missing fixes from dev-1.2.7 that were not included in the dev-2.0.0 branch:

  • NOW-713: Update OpenDNS Family Shield DNS server IPs
  • QUALITY-439: Allow /31 subnet masks for WAN Static IP settings

Changes

NOW-713: OpenDNS IP Update

  • Updated OpenDNS Family Shield IPs from 208.67.222.123/208.67.220.123 to 208.67.222.222/208.67.220.220
  • Files modified:
    • lib/page/instant_safety/services/instant_safety_service.dart
    • test/mocks/test_data/instant_safety_test_data.dart
    • test/page/instant_safety/services/instant_safety_service_test.dart

QUALITY-439: SubnetMask Validator Fix

  • Added max: 31 parameter to SubnetMaskValidator to allow /31 subnet masks for WAN Static IP
  • Files modified:
    • lib/page/advanced_settings/internet_settings/utils/internet_settings_form_validator.dart
    • lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_static_ip_view.dart

Test plan

  • flutter analyze passes with no errors
  • instant_safety_service_test.dart - 11/11 tests pass
  • Manual verification of OpenDNS safe browsing feature
  • Manual verification of WAN Static IP with /31 subnet mask

🤖 Generated with Claude Code

NOW-713: Update OpenDNS Family Shield IPs
- Changed from 208.67.222.123/208.67.220.123 to 208.67.222.222/208.67.220.220
- Updated service, test data, and test assertions

QUALITY-439: Allow /31 subnet masks for WAN Static IP
- Added max: 31 parameter to SubnetMaskValidator in:
  - internet_settings_form_validator.dart
  - pnp_static_ip_view.dart

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@qodo-code-review
Copy link

Review Summary by Qodo

Migrate missing fixes from dev-1.2.7 branch

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Migrate two critical fixes from dev-1.2.7 branch
• Update OpenDNS Family Shield DNS server IPs
• Allow /31 subnet masks for WAN Static IP configuration
• Update corresponding test data and assertions
Diagram
flowchart LR
  A["NOW-713: OpenDNS IP Update"] --> B["Update DNS Constants"]
  B --> C["instant_safety_service.dart"]
  B --> D["instant_safety_test_data.dart"]
  B --> E["instant_safety_service_test.dart"]
  F["QUALITY-439: /31 Subnet Support"] --> G["SubnetMaskValidator max: 31"]
  G --> H["internet_settings_form_validator.dart"]
  G --> I["pnp_static_ip_view.dart"]
Loading

Grey Divider

File Changes

1. lib/page/instant_safety/services/instant_safety_service.dart 🐞 Bug fix +3/-2

Update OpenDNS Family Shield DNS IPs

• Updated OpenDNS Family Shield DNS server IPs from 208.67.222.123/208.67.220.123 to
 208.67.222.222/208.67.220.220
• Added NOW-713 comment documenting the IP change

lib/page/instant_safety/services/instant_safety_service.dart


2. test/mocks/test_data/instant_safety_test_data.dart 🧪 Tests +3/-2

Sync test data with updated DNS IPs

• Updated OpenDNS test data constants to match new IPs (208.67.222.222/208.67.220.220)
• Added NOW-713 comment for consistency

test/mocks/test_data/instant_safety_test_data.dart


3. test/page/instant_safety/services/instant_safety_service_test.dart 🧪 Tests +3/-2

Update DNS IP test assertions

• Updated test assertions to expect new OpenDNS IPs (208.67.222.222/208.67.220.220)
• Added NOW-713 comment documenting the change

test/page/instant_safety/services/instant_safety_service_test.dart


View more (2)
4. lib/page/advanced_settings/internet_settings/utils/internet_settings_form_validator.dart 🐞 Bug fix +2/-1

Allow /31 subnet masks in validator

• Modified SubnetMaskValidator instantiation to allow /31 subnet masks by setting max: 31
• Added QUALITY-439 comment explaining the override of default max value

lib/page/advanced_settings/internet_settings/utils/internet_settings_form_validator.dart


5. lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_static_ip_view.dart 🐞 Bug fix +2/-1

Enable /31 subnet mask support

• Updated SubnetMaskValidator instantiation to allow /31 subnet masks by setting max: 31
• Added QUALITY-439 comment explaining the configuration change

lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_static_ip_view.dart


Grey Divider

Qodo Logo

@qodo-code-review
Copy link

qodo-code-review bot commented Feb 6, 2026

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (1) 📎 Requirement gaps (0)

Grey Divider


Action required

1. No tests for /31 masks 📘 Rule violation ⛯ Reliability
Description
• The PR changes WAN Static IP subnet mask validation to allow /31 by constructing
  SubnetMaskValidator(max: 31) in multiple places.
• There is no automated test asserting that a /31 mask (e.g., 255.255.255.254) is accepted in
  these flows, and existing tests still only cover /24 in the PNP static IP view.
• Without coverage for this boundary change, regressions may go undetected and the intended fix may
  not be reliably validated.
Code

lib/page/advanced_settings/internet_settings/utils/internet_settings_form_validator.dart[R46-48]

+    // QUALITY-439: Override default max (30) to allow /31 subnet masks for WAN Static IP
+    final subnetMaskValidator = SubnetMaskValidator(max: 31);
    if (subnetMaskValidator.validate(value)) {
Evidence
PR Compliance ID 12 requires automated test coverage for changed behavior. The PR introduces /31
support via SubnetMaskValidator(max: 31) in production code, but existing tests do not validate
/31 acceptance in the relevant UI/validation flows and NetworkUtils.isValidSubnetMask tests
still treat 255.255.255.254 as invalid under defaults without adding a complementary test for the
maxNetworkPrefixLength: 31 case.

CLAUDE.md
lib/page/advanced_settings/internet_settings/utils/internet_settings_form_validator.dart[46-48]
lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_static_ip_view.dart[37-40]
test/page/instant_setup/troubleshooter/views/isp_settings/localizations/pnp_static_ip_view_test.dart[122-175]
test/utils_test.dart[773-807]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR enables `/31` subnet masks for WAN Static IP by using `SubnetMaskValidator(max: 31)`, but there are no automated tests asserting that a `/31` mask (e.g., `255.255.255.254`) is accepted in these updated flows.

## Issue Context
Existing tests for the PNP static IP view only use `255.255.255.0` as the valid subnet mask, and current `NetworkUtils.isValidSubnetMask` tests treat `255.255.255.254` as invalid under default parameters. This leaves the new boundary behavior unverified.

## Fix Focus Areas
- lib/page/advanced_settings/internet_settings/utils/internet_settings_form_validator.dart[42-53]
- lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_static_ip_view.dart[34-40]
- test/page/instant_setup/troubleshooter/views/isp_settings/localizations/pnp_static_ip_view_test.dart[110-175]
- test/utils_test.dart[773-808]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. OpenDNS config regression 🐞 Bug ✓ Correctness
Suggestion Impact:The commit updates the spec and contract documentation/examples to use the new OpenDNS Family Shield IPs (208.67.222.222/208.67.220.220), addressing the suggestion’s docs/contract consistency concern, but it does not implement the suggested legacy-IP detection logic or tests.

code diff:

# File: specs/009-instant-safety-service/spec.md
@@ -115,7 +115,7 @@
 ## Assumptions
 
 - The existing `PreservableNotifierMixin` pattern will continue to be used for dirty state management
-- DNS server IP addresses for Fortinet (208.91.114.155) and OpenDNS (208.67.222.123, 208.67.220.123) are fixed and do not require configuration
+- DNS server IP addresses for Fortinet (208.91.114.155) and OpenDNS Family Shield (208.67.222.222, 208.67.220.220) are fixed and do not require configuration
 - The compatibility map for Fortinet support (currently empty) will remain managed within the service layer
 - The InstantSafety feature currently has no unit tests, so new tests will be created from scratch

# File: specs/009-instant-safety-service/contracts/instant_safety_service_contract.md
@@ -125,7 +125,7 @@
 1. Validates cached LAN settings exist (throws `InvalidInputError` if not)
 2. Constructs DHCP settings with appropriate DNS servers based on type:
    - `fortinet`: DNS1=208.91.114.155
-   - `openDNS`: DNS1=208.67.222.123, DNS2=208.67.220.123
+   - `openDNS`: DNS1=208.67.222.222, DNS2=208.67.220.220
    - `off`: Clear all DNS servers
 3. Calls `setLANSettings` JNAP action
 4. Allows `JNAPSideEffectError` to propagate (handled by UI layer)
@@ -191,7 +191,7 @@
 final dnsServer1 = lanSettings.dhcpSettings.dnsServer1;
 if (dnsServer1 == '208.91.114.155') {
   return InstantSafetyType.fortinet;
-} else if (dnsServer1 == '208.67.222.123') {
+} else if (dnsServer1 == '208.67.222.222') {
   return InstantSafetyType.openDNS;
 } else {
   return InstantSafetyType.off;
@@ -225,9 +225,9 @@
 // Fortinet Safe Browsing DNS
 static const _fortinetDns1 = '208.91.114.155';
 
-// OpenDNS Family Shield
-static const _openDnsDns1 = '208.67.222.123';
-static const _openDnsDns2 = '208.67.220.123';
+// OpenDNS Family Shield (NOW-713: Updated IPs)
+static const _openDnsDns1 = '208.67.222.222';
+static const _openDnsDns2 = '208.67.220.220';

</details>


<br/>

> <details open>
><summary>Description</summary>
><br/>
>
><pre>
>• InstantSafetyService determines the current provider via an exact match on <b><i>dnsServer1</i></b>; changing
>   the OpenDNS constant means routers still configured with the previously documented OpenDNS IPs will
>   now be classified as <b><i>off</i></b>.
>• This can surface as an incorrect UI state (shows “off” even though OpenDNS is configured) and can
>   lead to unintended changes when the user saves settings.
>• Repo specs/contracts still state OpenDNS uses the old IPs, so implementation and documented
>   behavior are inconsistent, increasing the chance of future regressions.
></pre>
></details>

> <details open>
><summary>Code</summary>
><br/>
>
><code>[lib/page/instant_safety/services/instant_safety_service.dart[R52-54]](https://github.com/linksys/PrivacyGUI/pull/619/files#diff-743d98767070867482452f6f491d6c9200ed2f6a2249872807bf7d8115251e3dR52-R54)</code>
>
>```diff
>+  // NOW-713: Updated OpenDNS Family Shield IPs
>+  static const _openDnsDns1 = '208.67.222.222';
>+  static const _openDnsDns2 = '208.67.220.220';
>```
></details>

> <details >
><summary>Evidence</summary>
><br/>
>
><pre>
>The service now defines OpenDNS as 208.67.222.222/208.67.220.220 and <b><i>_determineSafeBrowsingType</i></b>
>returns <b><i>openDNS</i></b> only when <b><i>dnsServer1 == _openDnsDns1</i></b>. The repo’s spec and contract explicitly
>document OpenDNS as 208.67.222.123/208.67.220.123 and show the same exact-match logic against
>208.67.222.123, so any router returning the documented legacy OpenDNS DNS1 will no longer be
>detected as <b><i>openDNS</i></b>.
></pre>
>
> <code>[lib/page/instant_safety/services/instant_safety_service.dart[50-155]](https://github.com/linksys/PrivacyGUI/blob/8fde42dadb01bf8a1401345a7faaf92bfa848eb9/lib/page/instant_safety/services/instant_safety_service.dart/#L50-L155)</code>
> <code>[specs/009-instant-safety-service/spec.md[115-120]](https://github.com/linksys/PrivacyGUI/blob/8fde42dadb01bf8a1401345a7faaf92bfa848eb9/specs/009-instant-safety-service/spec.md/#L115-L120)</code>
> <code>[specs/009-instant-safety-service/contracts/instant_safety_service_contract.md[124-199]](https://github.com/linksys/PrivacyGUI/blob/8fde42dadb01bf8a1401345a7faaf92bfa848eb9/specs/009-instant-safety-service/contracts/instant_safety_service_contract.md/#L124-L199)</code>
></details>

> <details>
><summary>Agent prompt</summary>
><br/>
>
>```
>The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
>
>### Issue description
>InstantSafetyService identifies OpenDNS by exact matching `dnsServer1` against `_openDnsDns1`. Updating `_openDnsDns1/_openDnsDns2` changes the detection key, so devices configured with the previously documented OpenDNS values will now be treated as `off`.
>
>### Issue Context
>Repo documentation/specs still describe OpenDNS as `208.67.222.123`/`208.67.220.123` and show detection logic matching against `208.67.222.123`. The implementation now uses `208.67.222.222`/`208.67.220.220`.
>
>### Fix Focus Areas
>- lib/page/instant_safety/services/instant_safety_service.dart[50-156]
>- specs/009-instant-safety-service/spec.md[115-120]
>- specs/009-instant-safety-service/contracts/instant_safety_service_contract.md[124-231]
>
>### Suggested approach
>1. Introduce legacy OpenDNS constants (or a set/list of acceptable DNS1 values).
>2. Update `_determineSafeBrowsingType` to return `openDNS` when `dnsServer1` equals either legacy or new DNS1 (optionally also validate DNS2 for additional safety).
>3. Decide the desired DNS values to *write* in `saveSettings` (new vs legacy) and update specs/contracts accordingly.
>4. Add/extend tests to ensure fetchSettings returns `InstantSafetyType.openDNS` when LAN settings contain the legacy DNS1 value.
>```
> <code>ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools</code>
></details>

<hr/>
</details>


<img src="https://www.qodo.ai/wp-content/uploads/2025/11/light-grey-line.svg" height="10%" alt="Grey Divider">
<pre>ⓘ The new review experience is currently in Beta. <a href="https://docs.qodo.ai/qodo-documentation/code-review">Learn more</a></pre>
<img src="https://www.qodo.ai/wp-content/uploads/2025/11/light-grey-line.svg" height="10%" alt="Grey Divider">


<!-- https://github.com/linksys/PrivacyGUI/commit/8fde42dadb01bf8a1401345a7faaf92bfa848eb9 -->

<a href="https://www.qodo.ai"><img src="https://www.qodo.ai/wp-content/uploads/2025/03/qodo-logo.svg" width="80" alt="Qodo Logo"></a>

Comment on lines +46 to 48
// QUALITY-439: Override default max (30) to allow /31 subnet masks for WAN Static IP
final subnetMaskValidator = SubnetMaskValidator(max: 31);
if (subnetMaskValidator.validate(value)) {

Choose a reason for hiding this comment

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

Action required

1. No tests for /31 masks 📘 Rule violation ⛯ Reliability

• The PR changes WAN Static IP subnet mask validation to allow /31 by constructing
  SubnetMaskValidator(max: 31) in multiple places.
• There is no automated test asserting that a /31 mask (e.g., 255.255.255.254) is accepted in
  these flows, and existing tests still only cover /24 in the PNP static IP view.
• Without coverage for this boundary change, regressions may go undetected and the intended fix may
  not be reliably validated.
Agent Prompt
## Issue description
The PR enables `/31` subnet masks for WAN Static IP by using `SubnetMaskValidator(max: 31)`, but there are no automated tests asserting that a `/31` mask (e.g., `255.255.255.254`) is accepted in these updated flows.

## Issue Context
Existing tests for the PNP static IP view only use `255.255.255.0` as the valid subnet mask, and current `NetworkUtils.isValidSubnetMask` tests treat `255.255.255.254` as invalid under default parameters. This leaves the new boundary behavior unverified.

## Fix Focus Areas
- lib/page/advanced_settings/internet_settings/utils/internet_settings_form_validator.dart[42-53]
- lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_static_ip_view.dart[34-40]
- test/page/instant_setup/troubleshooter/views/isp_settings/localizations/pnp_static_ip_view_test.dart[110-175]
- test/utils_test.dart[773-808]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +52 to +54
// NOW-713: Updated OpenDNS Family Shield IPs
static const _openDnsDns1 = '208.67.222.222';
static const _openDnsDns2 = '208.67.220.220';

Choose a reason for hiding this comment

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

Action required

2. Opendns config regression 🐞 Bug ✓ Correctness

• InstantSafetyService determines the current provider via an exact match on dnsServer1; changing
  the OpenDNS constant means routers still configured with the previously documented OpenDNS IPs will
  now be classified as off.
• This can surface as an incorrect UI state (shows “off” even though OpenDNS is configured) and can
  lead to unintended changes when the user saves settings.
• Repo specs/contracts still state OpenDNS uses the old IPs, so implementation and documented
  behavior are inconsistent, increasing the chance of future regressions.
Agent Prompt
### Issue description
InstantSafetyService identifies OpenDNS by exact matching `dnsServer1` against `_openDnsDns1`. Updating `_openDnsDns1/_openDnsDns2` changes the detection key, so devices configured with the previously documented OpenDNS values will now be treated as `off`.

### Issue Context
Repo documentation/specs still describe OpenDNS as `208.67.222.123`/`208.67.220.123` and show detection logic matching against `208.67.222.123`. The implementation now uses `208.67.222.222`/`208.67.220.220`.

### Fix Focus Areas
- lib/page/instant_safety/services/instant_safety_service.dart[50-156]
- specs/009-instant-safety-service/spec.md[115-120]
- specs/009-instant-safety-service/contracts/instant_safety_service_contract.md[124-231]

### Suggested approach
1. Introduce legacy OpenDNS constants (or a set/list of acceptable DNS1 values).
2. Update `_determineSafeBrowsingType` to return `openDNS` when `dnsServer1` equals either legacy or new DNS1 (optionally also validate DNS2 for additional safety).
3. Decide the desired DNS values to *write* in `saveSettings` (new vs legacy) and update specs/contracts accordingly.
4. Add/extend tests to ensure fetchSettings returns `InstantSafetyType.openDNS` when LAN settings contain the legacy DNS1 value.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

- Add /31 subnet mask tests for QUALITY-439
  - Test validates /31 mask (255.255.255.254) accepted with max: 31
  - Test validates /31 mask rejected with default max (30)

- Update spec documents with new OpenDNS IPs (NOW-713)
  - spec.md: Update assumptions section
  - contracts/instant_safety_service_contract.md: Update DNS constants and examples

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@PeterJhongLinksys PeterJhongLinksys merged commit ab6e2b1 into dev-2.0.0 Feb 6, 2026
2 checks passed
@PeterJhongLinksys PeterJhongLinksys deleted the fix/migrate-1.2.7-missing-items branch February 6, 2026 08:10
@AustinChangLinksys AustinChangLinksys linked an issue Feb 9, 2026 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[2.0.0] Merge 1.2.8 to 2.0.0

2 participants