Skip to content

fix(pfsense): resolve interfaces and DHCP scopes always reporting as disabled (#461) - #473

Merged
unclesp1d3r merged 21 commits into
mainfrom
461-fixpfsenseschema-pfsense-interfaces-and-dhcp-scopes-always-report-as-disabled-fork-interfacedhcpdinterface-to-use-boolflag-for-presence-based-enable
Mar 23, 2026
Merged

fix(pfsense): resolve interfaces and DHCP scopes always reporting as disabled (#461)#473
unclesp1d3r merged 21 commits into
mainfrom
461-fixpfsenseschema-pfsense-interfaces-and-dhcp-scopes-always-report-as-disabled-fork-interfacedhcpdinterface-to-use-boolflag-for-presence-based-enable

Conversation

@unclesp1d3r

@unclesp1d3r unclesp1d3r commented Mar 23, 2026

Copy link
Copy Markdown
Member

Summary

  • Fork pfsense.Interface and pfsense.DhcpdInterface with Enable opnsense.BoolFlag to correctly decode pfSense presence-based <enable/> elements (self-closing = enabled, absent = disabled)
  • Document.Interfaces and Document.Dhcpd now use the forked pfsense types directly — no intermediate decode layer
  • Converters call iface.Enable.Bool() / d.Enable.Bool() directly instead of isPfSenseValueTrue
  • Validators use pfSense-specific wrappers (validatePfSenseInterfaces, validatePfSenseDhcpd) that adapt to shared field-level validators
  • Deleted decode_types.go — 178 lines of field-by-field copy code eliminated
  • Updated documentation (mkdocs, llms.txt, about page) to reflect pfSense support and correct site URL

Architecture

Document uses pfsense.Interfaces and pfsense.Dhcpd with BoolFlag fields. XML decodes directly into Document. No intermediate representation.

XML → pfsense.Document (BoolFlag Enable) → converter (.Bool()) → CommonDevice

Test Plan

  • just ci-check passes (0 lint issues, all 35 packages green)
  • XML round-trip tests for pfsense.Interface<enable/>true, absent → false
  • XML round-trip tests for pfsense.DhcpdInterface — same cases
  • Marshal tests verify presence-based <enable> elements (not <enable>true</enable>)
  • Container-level marshal tests through Interfaces/Dhcpd maps
  • Document-level round-trip tests for both interface and DHCP enable states
  • End-to-end parser test with inline XML containing <enable/> on WAN + DHCP, absent on LAN
  • Existing 2.6.x fixture test extended to verify Enabled: true on interfaces and DHCP scopes
  • Validator tests updated for pfSense-specific types

Closes #461

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…r rule engine behavior

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…g for presence-based enablement

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…forks in pfSense

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…shaling for presence-based enablement

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…d types for improved handling

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…lag for presence-based enablement

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…se-specific types for interfaces and DHCP

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…enhance clarity on supported configurations

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…configurations

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…lFlag for presence-based enablement

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…d comprehensive XML marshaling/unmarshaling tests

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…r Interfaces and Dhcpd, and enhance XML unmarshaling for Interface Enable

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…aceLAN in EnablePresenceXML tests

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…nterfaces and Dhcpd with BoolFlag support

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
… isPfSenseValueTrue for accurate boolean evaluation

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
… Interfaces and Dhcpd in pfSense document validation

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…d pfSense configurations

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
@dosubot dosubot Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Mar 23, 2026
@coderabbitai

coderabbitai Bot commented Mar 23, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ed363956-a917-4f35-adf2-0294f37c8a0d

📥 Commits

Reviewing files that changed from the base of the PR and between f1d0e14 and a99f53c.

📒 Files selected for processing (1)
  • pkg/parser/pfsense/parser_test.go

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.


📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added full pfSense configuration support alongside OPNsense, including correct handling of interface/DHCP "enable" presence semantics and deterministic marshaling.
  • Documentation

    • Rebranded to "opnDossier" and updated docs/site copy to describe multi-platform (OPNsense + pfSense) processing and security analysis.
    • Added developer guidance on validator/adaptor patterns and CI/markdown tooling usage.
  • Tests

    • Extensive new tests covering pfSense schema, marshaling/unmarshaling, and parser behavior.

Walkthrough

Forked pfSense schema types for Interfaces and DHCP to use opnsense.BoolFlag for presence-based <enable/> semantics; updated Document, parser converters, and validators to use/adapt the new pfsense types; added schema/container marshal/unmarshal implementations and tests; documentation and developer guidance updated for type-forking and BoolFlag marshaling.

Changes

Cohort / File(s) Summary
Branding & docs
docs/about.md, docs/index.md, llms.txt, mkdocs.yml
Renamed/project branding to opnDossier and broadened scope to include pfSense; updated site metadata and descriptive text.
Development guidance
AGENTS.md, GOTCHAS.md
Added copy-on-write/type-forking guidance, BoolFlag marshal pattern (alias + pointer-delegate), validator-adapter cascade rules, and CI/markdown tooling instructions.
pfSense schema — Interfaces
pkg/schema/pfsense/interfaces.go, pkg/schema/pfsense/interfaces_test.go
New pfsense.Interface (Enable opnsense.BoolFlag) and pfsense.Interfaces container with custom XML marshal/unmarshal, deterministic ordering, accessors, and round-trip tests.
pfSense schema — DHCP
pkg/schema/pfsense/dhcp.go, pkg/schema/pfsense/dhcp_test.go
New pfsense.DhcpdInterface and pfsense.Dhcpd container using BoolFlag for Enable, with custom marshal/unmarshal, helpers, and comprehensive tests (presence/value/absent cases).
pfSense Document
pkg/schema/pfsense/document.go
Document now uses local pfsense.Interfaces and pfsense.Dhcpd; InterfaceByName returns pfsense.Interface.
Parser / converters / tests
pkg/parser/pfsense/converter_network.go, pkg/parser/pfsense/converter_services.go, pkg/parser/pfsense/parser.go, pkg/parser/pfsense/parser_test.go
Converters switch to iface.Enable.Bool() / d.Enable.Bool() (removed fallback); parser comment updated; tests changed to construct/assert with pfsense.* types and presence-based <enable/> fixtures.
Validators / tests
internal/validator/pfsense.go, internal/validator/pfsense_test.go
Introduced pfSense-specific validator helpers that build temporary opnsense.* shapes from pfsense.* fields to reuse shared field-level validators; tests updated to use pfsense types.
Small edits & formatting
AGENTS.md (CI line), minor comment updates across files
Workflow wording and markdown tooling constraint added; minor comment removals/formatting tweaks.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • PR #459: Directly touches the same pfSense schema, parser, and validator code paths—likely overlapping changes to pfsense types and BoolFlag handling.
  • PR #186: Introduced/shared BoolFlag XML behavior and map-backed schema patterns that this PR extends/applies for pfSense.
  • PR #417: Refactored validators and helpers (validateInterface/validateDhcpd/collectInterfaceNames) which this change wraps/adapts for pfSense.

Suggested labels

type:bug, go, testing, documentation

Poem

Where empty tags once hid the truth,
a BoolFlag wakes to show its worth.
pfSense and OPNsense now agree—
presence is presence, enabled we'll be. 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ❓ Inconclusive Documentation updates (mkdocs.yml, llms.txt, docs/about.md, docs/index.md, AGENTS.md, GOTCHAS.md) expand project scope description from OPNsense-only to OPNsense+pfSense, aligning with the PR's technical changes but extending beyond the core bug fix scope. Clarify whether documentation rebranding (site URL, project description) is within scope of this bug fix or should be addressed separately in a documentation-focused PR.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows conventional commit format with 'fix' prefix, scope 'pfsense', and a clear description of the bug being resolved with issue reference #461.
Description check ✅ Passed The description is comprehensive and well-structured, covering summary, architecture, test plan with checkboxes, and clear objectives. However, some template sections (e.g., test commands, detailed test results, breaking changes) are not fully completed.
Linked Issues check ✅ Passed The PR successfully addresses all primary coding objectives from issue #461: forked pfsense.Interface and pfsense.DhcpdInterface with BoolFlag, updated Document to use forked types, converters now use .Bool() instead of isPfSenseValueTrue, validators adapted to pfSense types, and comprehensive XML round-trip tests added.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 461-fixpfsenseschema-pfsense-interfaces-and-dhcp-scopes-always-report-as-disabled-fork-interfacedhcpdinterface-to-use-boolflag-for-presence-based-enable

Comment @coderabbitai help to get the list of available commands and usage tips.

@unclesp1d3r unclesp1d3r self-assigned this Mar 23, 2026
…dhcp-scopes-always-report-as-disabled-fork-interfacedhcpdinterface-to-use-boolflag-for-presence-based-enable
@mergify

mergify Bot commented Mar 23, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

Your pull request matches the following merge protections and will not be merged until they are valid.

🟠 Full CI must pass

Waiting checks: Integration Tests.

All CI checks must pass. Activates for non-bot authors, or dependabot when files exist outside .github/workflows/.

  • check-success = Integration Tests
  • check-success = Build
  • check-success = Coverage
  • check-success = Lint
  • check-success = Test (macos-latest)
  • check-success = Test (ubuntu-latest)
  • check-success = Test (windows-latest)

🟢 Enforce conventional commit

Wonderful, this rule succeeded.

Require conventional commit format per https://www.conventionalcommits.org/en/v1.0.0/. Skipped for dependabot and dosubot.

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert)(?:\(.+\))?!?:

🟢 Do not merge outdated PRs

Wonderful, this rule succeeded.

Make sure PRs are within 10 commits of the base branch before merging

  • #commits-behind <= 10

@dosubot dosubot Bot added the architecture Architectural changes and design decisions label Mar 23, 2026
@codecov

codecov Bot commented Mar 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.92913% with 42 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pkg/schema/pfsense/dhcp.go 53.84% 13 Missing and 5 partials ⚠️
pkg/schema/pfsense/interfaces.go 53.84% 13 Missing and 5 partials ⚠️
internal/validator/pfsense.go 89.18% 2 Missing and 2 partials ⚠️
pkg/schema/pfsense/document.go 66.66% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@dosubot

dosubot Bot commented Mar 23, 2026

Copy link
Copy Markdown
Contributor

Related Documentation

2 document(s) may need updating based on files changed in this PR:

opnDossier

Technical Deep-Dive: Architecture, Internals & Roadmap
View Suggested Changes
@@ -120,7 +120,13 @@
 
 **OPNsense** (via `internal/cfgparser/`): Streaming XML parser reads `config.xml` into `schema.OpnSenseDocument` DTOs with switch-case routing for top-level elements.
 
-**pfSense** (via `pkg/parser/pfsense/`): Self-contained XML decoding using `parser.NewSecureXMLDecoder()` directly, reads into `pfsense.Document` without cfgparser dependency.
+**pfSense** (via `pkg/parser/pfsense/`): Three-layer XML parsing approach for presence-based boolean handling:
+
+- <!-- §nt:aa111111-2222-3333-4444-555555555555 --> **Layer 1: XML decode** → `decodeDocument` (intermediate type with `pfsense.Interface` and `pfsense.DhcpdInterface` using `opnsense.BoolFlag` for `Enable` fields)
+- <!-- §nt:bb222222-3333-4444-5555-666666666666 --> **Layer 2: Conversion** → `toDocument()` converts `BoolFlag` to backward-compatible `opnsense.Interfaces`/`opnsense.Dhcpd` with `Enable = "1"` (enabled) or `""` (disabled)
+- <!-- §nt:cc333333-4444-5555-6666-777777777777 --> **Layer 3: Standard flow** → Parser converts to `CommonDevice` as before
+
+This decode-layer approach correctly distinguishes `<enable/>` (present = enabled) from absent (disabled) while keeping `pfsense.Document`'s exported API backward-compatible. See GOTCHAS.md §15 for BoolFlag marshaling requirements.
 
 **Shared Security Infrastructure** (via `pkg/parser/xmlutil.go`):
 - <!-- §nt:1b4309a8-87d3-4a16-9d12-9de23072e2d7 --> **Security protections**: XXE prevention, XML bomb protection
@@ -237,11 +243,15 @@
 | Domain Model | `pkg/model/` | Platform-agnostic `CommonDevice` with JSON/YAML tags. ~87 types. No XML tags. |
 | Parser | `pkg/parser/opnsense/`, `pkg/parser/pfsense/` | Converts device-specific XML DTOs to `CommonDevice`. Returns conversion warnings. |
 
-**pfSense Schema Reuse Pattern** (copy-on-write): The `pkg/schema/pfsense/` package imports and reuses `pkg/schema/opnsense/` types for structurally identical XML sections (interfaces, DHCP, OpenVPN, certificates, VLANs, etc.) and only defines pfSense-specific types at divergence points:
-- NAT inbound rules: pfSense uses `<target>` field, OPNsense uses `<internalip>`
-- User authentication: pfSense stores bcrypt hashes in `<bcrypt-hash>`, OPNsense uses SHA-based `<password>`
-- Filter rules: pfSense adds fields not present in OPNsense (`id`, `tag`, `tagged`, `os`, `associated-rule-id`)
-- DHCPv6: pfSense includes `RAMode` and `RAPriority` configuration
+**pfSense Schema Reuse Pattern** (copy-on-write): The `pkg/schema/pfsense/` package imports and reuses `pkg/schema/opnsense/` types for structurally identical XML sections (OpenVPN, certificates, VLANs, static routes, etc.) and only defines pfSense-specific types at divergence points:
+
+- <!-- §nt:aa888888-9999-aaaa-bbbb-cccccccccccc --> **Interfaces and DHCP scopes**: pfSense uses presence-based `<enable/>` elements; forked `pfsense.Interface` and `pfsense.DhcpdInterface` with `Enable opnsense.BoolFlag` (see `pkg/schema/pfsense/interfaces.go`, `pkg/schema/pfsense/dhcp.go`, and `pkg/parser/pfsense/decode_types.go` for BoolFlag→string conversion)
+- <!-- §nt:bb999999-aaaa-bbbb-cccc-dddddddddddd --> **NAT inbound rules**: pfSense uses `<target>` field, OPNsense uses `<internalip>`
+- <!-- §nt:cc000000-bbbb-cccc-dddd-eeeeeeeeeeee --> **User authentication**: pfSense stores bcrypt hashes in `<bcrypt-hash>`, OPNsense uses SHA-based `<password>`
+- <!-- §nt:dd111111-cccc-dddd-eeee-ffffffffffff --> **Filter rules**: pfSense adds fields not present in OPNsense (`id`, `tag`, `tagged`, `os`, `associated-rule-id`)
+- <!-- §nt:ee222222-dddd-eeee-ffff-000000000000 --> **DHCPv6**: pfSense includes `RAMode` and `RAPriority` configuration
+
+**Validator cascade on type forks** (GOTCHAS.md §9.2): When a `Document` field type changes from `opnsense.*` to `pfsense.*`, the validator function must adapt each item back to the opnsense type before calling shared validators.
 <!-- §nt:022ad0b9-47a4-4bbd-829d-c4112e80c8e8 -->
 ## CommonDevice Structure
 
@@ -305,6 +315,8 @@
 | Value-based boolean (`== "1"` in PHP) | `string` | `<enable>1</enable>`, `<blockpriv>1</blockpriv>` |
 | Presence with value access | `*string` | `<any/>` in Source/Destination |
 | Container + children | `[]ChildType` in container struct | `VLANs` container with `[]VLAN` slice |
+
+**pfSense BoolFlag Marshaling Pattern** (GOTCHAS.md §15): When forking an opnsense struct to use `BoolFlag` fields, add a private type alias and a pointer-receiver `MarshalXML` method that delegates via `e.EncodeElement((*alias)(&value), start)` to ensure `(*BoolFlag).MarshalXML` is invoked for proper `<enable/>` element serialization. See `pkg/schema/pfsense/interfaces.go` (`interfaceAlias`) and `pkg/schema/pfsense/dhcp.go` (`dhcpdInterfaceAlias`) for implementation examples.
 <!-- §nt:2f7ccda1-2240-485f-a691-7544c7c99048 -->
 
 ---

✅ Accepted

xml-structure-research /opnDossier/blob/main/docs/development/xml-structure-research.md
View Suggested Changes
@@ -48,9 +48,13 @@
 | `<interfacenot/>`           | `<rule>` (filter)           | `!empty($rule['interfacenot'])`                         |
 | `<nottagged/>`              | `<rule>` (filter)           | Match packets NOT tagged                                |
 | `<trigger_initial_wizard/>` | `<opnsense>` (root)         | First-boot wizard trigger                               |
+| `<enable/>`                 | `<interfaces><wan>`         | Interface enabled (pfSense uses BoolFlag)               |
+| `<enable/>`                 | `<dhcpd><lan>`              | DHCP scope enabled (pfSense uses BoolFlag)              |
 
 **pfSense Bug #6893 note:** Prior to pfSense 2.3.3, some code produced `<tag/>` while other code produced `<tag></tag>`. Both forms are valid XML and our `*string` / `BoolFlag` types handle both correctly via Go's `encoding/xml`.
 
+**pfSense presence-based enable note:** pfSense correctly parses `Interface` and `DhcpdInterface` `<enable/>` elements as presence-based using BoolFlag types. The public API converts to string `"1"` for backward compatibility.
+
 ### 1b. Value-Based Booleans
 
 Element contains `1`, `yes`, or a specific value. Absent or empty = false.
@@ -59,10 +63,11 @@
 
 **Go type:** `string` with value check, or potentially a custom type
 
-| Element                  | Parent                   | Values | Notes                    |
-| ------------------------ | ------------------------ | ------ | ------------------------ |
-| `<enable>`               | `<interfaces><wan>`      | `1`    | Interface enable/disable |
-| `<blockpriv>`            | `<interfaces><wan>`      | `1`    | Block private networks   |
+| Element                  | Parent                   | Values | Notes                                                                                            |
+| ------------------------ | ------------------------ | ------ | ------------------------------------------------------------------------------------------------ |
+| `<enable>`               | `<interfaces><wan>`      | `1`    | pfSense: presence-based (see §1a). OPNsense: value-based. pfSense parser uses BoolFlag fork     |
+| `<enable>`               | `<dhcpd><lan>`           | `1`    | pfSense: presence-based (see §1a). OPNsense: value-based. pfSense parser uses BoolFlag fork     |
+| `<blockpriv>`            | `<interfaces><wan>`      | `1`    | Block private networks                                                                           |
 | `<blockbogons>`          | `<interfaces><wan>`      | `1`    | Block bogon networks     |
 | `<dnsallowoverride>`     | `<system>`               | `1`    | Allow DNS override       |
 | `<ipv6allow>`            | `<system>`               | `1`    | IPv6 enabled             |
@@ -314,11 +319,16 @@
 | Netflow.Capture        | EgressOnly          | `string` | MVC field, value-based |
 | Netflow.Collect        | Enable              | `string` | MVC field, value-based |
 
-### 5d. DHCP (dhcp.go) — value-based, kept as string
-
-| Struct         | Field  | Type     | Rationale                                     |
-| -------------- | ------ | -------- | --------------------------------------------- |
-| DhcpdInterface | Enable | `string` | Value-based (`<enable>1</enable>`), heavy use |
+### 5d. Interfaces and DHCP (interfaces.go, dhcp.go) — platform-specific
+
+pfSense and OPNsense use different boolean semantics for interface and DHCP scope enable flags:
+
+| Struct           | Field  | pfSense Type      | OPNsense Type | Rationale                                                                                                                                                                                                                              |
+| ---------------- | ------ | ----------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Interface        | Enable | `opnsense.BoolFlag` | `string`      | pfSense: presence-based `<enable/>` / absent. OPNsense: value-based `<enable>1</enable>`. pfSense parser uses platform-specific type fork (`pkg/schema/pfsense/interfaces.go`) with BoolFlag, converts to `"1"` for API compatibility |
+| DhcpdInterface   | Enable | `opnsense.BoolFlag` | `string`      | pfSense: presence-based `<enable/>` / absent. OPNsense: value-based `<enable>1</enable>`. pfSense parser uses platform-specific type fork (`pkg/schema/pfsense/dhcp.go`) with BoolFlag, converts to `"1"` for API compatibility       |
+
+**Implementation:** The pfSense parser uses an intermediate `decodeDocument` type (`pkg/parser/pfsense/decode_types.go`) that decodes XML with BoolFlag-aware pfsense.Interface and pfsense.DhcpdInterface types, then converts to backward-compatible opnsense.Interfaces/opnsense.Dhcpd with string Enable fields set to `"1"` (enabled) or `""` (disabled).
 
 **Note on value-based fields:** These use OPNsense MVC pattern `<field>1</field>` / `<field>0</field>`. Converting to `BoolFlag` would break semantics because `BoolFlag.UnmarshalXML` treats any present element as true, regardless of content — so `<enabled>0</enabled>` would incorrectly become `true`.
 
@@ -413,9 +423,19 @@
 
 Correctly handle dynamic interface element names via custom `UnmarshalXML`/`MarshalXML`.
 
-### 8e. `RuleLocation` Struct
-
-Already has all needed fields for complete source/destination modeling. Just needs to be connected to the actual `Source`/`Destination` types.
+### 8e. decodeDocument Intermediate Layer (pfSense parser)
+
+The pfSense parser uses a two-stage architecture for correct presence-based boolean handling:
+
+1. **Decode stage:** XML is decoded into an intermediate `decodeDocument` type (defined in `pkg/parser/pfsense/decode_types.go`) that uses platform-specific types with BoolFlag-aware Enable fields:
+   - `pfsense.Interface` with `Enable opnsense.BoolFlag` (from `pkg/schema/pfsense/interfaces.go`)
+   - `pfsense.DhcpdInterface` with `Enable opnsense.BoolFlag` (from `pkg/schema/pfsense/dhcp.go`)
+
+2. **Conversion stage:** The intermediate document is converted to a `pfsense.Document` with backward-compatible opnsense types via `toDocument()`:
+   - BoolFlag Enable fields are transformed to string: `true` → `"1"`, `false` → `""`
+   - This preserves API compatibility with existing consumers expecting string Enable fields
+
+This architecture resolves the type mismatch issue described in Section 5 by using platform-specific type forks at the decode layer while maintaining a unified public API. It correctly distinguishes pfSense's presence-based `<enable/>` (element present = enabled) from absent elements (disabled), which was previously mishandled when using string types that cannot distinguish `<enable/>` from `<enable></enable>` from absent elements.
 
 ---
 

✅ Accepted

Note: You must be authenticated to accept/decline updates.

How did I do? Any feedback?

@coderabbitai coderabbitai Bot added documentation Improvements or additions to documentation go Pull requests that update go code type:bug Bug or defect that needs fixing labels Mar 23, 2026
@coderabbitai coderabbitai Bot added priority:normal Normal priority issue testing Test infrastructure and test-related issues labels Mar 23, 2026
…olFlag usage

Replace the intermediate decodeDocument type with direct use of
pfsense.Interfaces and pfsense.Dhcpd in Document. Converters now call
iface.Enable.Bool() directly instead of isPfSenseValueTrue on
pre-converted string values.

Validators use pfSense-specific wrappers (validatePfSenseInterfaces,
validatePfSenseDhcpd) that adapt to shared field-level validators.

Deletes 178 lines of field-by-field copy code in decode_types.go.

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@AGENTS.md`:
- Around line 438-440: The docs currently mix two forms for reading BoolFlag
(e.g., "iface.Enable.Bool()" vs "bool(iface.Enable)"); update the AGENTS.md
wording to use the canonical form used in code—use bool(iface.Enable) and
bool(d.Enable) everywhere; also confirm the sentence about pfsense.Interface
having Enable of type opnsense.BoolFlag matches the implemented API and remove
references to isPfSenseValueTrue() so consumers see only the canonical bool(...)
usage (refer to symbols pfsense.Interface, iface.Enable, d.Enable,
opnsense.BoolFlag, and the validator adapters validatePfSenseInterfaces /
validatePfSenseDhcpd as context).

In `@pkg/schema/pfsense/dhcp.go`:
- Around line 99-123: The UnmarshalXML method for Dhcpd currently wraps any
decoder.Token() error (including io.EOF) as "failed to read Dhcpd token"; update
Dhcpd.UnmarshalXML to check for io.EOF after calling decoder.Token() and return
a clearer error (e.g., "unexpected end of XML while unmarshalling Dhcpd")
instead of the generic wrap, while preserving the existing fmt.Errorf wrapping
for other errors; look for the function Dhcpd.UnmarshalXML, the decoder.Token()
call, and the start xml.StartElement/end element handling to implement this
distinction.

In `@pkg/schema/pfsense/interfaces_test.go`:
- Around line 66-105: Add a brief inline guard comment to
TestInterfacesMarshalXML_EnableProducesPresenceElement explaining that the
test's substring extraction relies on the alphabetical ordering guaranteed by
Interfaces.MarshalXML (which sorts map keys when marshaling the Items map), e.g.
noting that "lan" will appear before "wan" because MarshalXML sorts keys; keep
the existing require.Greater checks but document the ordering guarantee so
future maintainers understand why lanIdx < wanIdx is expected.

In `@pkg/schema/pfsense/interfaces.go`:
- Line 45: The Range field (type opnsense.DhcpRange) currently has a JSON tag
json:"range" but YAML tag yaml:"range,omitempty"; update the struct field tag
for Range to include omitempty in the JSON tag as well (e.g.,
json:"range,omitempty") so JSON serialization matches other optional fields and
avoids emitting zero-value ranges.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 55bb608e-ae51-4fc9-905f-72367b67f19f

📥 Commits

Reviewing files that changed from the base of the PR and between 3d781b3 and 4081d6a.

📒 Files selected for processing (16)
  • AGENTS.md
  • GOTCHAS.md
  • docs/about.md
  • docs/index.md
  • internal/validator/pfsense.go
  • llms.txt
  • mkdocs.yml
  • pkg/parser/pfsense/converter_network.go
  • pkg/parser/pfsense/converter_services.go
  • pkg/parser/pfsense/decode_types.go
  • pkg/parser/pfsense/parser.go
  • pkg/parser/pfsense/parser_test.go
  • pkg/schema/pfsense/dhcp.go
  • pkg/schema/pfsense/dhcp_test.go
  • pkg/schema/pfsense/interfaces.go
  • pkg/schema/pfsense/interfaces_test.go

Comment thread AGENTS.md
Comment thread pkg/schema/pfsense/dhcp.go
Comment thread pkg/schema/pfsense/interfaces_test.go
Comment thread pkg/schema/pfsense/interfaces.go
@coderabbitai coderabbitai Bot added priority:high High priority issue and removed documentation Improvements or additions to documentation go Pull requests that update go code type:bug Bug or defect that needs fixing priority:normal Normal priority issue testing Test infrastructure and test-related issues labels Mar 23, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/parser/pfsense/parser_test.go`:
- Around line 984-1061: Extend TestParser_EnablePresenceXML to also include a
DHCP scope in the XML input that lacks the self-closing <enable/> (e.g. add a
<wan> DHCP block without <enable/>), then locate that scope after parsing
(similar to how lanDHCP is found) and add an assertion that its Enabled field is
false; update the test inside TestParser_EnablePresenceXML (use the same device,
device.DHCP iteration logic and variable naming like wanDHCP) to require.NotNil
for the new scope and assert.False(wanDHCP.Enabled).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7e37eb68-9d92-41a0-adce-a63a3f07adfe

📥 Commits

Reviewing files that changed from the base of the PR and between 4081d6a and f1d0e14.

📒 Files selected for processing (9)
  • internal/validator/pfsense.go
  • internal/validator/pfsense_test.go
  • pkg/parser/pfsense/converter_network.go
  • pkg/parser/pfsense/converter_services.go
  • pkg/parser/pfsense/parser.go
  • pkg/parser/pfsense/parser_test.go
  • pkg/schema/pfsense/dhcp_test.go
  • pkg/schema/pfsense/document.go
  • pkg/schema/pfsense/interfaces_test.go

Comment thread pkg/parser/pfsense/parser_test.go
… test

Add opt1 DHCP scope without <enable/> to verify absent element
correctly produces Enabled: false, locking both sides of the
BoolFlag contract. Addresses CodeRabbit review feedback.

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
@unclesp1d3r
unclesp1d3r merged commit 94d9c30 into main Mar 23, 2026
20 of 23 checks passed
@unclesp1d3r
unclesp1d3r deleted the 461-fixpfsenseschema-pfsense-interfaces-and-dhcp-scopes-always-report-as-disabled-fork-interfacedhcpdinterface-to-use-boolflag-for-presence-based-enable branch March 23, 2026 07:01
@coderabbitai coderabbitai Bot added documentation Improvements or additions to documentation go Pull requests that update go code type:bug Bug or defect that needs fixing testing Test infrastructure and test-related issues and removed priority:high High priority issue labels Mar 23, 2026
mergify Bot pushed a commit that referenced this pull request Apr 11, 2026
Update documentation for
#473

This document provides comprehensive research on OPNsense and pfSense
config.xml structure, including boolean patterns, source/destination
complexity, and firewall rule fields. It documents schema gaps that have
been resolved across five implementation phases and establishes the
rationale for type decisions (BoolFlag vs string) across the parser,
enabling more accurate config parsing and identifying remaining
low-priority fields for future work.

_Generated by [Dosu](https://dosu.dev)_

Co-authored-by: dosubot[bot] <131922026+dosubot[bot]@users.noreply.github.com>
@dosubot dosubot Bot mentioned this pull request Apr 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

architecture Architectural changes and design decisions documentation Improvements or additions to documentation go Pull requests that update go code size:XXL This PR changes 1000+ lines, ignoring generated files. testing Test infrastructure and test-related issues type:bug Bug or defect that needs fixing

Projects

None yet

1 participant