Skip to content

v0.6.0

Choose a tag to compare

@night4me night4me released this 22 Aug 11:52
· 110 commits to main since this release

READ-capability expansion. Public contract: 84 → 95 READ tools
(0 default WRITE, unchanged). Useful READ coverage: 84/105 (80.0%) →
95/105 (90.5%) against this project's own capability-audit denominator
(unchanged — every candidate added this release was already counted in
that original 105, none legitimately expands it). 84 → 94 distinct READ
privileges; 85 → 95 write-protected combined privileges. Every new tool
was exercised against a real pfSense instance (LAB, this project's
disposable CE 2.9.0 appliance) before public registration — 10 of the
11 with an exact field-level key-set match against their typed model
(FIELD_MODEL_LIVE_VERIFIED); the remaining one (WireGuard tunnel
addresses) confirmed reachable and correctly authorized but returned an
empty list on this LAB (ENDPOINT_VERIFIED), so its field shape rests
on independent schema/security review rather than an observed
populated item. No package was installed to support this release; the
one package-conditional addition (WireGuard tunnel addresses) uses a
package already present on the LAB from prior, separately authorized
work.

Added

  • Schema field-drift regression protection (v0.6.0 Phase B, Batch A).
    scripts/lib/schema_drift.py provides a general mechanism,
    independently designed (not derived from the comparison project
    investigated in the v0.6.0 competitive audit), that asserts every
    field a pinned upstream OpenAPI schema component declares is either a
    field this project's Pydantic response model already declares, or is
    present in an explicit, reviewed intentional_exclusions allowlist
    (e.g. WireGuardPeerStatus.preshared_key, deliberately never
    modeled). This closes a real, previously-unguarded gap: a future
    pfREST release adding a field to an already-modeled response object
    would otherwise go completely unnoticed, since a Pydantic model
    silently ignores unknown upstream keys by construction.
    tests/test_schema_field_drift.py registers four already-shipped
    models (ConfigHistoryRevision, SystemTimezone,
    WireGuardTunnelStatus, WireGuardPeerStatus) against a small,
    explicitly curated fixture (tests/fixtures/pinned_response_schemas.json)
    and proves the mechanism itself fires correctly against synthetic
    ordinary-field, secret-like-field, nested-model, exclusion-allowlist,
    stale-exclusion, and schema-evolution (nullable) cases. No MCP tool,
    capability, or public contract change. Public contract remains 84
    READ / 0 default WRITE.

  • pfsense_get_diagnostics_config_history_revisions (v0.6.0 Phase B,
    Batch B).
    Lists configuration-history (backup) revisions: change
    timestamp, pfSense's own system-generated audit description, the
    pfSense version at the time, and the backup file size. Metadata only
    — the v0.6.0 Phase A qualification independently confirmed, against
    the upstream ConfigHistoryRevision.inc Model source (not just the
    OpenAPI schema), that this endpoint's response never includes the
    backup's actual configuration content, only filesystem-level metadata.
    The underlying client method, typed model, and Endpoints entry
    already existed (added 2026-08-16 for internal ADR-026 evidence
    gathering, verified=True from that session's real LAB call); this
    release adds only the public MCP tool registration. A fresh
    confirmatory LAB call was attempted this session but could not be
    completed (the read-only LAB service account's privilege scope did
    not yet include this endpoint, and granting it required admin LAB
    access not available in this session) — promotion rests on the
    pre-existing 2026-08-16 evidence, disclosed explicitly rather than
    overstated; see docs/PFSENSE_LEAST_PRIVILEGE_MATRIX.md. Public
    contract: 84 → 85 READ tools (0 default WRITE, unchanged).

  • LogSettings model + client method, implemented and offline-tested
    (v0.6.0 Phase B, Batch C — not yet registered).
    New
    src/pfsense_mcp/models/log_settings.py (34 fields, all
    boolean/string/integer, no writeOnly/secret-shaped field anywhere —
    re-verified directly against the pinned schema immediately before
    implementation, independent of the v0.6.0 Phase A finding) and
    PfSenseClient.get_status_logs_settings(). LAB verification could not
    be completed this session: the read-only LAB service account's
    privilege scope covers only already-registered tools, and granting
    api-v2-status-logs-settings-get required admin LAB access that did
    not authenticate successfully. Endpoints.STATUS_LOGS_SETTINGS remains
    verified=False; no tools/read/ file, Capability enum member, or
    registry wiring was added, matching this project's established
    WireGuard-package-blocker precedent. Public contract unchanged at 85
    READ / 0 default WRITE. Registered in the Batch A schema-drift
    registry.

  • Apply-status sweep, implemented and offline-tested (v0.6.0 Phase B,
    Batch D — not yet registered).
    Eight new models/client methods for
    firewall/virtual_ip/apply, interface/apply, routing/apply,
    services/dhcp_server/apply, services/dns_forwarder/apply,
    services/dns_resolver/apply, vpn/ipsec/apply, vpn/wireguard/apply
    — each independently re-verified against the pinned schema (all
    trivial {"applied": bool} shapes; interface/apply additionally
    has a flat pending_interfaces: list[str]; no secret material in
    any). Mirrors the already-shipped FirewallApplyStatus pattern.
    applied/pending_interfaces are modeled | None (schema-declared
    nullable: true), deliberately not assumed non-null the way the
    pre-existing FirewallApplyStatus is, since no live call has
    confirmed any of these eight endpoints' actual behavior yet. None
    registered as public tools — same LAB-access blocker as Batch C.
    Public contract unchanged at 85 READ / 0 default WRITE.

  • WireGuard tunnel addresses, implemented and offline-tested (v0.6.0
    Phase B, Batch E — not yet registered).
    New
    WireGuardTunnelAddress model/client method for
    vpn/wireguard/tunnel/addresses (address/mask/descr, none
    writeOnly, no secret material — address/mask redacted by
    default, matching RoutingStaticRoute's established convention).
    Independently re-confirmed NOT redundant with the already-shipped
    WireGuardTunnelStatus, which has no address/CIDR field at all —
    unlike WireGuard peer allowed-IPs, deliberately not implemented
    since it is already nested as WireGuardPeerStatus.allowed_ips.
    pfSense-pkg-WireGuard is already installed on the LAB (prior,
    separately authorized action), so package availability is not this
    batch's blocker — the same read-only LAB service-account privilege
    scope issue as Batches C/D is. Not registered as a public tool. Public
    contract unchanged at 85 READ / 0 default WRITE.

  • v0.6.0 Phase B completion: LAB-verified and registered all 10
    previously-pending Batch C/D/E candidates.
    The read-only LAB
    service account (pfsense-mcp, id=2) was synced from a stale
    42-privilege snapshot (dating to its original 2026-08-19 ADR-033
    provisioning) to the current full requirement, after reconciling —
    with direct evidence from AI_CONTEXT.md's own provisioning
    checkpoint, not assumption — that this account is the project's
    single, intentionally-provisioned write_protected-profile service
    account (hence its pre-existing api-v2-firewall-alias-patch
    privilege, preserved throughout the sync). All 10 candidates were
    then live-verified in one pass:

    • pfsense_get_status_logs_settingsFIELD_MODEL_LIVE_VERIFIED.
      Fixed a real defect found by the live call, not assumed correct:
      sourceip needed the same nullable: falseOptional widening
      already applied to 17 other fields, missed in the earlier partial
      fix — a second live parse attempt (not a first-pass assumption)
      caught it.
    • pfsense_get_firewall_virtual_ip_apply_status,
      pfsense_get_interface_apply_status,
      pfsense_get_routing_apply_status,
      pfsense_get_dhcp_server_apply_status,
      pfsense_get_dns_forwarder_apply_status,
      pfsense_get_dns_resolver_apply_status,
      pfsense_get_ipsec_apply_status,
      pfsense_get_wireguard_apply_status — all 8
      FIELD_MODEL_LIVE_VERIFIED, exact key-set match, independently
      confirmed per-endpoint (not inferred from one passing).
    • pfsense_get_vpn_wireguard_tunnel_addresses
      ENDPOINT_VERIFIED (200, {"data": []} — no tunnel addresses
      configured on this LAB; field safety rests on the Phase A
      schema/security review, not an observed populated item).

    Public contract: 85 → 95 READ tools (0 default WRITE, unchanged).
    Useful READ coverage: 95/105 (unchanged historical denominator, per
    the Phase A correction). tests/fixtures/pfsense_openapi_schema_trimmed.json
    extended with all 10 endpoints' real captured descriptions (needed
    for the security-bootstrap/privilege-derivation test suite, which
    resolves privileges from this fixture). Fixed the resulting
    hardcoded-count cascade across test files, docs/API.md, and
    docs/PFSENSE_LEAST_PRIVILEGE_MATRIX.md.

Fixed

  • Stale tool-count/coverage claims across README, docs, and examples,
    found during this release's own release-readiness audit: the 84→95
    increase above was reflected in docs/API.md and
    docs/PFSENSE_LEAST_PRIVILEGE_MATRIX.md (updated as part of the
    READ-capability work itself) but not yet in README.md (Key facts,
    architecture diagram labels, capability-overview table and per-category
    counts, package-conditional-tools note), docs/ARCHITECTURE_DIAGRAMS.md,
    docs/API_SURFACE_ARCHITECTURE.md, docs/CONFIGURATION.md,
    docs/PYPI_RELEASE.md, docs/SECURITY_MODEL.md, docs/THREAT_MODEL.md,
    docs/index.md, or any of the 7 client-setup guides under examples/.
    Evidence-tier distinctions were preserved rather than strengthened:
    README's Plus 26.07 PRODUCTION VERIFIED row keeps its exact "82 of
    84" historical claim unchanged (that pass predates this release's 11
    additions) and now explicitly states those 11 tools are LAB VERIFIED
    only, not production-verified. Historical, dated narrative describing
    specific past batches/releases (e.g. v0.5.0's own "42 → 84 tools"
    delta) was left untouched, matching this project's established
    release-immutability convention.