Skip to content

Commit 4190c8c

Browse files
Merge pull request #906 from pfrest/next_patch
v2.8.1 Fixes
2 parents 7560ef8 + 5b85beb commit 4190c8c

10 files changed

Lines changed: 143 additions & 11 deletions

File tree

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ jobs:
121121
- name: Install Node.js
122122
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
123123
with:
124-
node-version: "20"
124+
node-version: "26"
125125

126126
- name: Install npm dependencies
127127
run: npm i

.github/workflows/quality.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
99
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
1010
with:
11-
node-version: 20
11+
node-version: 26
1212
- name: Install npm packages
1313
run: npm install
1414
- name: Check Prettier

.github/workflows/release.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ jobs:
3232
PFSENSE_VERSION: "25.11.1"
3333
- FREEBSD_VERSION: FreeBSD-16.0-CURRENT
3434
PFSENSE_VERSION: "26.03"
35+
- FREEBSD_VERSION: FreeBSD-16.0-CURRENT
36+
PFSENSE_VERSION: "26.03.1"
3537

3638
steps:
3739
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pkg-static add https://github.com/pfrest/pfSense-pkg-RESTAPI/releases/latest/dow
4242
Install on pfSense Plus:
4343

4444
```bash
45-
pkg-static -C /dev/null add https://github.com/pfrest/pfSense-pkg-RESTAPI/releases/latest/download/pfSense-26.03-pkg-RESTAPI.pkg
45+
pkg-static -C /dev/null add https://github.com/pfrest/pfSense-pkg-RESTAPI/releases/latest/download/pfSense-26.03.1-pkg-RESTAPI.pkg
4646
```
4747

4848
> [!WARNING]

docs/INSTALL_AND_CONFIG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ run pfSense. It's recommended to follow Netgate's [minimum hardware requirements
1717
- pfSense CE 2.8.1
1818
- pfSense Plus 25.11.1
1919
- pfSense Plus 26.03
20+
- pfSense Plus 26.03.1
21+
2022

2123
!!! Warning
2224
Installation of the package on unsupported versions of pfSense may result in unexpected behavior and/or system instability.

docs/QUERIES_FILTERS_AND_SORTING.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,11 @@ value array contains a given value for array fields.
5656

5757
Search for objects whose field value is within a given array of values (when the filter value is an array), or search
5858
for objects whose field value is a substring of a given string (when the filter value is a string).
59+
5960
- Name: `in`
6061
- Examples:
61-
- `https://pfsense.example.com/api/v2/examples?fieldname__in=example`
62-
- `https://pfsense.example.com/api/v2/examples?fieldname__in[]=example1&fieldname__in[]=example2`
62+
- `https://pfsense.example.com/api/v2/examples?fieldname__in=example`
63+
- `https://pfsense.example.com/api/v2/examples?fieldname__in[]=example1&fieldname__in[]=example2`
6364

6465
### Less Than (lt)
6566

@@ -95,8 +96,8 @@ Search for objects whose field value matches a given format.
9596

9697
- Name: `format`
9798
- Examples:
98-
- `https://pfsense.example.com/api/v2/examples?fieldname__format=ipv4`
99-
- `https://pfsense.example.com/api/v2/examples?fieldname__format=email`
99+
- `https://pfsense.example.com/api/v2/examples?fieldname__format=ipv4`
100+
- `https://pfsense.example.com/api/v2/examples?fieldname__format=email`
100101

101102
#### Supported Formats
102103

pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Caches/RESTAPIVersionReleasesCache.inc

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,16 @@ class RESTAPIVersionReleasesCache extends Cache {
3232
);
3333
$releases = json_decode($releases_json, true);
3434

35-
# Return the fetched releases if in a valid format, otherwise retain the existing cache
36-
return is_array($releases) ? $releases : $this->read();
35+
# If we don't have an 'assets' key, the response is invalid. Log the response, keep the existing cache
36+
if (!is_array($releases) or !array_key_exists(0, $releases) or !array_key_exists('assets', $releases[0])) {
37+
Cache::log(
38+
level: LOG_ERR,
39+
message: "Releases data is malformed, received $releases_json. Keeping existing cache.",
40+
);
41+
return $this->read();
42+
}
43+
44+
# Return the fetched releases
45+
return $releases;
3746
}
3847
}

pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Core/Dispatcher.inc

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace RESTAPI\Core;
44

55
use RESTAPI\Models\CronJob;
6+
use RESTAPI\Models\RESTAPISettings;
67
use RESTAPI\Responses\FailedDependencyError;
78
use RESTAPI\Responses\ServerError;
89
use RESTAPI\Responses\ServiceUnavailableError;
@@ -119,10 +120,18 @@ class Dispatcher {
119120
* @throws FailedDependencyError When a package requires a PHP include file that could not be found.
120121
*/
121122
private function check_required_packages(): void {
123+
# Check if the user has opted in to using development (-devel) package variants
124+
$pkg_config = RESTAPISettings::get_pkg_config();
125+
$allow_development_packages = ($pkg_config['allow_development_packages'] ?? '') === 'enabled';
126+
122127
# Loop through each required package and ensure it is present on the system.
123128
foreach ($this->required_packages as $pkg) {
124-
# Return an error if the package is not installed
125-
if (!is_pkg_installed($pkg)) {
129+
# When the development packages setting is enabled, also accept the -devel variant of the package
130+
$devel_pkg = $pkg . '-devel';
131+
$pkg_installed = is_pkg_installed($pkg) || ($allow_development_packages && is_pkg_installed($devel_pkg));
132+
133+
# Return an error if neither the package nor its -devel variant (when allowed) is installed
134+
if (!$pkg_installed) {
126135
throw new FailedDependencyError(
127136
message: "The requested action requires the '$pkg' package but it is not installed.",
128137
response_id: 'DISPATCHER_MISSING_REQUIRED_PACKAGE',

pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/WireGuardTunnel.inc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,18 @@ class WireGuardTunnel extends Model {
145145
return wg_is_key_clamped($privatekey) ? $privatekey : wg_clamp_key($privatekey);
146146
}
147147

148+
/**
149+
* Extends the default _update method to ensure addresses are removed if the tunnel has an interface assignment
150+
*/
151+
public function _update(): void {
152+
# Remove any existing addresses if this tunnel has an existing interface assignment
153+
if (NetworkInterface::query(if: $this->name->value)->exists()) {
154+
$this->addresses->value = [];
155+
}
156+
157+
parent::_update();
158+
}
159+
148160
/**
149161
* Obtains the next available WireGuard tunnel interface name.
150162
* @return string The next available WireGuard tunnel interface name (i.e. tun_wg0)

pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APICoreDispatcherTestCase.inc

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use RESTAPI\Core\Dispatcher;
66
use RESTAPI\Core\TestCase;
77
use RESTAPI\Dispatchers\WireGuardApplyDispatcher;
88
use RESTAPI\Models\Package;
9+
use RESTAPI\Models\RESTAPISettings;
910

1011
class APICoreDispatcherTestCase extends TestCase {
1112
/**
@@ -176,4 +177,100 @@ class APICoreDispatcherTestCase extends TestCase {
176177
# Remove the installed package
177178
$package->delete();
178179
}
180+
181+
/**
182+
* Checks that a Dispatcher requiring a package that is not installed throws DISPATCHER_MISSING_REQUIRED_PACKAGE
183+
* when the `allow_development_packages` setting is disabled (default).
184+
*/
185+
public function test_required_package_missing_throws_by_default(): void {
186+
# Ensure the allow_development_packages setting is disabled
187+
$settings = new RESTAPISettings();
188+
$settings->from_internal();
189+
$original = $settings->allow_development_packages->value;
190+
191+
if ($original) {
192+
$settings->allow_development_packages->value = false;
193+
$settings->update(apply: false);
194+
}
195+
196+
# A Dispatcher requiring a package that is not installed should fail
197+
$this->assert_throws_response(
198+
response_id: 'DISPATCHER_MISSING_REQUIRED_PACKAGE',
199+
code: 424,
200+
callable: function () {
201+
$dispatcher = new RequiredPackagesTestDispatcher();
202+
$dispatcher->required_packages = ['pfSense-pkg-some_package_we_dont_have'];
203+
$dispatcher->process();
204+
},
205+
);
206+
}
207+
208+
/**
209+
* Checks that when `allow_development_packages` is enabled, a Dispatcher whose required package is not installed
210+
* and whose -devel counterpart is also not installed still throws DISPATCHER_MISSING_REQUIRED_PACKAGE. Since we
211+
* cannot install arbitrary packages in tests, we verify the inverse: a package whose -devel name also doesn't
212+
* exist still fails even with the setting enabled.
213+
*/
214+
public function test_devel_variant_still_fails_when_neither_installed(): void {
215+
# Enable the allow_development_packages setting
216+
$settings = new RESTAPISettings();
217+
$settings->from_internal();
218+
$settings->allow_development_packages->value = true;
219+
$settings->update(apply: false);
220+
221+
# Even with the setting on, if neither the base package nor the -devel variant is installed, it should fail
222+
$this->assert_throws_response(
223+
response_id: 'DISPATCHER_MISSING_REQUIRED_PACKAGE',
224+
code: 424,
225+
callable: function () {
226+
$dispatcher = new RequiredPackagesTestDispatcher();
227+
$dispatcher->required_packages = ['pfSense-pkg-some_package_we_dont_have'];
228+
$dispatcher->process();
229+
},
230+
);
231+
232+
# Restore the setting to its original value
233+
$settings->allow_development_packages->value = false;
234+
$settings->update(apply: false);
235+
}
236+
237+
/**
238+
* Checks that when `allow_development_packages` is enabled, a Dispatcher whose required base package is installed
239+
* (using pfSense-pkg-RESTAPI as a proxy for the base package) still passes the required package check.
240+
*/
241+
public function test_base_package_accepted_when_devel_enabled(): void {
242+
# Enable the allow_development_packages setting
243+
$settings = new RESTAPISettings();
244+
$settings->from_internal();
245+
$settings->allow_development_packages->value = true;
246+
$settings->update(apply: false);
247+
248+
# The base package (pfSense-pkg-RESTAPI) is installed; the package check should still pass
249+
$this->assert_does_not_throw(
250+
callable: function () {
251+
$dispatcher = new RequiredPackagesTestDispatcher();
252+
$dispatcher->required_packages = ['pfSense-pkg-RESTAPI'];
253+
$dispatcher->process();
254+
},
255+
);
256+
257+
# Restore the setting to its original value
258+
$settings->allow_development_packages->value = false;
259+
$settings->update(apply: false);
260+
}
261+
}
262+
263+
/**
264+
* Defines a test-only Dispatcher used to exercise the $required_packages check without spawning a real background
265+
* process. The $required_packages property is exposed publicly so individual tests can assign the package(s) to
266+
* check, and _process() is intentionally a no-op so calling process() only runs the required package validation.
267+
*/
268+
class RequiredPackagesTestDispatcher extends Dispatcher {
269+
public array $required_packages = [];
270+
271+
/**
272+
* Overrides the default _process() with a no-op so tests can validate the package check in isolation.
273+
* @param mixed ...$arguments Unused arguments accepted to match the parent signature.
274+
*/
275+
protected function _process(mixed ...$arguments): void {}
179276
}

0 commit comments

Comments
 (0)