From 09878061311f8be094e035f69359bcf311e7e557 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 16 May 2026 15:42:42 -0600 Subject: [PATCH 01/14] chore: bump the github-actions group with 3 updates (#899) --- .github/workflows/quality.yml | 4 ++-- .github/workflows/release.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 6358f03d..b4c601de 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: psf/black@c6755bb741b6481d6b3d3bb563c83fa060db96c9 # 26.3.1 + - uses: psf/black@d2490e24dad33b8f68c77602ee29160de0fea24b # 26.5.0 lint_php: runs-on: ubuntu-latest @@ -29,7 +29,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: "Setup PHP ${{ matrix.PHP_VERSION }}" - uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 + uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # 2.37.1 with: php-version: "${{ matrix.PHP_VERSION }}" coverage: "none" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dcf184b1..d09b5a9c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -165,7 +165,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Pages - uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 + uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 - name: Make website directory run: mkdir ./www From dce1d7bf01b949c120cf9224fdc6e0acb153ebb0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 16 May 2026 15:43:09 -0600 Subject: [PATCH 02/14] chore: bump @stoplight/spectral-cli in the npm group (#898) --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index fdc00204..2b7ac456 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "": { "devDependencies": { "@prettier/plugin-php": "^0.25.0", - "@stoplight/spectral-cli": "^6.15.1", + "@stoplight/spectral-cli": "^6.16.0", "prettier": "^3.8.3" } }, @@ -241,9 +241,9 @@ } }, "node_modules/@stoplight/spectral-cli": { - "version": "6.15.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.15.1.tgz", - "integrity": "sha512-ev72bUglbaZvFSMWCP5o1Iso5NGgbLZOAuedvRxYrUMey9dVCR83i033tSFvDv6cpj86HsbEmiilh8vwrY/asQ==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.16.0.tgz", + "integrity": "sha512-P1acHIV/hDiO3w0YNUc3pD7/0q68SMAMyWVxAPUGzsAeq50lLpl0obN5j3QITMgJPhPByvBIjBV4ftkBd8nwMg==", "dev": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index e0401f37..8eb7545f 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,6 @@ "devDependencies": { "prettier": "^3.8.3", "@prettier/plugin-php": "^0.25.0", - "@stoplight/spectral-cli": "^6.15.1" + "@stoplight/spectral-cli": "^6.16.0" } } From 431baab2f7fa530fa0ef71933615f7b94b6538e5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 16 May 2026 15:43:34 -0600 Subject: [PATCH 03/14] chore: update black requirement in the pip group (#897) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 138b0b14..87598b91 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ jinja2~=3.1.6 pylint~=4.0.5 -black~=26.3.1 +black~=26.5.0 mkdocs~=1.6.1 From 1fe956da1028cd3f02b47e46a6440e0e34ac75f4 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Fri, 5 Jun 2026 17:02:14 -0600 Subject: [PATCH 04/14] ci: use node from 20 to 26 --- .github/workflows/build.yml | 2 +- .github/workflows/quality.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d5faef96..0ba335f3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -121,7 +121,7 @@ jobs: - name: Install Node.js uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: "20" + node-version: "26" - name: Install npm dependencies run: npm i diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index b4c601de..f1007962 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -8,7 +8,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: 20 + node-version: 26 - name: Install npm packages run: npm install - name: Check Prettier From 725757da9a98142e5bc97465e7f0e8aedc6a8aa8 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Fri, 5 Jun 2026 17:02:54 -0600 Subject: [PATCH 05/14] feat: add build for pfSense Plus 26.03.1 --- .github/workflows/release.yml | 2 ++ README.md | 2 +- docs/INSTALL_AND_CONFIG.md | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d09b5a9c..19098db9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,6 +32,8 @@ jobs: PFSENSE_VERSION: "25.11.1" - FREEBSD_VERSION: FreeBSD-16.0-CURRENT PFSENSE_VERSION: "26.03" + - FREEBSD_VERSION: FreeBSD-16.0-CURRENT + PFSENSE_VERSION: "26.03.1" steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 diff --git a/README.md b/README.md index 8b902d1e..3687aa56 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ pkg-static add https://github.com/pfrest/pfSense-pkg-RESTAPI/releases/latest/dow Install on pfSense Plus: ```bash -pkg-static -C /dev/null add https://github.com/pfrest/pfSense-pkg-RESTAPI/releases/latest/download/pfSense-26.03-pkg-RESTAPI.pkg +pkg-static -C /dev/null add https://github.com/pfrest/pfSense-pkg-RESTAPI/releases/latest/download/pfSense-26.03.1-pkg-RESTAPI.pkg ``` > [!WARNING] diff --git a/docs/INSTALL_AND_CONFIG.md b/docs/INSTALL_AND_CONFIG.md index 63fadf30..0c21b0f2 100644 --- a/docs/INSTALL_AND_CONFIG.md +++ b/docs/INSTALL_AND_CONFIG.md @@ -17,6 +17,8 @@ run pfSense. It's recommended to follow Netgate's [minimum hardware requirements - pfSense CE 2.8.1 - pfSense Plus 25.11.1 - pfSense Plus 26.03 +- pfSense Plus 26.03.1 + !!! Warning Installation of the package on unsupported versions of pfSense may result in unexpected behavior and/or system instability. From 7e354c323425348183ab5434203df9bf575ab586 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Fri, 5 Jun 2026 17:06:40 -0600 Subject: [PATCH 06/14] docs: fix bad indents in filter docs --- docs/QUERIES_FILTERS_AND_SORTING.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/QUERIES_FILTERS_AND_SORTING.md b/docs/QUERIES_FILTERS_AND_SORTING.md index 5e85533d..3d7773bf 100644 --- a/docs/QUERIES_FILTERS_AND_SORTING.md +++ b/docs/QUERIES_FILTERS_AND_SORTING.md @@ -56,10 +56,11 @@ value array contains a given value for array fields. Search for objects whose field value is within a given array of values (when the filter value is an array), or search for objects whose field value is a substring of a given string (when the filter value is a string). + - Name: `in` - Examples: - - `https://pfsense.example.com/api/v2/examples?fieldname__in=example` - - `https://pfsense.example.com/api/v2/examples?fieldname__in[]=example1&fieldname__in[]=example2` + - `https://pfsense.example.com/api/v2/examples?fieldname__in=example` + - `https://pfsense.example.com/api/v2/examples?fieldname__in[]=example1&fieldname__in[]=example2` ### Less Than (lt) @@ -95,8 +96,8 @@ Search for objects whose field value matches a given format. - Name: `format` - Examples: - - `https://pfsense.example.com/api/v2/examples?fieldname__format=ipv4` - - `https://pfsense.example.com/api/v2/examples?fieldname__format=email` + - `https://pfsense.example.com/api/v2/examples?fieldname__format=ipv4` + - `https://pfsense.example.com/api/v2/examples?fieldname__format=email` #### Supported Formats From fbee00c442efd2296868e9c4c39f2e6d75c712e7 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Fri, 5 Jun 2026 17:46:23 -0600 Subject: [PATCH 07/14] fix(RESTAPIVersionReleasesCache): don't cache bad gh api responses #900 --- .../RESTAPI/Caches/RESTAPIVersionReleasesCache.inc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Caches/RESTAPIVersionReleasesCache.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Caches/RESTAPIVersionReleasesCache.inc index 7eddd76a..7b956f29 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Caches/RESTAPIVersionReleasesCache.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Caches/RESTAPIVersionReleasesCache.inc @@ -32,7 +32,16 @@ class RESTAPIVersionReleasesCache extends Cache { ); $releases = json_decode($releases_json, true); - # Return the fetched releases if in a valid format, otherwise retain the existing cache - return is_array($releases) ? $releases : $this->read(); + # If we don't have an 'assets' key, the response is invalid. Log the response, keep the existing cache + if (!is_array($releases) or !array_key_exists('assets', $releases)) { + Cache::log( + level: LOG_ERR, + message: "Releases data is malformed, received $releases_json. Keeping existing cache.", + ); + return $this->read(); + } + + # Return the fetched releases + return $releases; } } From d8d4732b5a820a69f42e744a43844bebdf0defa0 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Fri, 5 Jun 2026 17:51:48 -0600 Subject: [PATCH 08/14] fix(WireGuardTunnel): ignore addresses if tunnel has a current iface assignment #902 --- .../local/pkg/RESTAPI/Models/WireGuardTunnel.inc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/WireGuardTunnel.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/WireGuardTunnel.inc index fcf38ce6..7feb9b2a 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/WireGuardTunnel.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/WireGuardTunnel.inc @@ -145,6 +145,19 @@ class WireGuardTunnel extends Model { return wg_is_key_clamped($privatekey) ? $privatekey : wg_clamp_key($privatekey); } + /** + * Extends the default _update method to ensure addresses are removed if the tunnel has an interface assignment + */ + public function _update(): void + { + # Remove any existing addresses if this tunnel has an existing interface assignment + if (NetworkInterface::query(if: $this->name->value)->exists()) { + $this->addresses->value = null; + } + + parent::_update(); + } + /** * Obtains the next available WireGuard tunnel interface name. * @return string The next available WireGuard tunnel interface name (i.e. tun_wg0) From e81b30ce2f33dc2bcad962945969742a72ce4dce Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Fri, 5 Jun 2026 17:52:18 -0600 Subject: [PATCH 09/14] style: run prettier on changed files --- .../files/usr/local/pkg/RESTAPI/Models/WireGuardTunnel.inc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/WireGuardTunnel.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/WireGuardTunnel.inc index 7feb9b2a..17650ea5 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/WireGuardTunnel.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/WireGuardTunnel.inc @@ -148,8 +148,7 @@ class WireGuardTunnel extends Model { /** * Extends the default _update method to ensure addresses are removed if the tunnel has an interface assignment */ - public function _update(): void - { + public function _update(): void { # Remove any existing addresses if this tunnel has an existing interface assignment if (NetworkInterface::query(if: $this->name->value)->exists()) { $this->addresses->value = null; From 3235c8a33121d71b7dca0d7796bc9eee6e0df5c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 18:18:55 -0600 Subject: [PATCH 10/14] chore: update black requirement in the pip group (#903) Updates the requirements on [black](https://github.com/psf/black) to permit the latest version. Updates `black` to 26.5.1 - [Release notes](https://github.com/psf/black/releases) - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - [Commits](https://github.com/psf/black/compare/26.5.0...26.5.1) --- updated-dependencies: - dependency-name: black dependency-version: 26.5.1 dependency-type: direct:production dependency-group: pip ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 87598b91..96ee0a89 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ jinja2~=3.1.6 pylint~=4.0.5 -black~=26.5.0 +black~=26.5.1 mkdocs~=1.6.1 From 7560ef8d68f0d55f07e8505cdf1911bbd0a20b4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 18:25:46 -0600 Subject: [PATCH 11/14] chore: bump the github-actions group with 2 updates (#904) Bumps the github-actions group with 2 updates: [psf/black](https://github.com/psf/black) and [actions/stale](https://github.com/actions/stale). Updates `psf/black` from 26.5.0 to 26.5.1 - [Release notes](https://github.com/psf/black/releases) - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - [Commits](https://github.com/psf/black/compare/d2490e24dad33b8f68c77602ee29160de0fea24b...87928e6d6761a4a6d22250e1fee5601b3998086e) Updates `actions/stale` from 10.2.0 to 10.3.0 - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/b5d41d4e1d5dceea10e7104786b73624c18a190f...eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899) --- updated-dependencies: - dependency-name: psf/black dependency-version: 26.5.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/stale dependency-version: 10.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jared Hendrickson --- .github/workflows/quality.yml | 2 +- .github/workflows/schedule_weekly.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index b4c601de..ec6e7cd7 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: psf/black@d2490e24dad33b8f68c77602ee29160de0fea24b # 26.5.0 + - uses: psf/black@87928e6d6761a4a6d22250e1fee5601b3998086e # 26.5.1 lint_php: runs-on: ubuntu-latest diff --git a/.github/workflows/schedule_weekly.yml b/.github/workflows/schedule_weekly.yml index 4e643a72..7a2ad380 100644 --- a/.github/workflows/schedule_weekly.yml +++ b/.github/workflows/schedule_weekly.yml @@ -15,7 +15,7 @@ jobs: env: DAYS_BEFORE_STALE: 60 steps: - - uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0 + - uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0 with: stale-issue-message: | This issue has been automatically marked as stale because it has had no recent activity in the last ${{ env.DAYS_BEFORE_STALE }} days. From 3cd158bc7d3855682fb40443e410a7985e154451 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Fri, 5 Jun 2026 18:30:36 -0600 Subject: [PATCH 12/14] fix(Dispatcher): accept devel variants when allow_development_packages is enabled #905 --- .../usr/local/pkg/RESTAPI/Core/Dispatcher.inc | 13 ++- .../Tests/APICoreDispatcherTestCase.inc | 97 +++++++++++++++++++ 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Core/Dispatcher.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Core/Dispatcher.inc index 5411d4a1..021e7591 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Core/Dispatcher.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Core/Dispatcher.inc @@ -3,6 +3,7 @@ namespace RESTAPI\Core; use RESTAPI\Models\CronJob; +use RESTAPI\Models\RESTAPISettings; use RESTAPI\Responses\FailedDependencyError; use RESTAPI\Responses\ServerError; use RESTAPI\Responses\ServiceUnavailableError; @@ -119,10 +120,18 @@ class Dispatcher { * @throws FailedDependencyError When a package requires a PHP include file that could not be found. */ private function check_required_packages(): void { + # Check if the user has opted in to using development (-devel) package variants + $pkg_config = RESTAPISettings::get_pkg_config(); + $allow_development_packages = ($pkg_config['allow_development_packages'] ?? '') === 'enabled'; + # Loop through each required package and ensure it is present on the system. foreach ($this->required_packages as $pkg) { - # Return an error if the package is not installed - if (!is_pkg_installed($pkg)) { + # When the development packages setting is enabled, also accept the -devel variant of the package + $devel_pkg = $pkg . '-devel'; + $pkg_installed = is_pkg_installed($pkg) || ($allow_development_packages && is_pkg_installed($devel_pkg)); + + # Return an error if neither the package nor its -devel variant (when allowed) is installed + if (!$pkg_installed) { throw new FailedDependencyError( message: "The requested action requires the '$pkg' package but it is not installed.", response_id: 'DISPATCHER_MISSING_REQUIRED_PACKAGE', diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APICoreDispatcherTestCase.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APICoreDispatcherTestCase.inc index ceddaf44..52ea30d5 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APICoreDispatcherTestCase.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APICoreDispatcherTestCase.inc @@ -6,6 +6,7 @@ use RESTAPI\Core\Dispatcher; use RESTAPI\Core\TestCase; use RESTAPI\Dispatchers\WireGuardApplyDispatcher; use RESTAPI\Models\Package; +use RESTAPI\Models\RESTAPISettings; class APICoreDispatcherTestCase extends TestCase { /** @@ -176,4 +177,100 @@ class APICoreDispatcherTestCase extends TestCase { # Remove the installed package $package->delete(); } + + /** + * Checks that a Dispatcher requiring a package that is not installed throws DISPATCHER_MISSING_REQUIRED_PACKAGE + * when the `allow_development_packages` setting is disabled (default). + */ + public function test_required_package_missing_throws_by_default(): void { + # Ensure the allow_development_packages setting is disabled + $settings = new RESTAPISettings(); + $settings->from_internal(); + $original = $settings->allow_development_packages->value; + + if ($original) { + $settings->allow_development_packages->value = false; + $settings->update(apply: false); + } + + # A Dispatcher requiring a package that is not installed should fail + $this->assert_throws_response( + response_id: 'DISPATCHER_MISSING_REQUIRED_PACKAGE', + code: 424, + callable: function () { + $dispatcher = new RequiredPackagesTestDispatcher(); + $dispatcher->required_packages = ['pfSense-pkg-some_package_we_dont_have']; + $dispatcher->process(); + }, + ); + } + + /** + * Checks that when `allow_development_packages` is enabled, a Dispatcher whose required package is not installed + * and whose -devel counterpart is also not installed still throws DISPATCHER_MISSING_REQUIRED_PACKAGE. Since we + * cannot install arbitrary packages in tests, we verify the inverse: a package whose -devel name also doesn't + * exist still fails even with the setting enabled. + */ + public function test_devel_variant_still_fails_when_neither_installed(): void { + # Enable the allow_development_packages setting + $settings = new RESTAPISettings(); + $settings->from_internal(); + $settings->allow_development_packages->value = true; + $settings->update(apply: false); + + # Even with the setting on, if neither the base package nor the -devel variant is installed, it should fail + $this->assert_throws_response( + response_id: 'DISPATCHER_MISSING_REQUIRED_PACKAGE', + code: 424, + callable: function () { + $dispatcher = new RequiredPackagesTestDispatcher(); + $dispatcher->required_packages = ['pfSense-pkg-some_package_we_dont_have']; + $dispatcher->process(); + }, + ); + + # Restore the setting to its original value + $settings->allow_development_packages->value = false; + $settings->update(apply: false); + } + + /** + * Checks that when `allow_development_packages` is enabled, a Dispatcher whose required base package is installed + * (using pfSense-pkg-RESTAPI as a proxy for the base package) still passes the required package check. + */ + public function test_base_package_accepted_when_devel_enabled(): void { + # Enable the allow_development_packages setting + $settings = new RESTAPISettings(); + $settings->from_internal(); + $settings->allow_development_packages->value = true; + $settings->update(apply: false); + + # The base package (pfSense-pkg-RESTAPI) is installed; the package check should still pass + $this->assert_does_not_throw( + callable: function () { + $dispatcher = new RequiredPackagesTestDispatcher(); + $dispatcher->required_packages = ['pfSense-pkg-RESTAPI']; + $dispatcher->process(); + }, + ); + + # Restore the setting to its original value + $settings->allow_development_packages->value = false; + $settings->update(apply: false); + } +} + +/** + * Defines a test-only Dispatcher used to exercise the $required_packages check without spawning a real background + * process. The $required_packages property is exposed publicly so individual tests can assign the package(s) to + * check, and _process() is intentionally a no-op so calling process() only runs the required package validation. + */ +class RequiredPackagesTestDispatcher extends Dispatcher { + public array $required_packages = []; + + /** + * Overrides the default _process() with a no-op so tests can validate the package check in isolation. + * @param mixed ...$arguments Unused arguments accepted to match the parent signature. + */ + protected function _process(mixed ...$arguments): void {} } From e05c3b65272ab428c900401711745f93aa58f1ca Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Sat, 6 Jun 2026 19:27:51 -0600 Subject: [PATCH 13/14] chore: improve cache handling logic --- .../local/pkg/RESTAPI/Caches/RESTAPIVersionReleasesCache.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Caches/RESTAPIVersionReleasesCache.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Caches/RESTAPIVersionReleasesCache.inc index 7b956f29..ca9b9277 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Caches/RESTAPIVersionReleasesCache.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Caches/RESTAPIVersionReleasesCache.inc @@ -33,7 +33,7 @@ class RESTAPIVersionReleasesCache extends Cache { $releases = json_decode($releases_json, true); # If we don't have an 'assets' key, the response is invalid. Log the response, keep the existing cache - if (!is_array($releases) or !array_key_exists('assets', $releases)) { + if (!is_array($releases) or !array_key_exists(0, $releases) or !array_key_exists('assets', $releases[0])) { Cache::log( level: LOG_ERR, message: "Releases data is malformed, received $releases_json. Keeping existing cache.", From df78467ad6ab3a34294b0fe25d19e666dcba0ccb Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Sat, 6 Jun 2026 22:54:06 -0600 Subject: [PATCH 14/14] refactor(WireGuardTunnel): empty addresses with iface assignment --- .../files/usr/local/pkg/RESTAPI/Models/WireGuardTunnel.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/WireGuardTunnel.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/WireGuardTunnel.inc index 17650ea5..63a3b53b 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/WireGuardTunnel.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/WireGuardTunnel.inc @@ -151,7 +151,7 @@ class WireGuardTunnel extends Model { public function _update(): void { # Remove any existing addresses if this tunnel has an existing interface assignment if (NetworkInterface::query(if: $this->name->value)->exists()) { - $this->addresses->value = null; + $this->addresses->value = []; } parent::_update();