diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d3db4f15..20d47009 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -134,6 +134,8 @@ jobs: include: - PFSENSE_VERSION: pfSense-2.8.1-RELEASE FREEBSD_ID: freebsd15 + - PFSENSE_VERSION: pfSense-2.9.0-RELEASE + FREEBSD_ID: freebsd16 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b178d34e..89698940 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ concurrency: build env: SWAGGER_UI_VERSION: "5.17.10" PYTHON_VERSION: "3.10" - DEFAULT_PFSENSE_VERSION: "2.8.1" + DEFAULT_PFSENSE_VERSION: "2.9.0" # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: @@ -28,12 +28,16 @@ jobs: # Note: The first item in this matrix must use env.DEFAULT_PFSENSE_VERSION as the PFSENSE_VERSION! - FREEBSD_VERSION: FreeBSD-15.0-CURRENT PFSENSE_VERSION: "2.8.1" + - FREEBSD_VERSION: FreeBSD-15.0-CURRENT + PFSENSE_VERSION: "2.9.0" - FREEBSD_VERSION: FreeBSD-16.0-CURRENT 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" + - FREEBSD_VERSION: FreeBSD-16.0-CURRENT + PFSENSE_VERSION: "26.07" steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 diff --git a/docs/INSTALL_AND_CONFIG.md b/docs/INSTALL_AND_CONFIG.md index 0c21b0f2..a7c5ebfe 100644 --- a/docs/INSTALL_AND_CONFIG.md +++ b/docs/INSTALL_AND_CONFIG.md @@ -15,10 +15,11 @@ run pfSense. It's recommended to follow Netgate's [minimum hardware requirements ### Supported pfSense versions - pfSense CE 2.8.1 +- pfSense CE 2.9.0 - pfSense Plus 25.11.1 - pfSense Plus 26.03 - pfSense Plus 26.03.1 - +- pfSense Plus 26.07 !!! Warning Installation of the package on unsupported versions of pfSense may result in unexpected behavior and/or system instability. diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Core/Model.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Core/Model.inc index 9fed4dd1..fae9e82e 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Core/Model.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Core/Model.inc @@ -800,7 +800,7 @@ class Model { # Clear the object cache for all Model classes since config is being reloaded self::clear_model_cache(); - $config = parse_config(parse: $force_parse); + config_read_file(); } /** diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Dispatchers/FirewallApplyDispatcher.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Dispatchers/FirewallApplyDispatcher.inc index b41141fc..54086bfd 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Dispatchers/FirewallApplyDispatcher.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Dispatchers/FirewallApplyDispatcher.inc @@ -2,6 +2,7 @@ namespace RESTAPI\Dispatchers; +use RESTAPI\Core\Command; use RESTAPI\Core\Dispatcher; /** @@ -12,10 +13,6 @@ class FirewallApplyDispatcher extends Dispatcher { * Reloads the filter services. */ protected function _process(mixed ...$arguments): void { - if ($this->async) { - filter_configure(); - } else { - filter_configure_sync(); - } + new Command('/etc/rc.filter_configure_sync'); } } diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/DHCPServer.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/DHCPServer.inc index f3c6877a..da29058f 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/DHCPServer.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/DHCPServer.inc @@ -17,6 +17,7 @@ use RESTAPI\Responses\ConflictError; use RESTAPI\Responses\ValidationError; use RESTAPI\Validators\IPAddressValidator; use RESTAPI\Validators\MACAddressValidator; +use RESTAPI\Validators\URLValidator; /** * Defines a Model that interacts with the DHCP server for a given interface. @@ -48,6 +49,15 @@ class DHCPServer extends Model { public NestedModelField $pool; public NestedModelField $numberoptions; public NestedModelField $staticmap; + public BooleanField $netboot; + public StringField $nextserver; + public StringField $filename; + public StringField $filename32; + public StringField $filename64; + public StringField $filename32arm; + public StringField $filename64arm; + public StringField $uefihttpboot; + public StringField $rootpath; public function __construct(mixed $id = null, mixed $parent_id = null, mixed $data = [], mixed ...$options) { # Define Model attributes @@ -78,10 +88,10 @@ class DHCPServer extends Model { default: '', allow_empty: true, maximum_length: 15, + verbose_name: 'Range From', internal_name: 'from', internal_namespace: 'range', validators: [new IPAddressValidator(allow_ipv4: true, allow_ipv6: false)], - verbose_name: 'Range From', help_text: 'The starting IP address for the primary DHCP pool. This address must be less than or equal ' . 'to the `range_to` field.', ); @@ -89,10 +99,10 @@ class DHCPServer extends Model { default: '', allow_empty: true, maximum_length: 15, + verbose_name: 'Range To', internal_name: 'to', internal_namespace: 'range', validators: [new IPAddressValidator(allow_ipv4: true, allow_ipv6: false)], - verbose_name: 'Range To', help_text: 'The ending IP address for the primary DHCP pool. This address must be greater than or equal ' . 'to the `range_to` field.', ); @@ -107,8 +117,8 @@ class DHCPServer extends Model { default: '', allow_empty: true, maximum_length: 255, - validators: [new IPAddressValidator(allow_ipv4: true, allow_ipv6: true, allow_fqdn: true)], verbose_name: 'Failover Peer IP', + validators: [new IPAddressValidator(allow_ipv4: true, allow_ipv6: true, allow_fqdn: true)], help_text: 'The interface IP address of the other firewall (failover peer) in this subnet. Leave ' . 'empty to disable failover peering.', ); @@ -117,8 +127,8 @@ class DHCPServer extends Model { allow_empty: true, many: true, maximum_length: 17, - validators: [new MACAddressValidator()], verbose_name: 'MAC Allow', + validators: [new MACAddressValidator()], help_text: 'MAC addresses this DHCP server is allowed to provide leases for.', ); $this->mac_deny = new StringField( @@ -126,8 +136,8 @@ class DHCPServer extends Model { allow_empty: true, many: true, maximum_length: 17, - validators: [new MACAddressValidator()], verbose_name: 'MAC Deny', + validators: [new MACAddressValidator()], help_text: 'MAC addresses this DHCP server is not allowed to provide leases for.', ); $this->domainsearchlist = new StringField( @@ -136,8 +146,8 @@ class DHCPServer extends Model { many: true, maximum_length: 255, delimiter: ';', - validators: [new IPAddressValidator(allow_ipv4: false, allow_ipv6: false, allow_fqdn: true)], verbose_name: 'Domain Search List', + validators: [new IPAddressValidator(allow_ipv4: false, allow_ipv6: false, allow_fqdn: true)], help_text: 'The domain search list to provide via DHCP.', ); $this->defaultleasetime = new IntegerField( @@ -159,8 +169,8 @@ class DHCPServer extends Model { default: '', allow_empty: true, maximum_length: 15, - validators: [new IPAddressValidator(allow_ipv4: true, allow_ipv6: false, allow_keywords: ['none'])], verbose_name: 'Gateway', + validators: [new IPAddressValidator(allow_ipv4: true, allow_ipv6: false, allow_keywords: ['none'])], help_text: 'The gateway IPv4 address to provide via DHCP. This is only necessary if you are not using ' . "the interface's IP as the gateway. Specify `none` for no gateway assignment.", ); @@ -171,8 +181,8 @@ class DHCPServer extends Model { many_maximum: 4, maximum_length: 15, delimiter: null, - validators: [new IPAddressValidator(allow_ipv4: true, allow_ipv6: false)], verbose_name: 'DNS Servers', + validators: [new IPAddressValidator(allow_ipv4: true, allow_ipv6: false)], help_text: 'The DNS servers to provide via DHCP. Leave empty to default to system nameservers.', ); $this->winsserver = new StringField( @@ -182,8 +192,8 @@ class DHCPServer extends Model { many_maximum: 2, maximum_length: 15, delimiter: null, - validators: [new IPAddressValidator(allow_ipv4: true, allow_ipv6: false)], verbose_name: 'WINS Servers', + validators: [new IPAddressValidator(allow_ipv4: true, allow_ipv6: false)], help_text: 'The WINS servers to provide via DHCP.', ); $this->ntpserver = new StringField( @@ -193,8 +203,8 @@ class DHCPServer extends Model { many_maximum: 4, maximum_length: 256, delimiter: null, - validators: [new IPAddressValidator(allow_ipv4: true, allow_ipv6: false, allow_fqdn: true)], verbose_name: 'NTP Servers', + validators: [new IPAddressValidator(allow_ipv4: true, allow_ipv6: false, allow_fqdn: true)], help_text: 'The NTP servers to provide via DHCP.', ); $this->staticarp = new BooleanField( @@ -273,6 +283,69 @@ class DHCPServer extends Model { verbose_name: 'Static Mappings', help_text: 'Static mappings applied to this DHCP server.', ); + $this->netboot = new BooleanField( + default: false, + verbose_name: 'Enable Network Booting', + help_text: 'Enable network booting (PXE/TFTP/UEFI HTTP boot) options for this DHCP server.', + ); + $this->nextserver = new StringField( + default: '', + allow_empty: true, + verbose_name: 'Next Server', + conditions: ['netboot' => true], + validators: [new IPAddressValidator(allow_ipv4: true, allow_ipv6: false)], + help_text: 'The IPv4 address of the network boot server (e.g. TFTP server).', + ); + $this->filename = new StringField( + default: '', + allow_empty: true, + verbose_name: 'Default Bootfile Name', + conditions: ['netboot' => true], + help_text: 'The default bootfile name provided to BIOS/legacy PXE clients.', + ); + $this->filename32 = new StringField( + default: '', + allow_empty: true, + verbose_name: 'UEFI 32-bit Bootfile Name', + conditions: ['netboot' => true], + help_text: 'The bootfile name provided to 32-bit UEFI PXE clients.', + ); + $this->filename64 = new StringField( + default: '', + allow_empty: true, + verbose_name: 'UEFI 64-bit Bootfile Name', + conditions: ['netboot' => true], + help_text: 'The bootfile name provided to 64-bit UEFI PXE clients.', + ); + $this->filename32arm = new StringField( + default: '', + allow_empty: true, + verbose_name: 'UEFI 32-bit ARM Bootfile Name', + conditions: ['netboot' => true], + help_text: 'The bootfile name provided to 32-bit ARM UEFI PXE clients.', + ); + $this->filename64arm = new StringField( + default: '', + allow_empty: true, + verbose_name: 'UEFI 64-bit ARM Bootfile Name', + conditions: ['netboot' => true], + help_text: 'The bootfile name provided to 64-bit ARM UEFI PXE clients.', + ); + $this->uefihttpboot = new StringField( + default: '', + allow_empty: true, + verbose_name: 'UEFI HTTPBoot URL', + conditions: ['netboot' => true], + validators: [new URLValidator()], + help_text: 'The URL provided to UEFI HTTP boot clients.', + ); + $this->rootpath = new StringField( + default: '', + allow_empty: true, + verbose_name: 'Root Path', + conditions: ['netboot' => true], + help_text: 'The root path provided to network boot clients.', + ); parent::__construct($id, $parent_id, $data, ...$options); } diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/RESTAPIVersion.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/RESTAPIVersion.inc index b3934894..d603f232 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/RESTAPIVersion.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/RESTAPIVersion.inc @@ -127,7 +127,7 @@ class RESTAPIVersion extends Model { # Locate the version and format it to a standard semantic version format (x.x.x) $version = str_replace(' ', '', $pkg_line); $version = explode(':', $version)[1]; - $version = strlen($version) === 3 ? $version . '.0' : $version; + $version = substr_count($version, '.') === 1 ? $version . '.0' : $version; $version = str_replace('_', '.', $version); return "v$version"; } diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsCertificateAuthorityTestCase.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsCertificateAuthorityTestCase.inc index 699e3fa5..9149928b 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsCertificateAuthorityTestCase.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsCertificateAuthorityTestCase.inc @@ -98,37 +98,6 @@ R02Pul8ulWQ8Kl3Q3pou8As7W1mMzA2DxQ== ); } - /** - * Checks that the CA is found in the OS trust store when `trust` is enabled. - */ - public function test_ca_trust() { - # Create a CA to test with - $ca = new CertificateAuthority( - data: [ - 'descr' => 'test', - 'crt' => self::EXAMPLE_CRT, - 'prv' => self::EXAMPLE_PRV, - 'trust' => true, - ], - ); - $ca->create(); - - # Ensure the cert is in the trust store directory - $truststore_dir_ls = glob('/usr/local/etc/ssl/certs/*.crt'); - $this->assert_is_not_empty($truststore_dir_ls, message: 'Trust store directory should have one trusted CA!'); - - # Disable `trust` - $ca->trust->value = false; - $ca->update(); - - # Ensure the certificate is not found in the trust store - $truststore_dir_ls = glob('/usr/local/etc/ssl/certs/*.crt'); - $this->assert_is_empty($truststore_dir_ls, message: 'Trust store directory should have no trusted CAs!'); - - # Delete the CA - $ca->delete(); - } - /** * Checks that we cannot delete a CA that is in use. */ diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsDHCPServerTestCase.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsDHCPServerTestCase.inc index 3143d5d7..48eb6c05 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsDHCPServerTestCase.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsDHCPServerTestCase.inc @@ -6,6 +6,7 @@ use RESTAPI\Core\Command; use RESTAPI\Core\Model; use RESTAPI\Core\TestCase; use RESTAPI\Models\DHCPServer; +use RESTAPI\Models\DHCPServerBackend; use RESTAPI\Models\DHCPServerStaticMapping; use RESTAPI\Models\NetworkInterface; use RESTAPI\Models\VirtualIP; @@ -536,6 +537,122 @@ class APIModelsDHCPServerTestCase extends TestCase { $this->assert_is_false(array_key_exists('opt1', Model::get_config('dhcpd'))); } + /** + * Ensures the netboot fields are correctly written to the Kea DHCPv4 configuration after applying. + * This test only runs when Kea is the active DHCP backend (kea-dhcp4.conf exists). + */ + public function test_netboot_fields_written_to_kea_config(): void { + # Ensure kea is set as the DHCP backend + $backend = new DHCPServerBackend(dhcpbackend: 'kea', async: false); + $backend->update(apply: true); + + $dhcp_server = new DHCPServer(id: 'lan', async: false); + $dhcp_server->netboot->value = true; + $dhcp_server->nextserver->value = '1.2.3.4'; + $dhcp_server->filename->value = 'test.txt'; + $dhcp_server->filename32->value = '32.txt'; + $dhcp_server->filename64->value = '64.txt'; + $dhcp_server->filename32arm->value = 'arm32.txt'; + $dhcp_server->filename64arm->value = 'arm64.txt'; + $dhcp_server->uefihttpboot->value = 'https://example.com'; + $dhcp_server->rootpath->value = 'testroot'; + $dhcp_server->update(apply: true); + + $kea_conf = (new Command('cat /usr/local/etc/kea/kea-dhcp4.conf'))->output; + + # Ensure next-server is written + $this->assert_str_contains($kea_conf, '"next-server": "1.2.3.4"'); + + # Ensure root-path option-data is written + $this->assert_str_contains($kea_conf, '"root-path"'); + $this->assert_str_contains($kea_conf, '"data": "testroot"'); + + # Ensure UEFI HTTP boot client-class is written with the correct URL + $this->assert_str_contains($kea_conf, 'ipxe_uefihttp_'); + $this->assert_str_contains($kea_conf, '"data": "https://example.com"'); + + # Ensure 32-bit UEFI PXE client-class is written + $this->assert_str_contains($kea_conf, 'ipxe_32_'); + $this->assert_str_contains($kea_conf, '"data": "32.txt"'); + + # Ensure 64-bit UEFI PXE client-class is written + $this->assert_str_contains($kea_conf, 'ipxe_64_'); + $this->assert_str_contains($kea_conf, '"data": "64.txt"'); + + # Ensure 32-bit ARM UEFI PXE client-class is written + $this->assert_str_contains($kea_conf, 'ipxe_32arm_'); + $this->assert_str_contains($kea_conf, '"data": "arm32.txt"'); + + # Ensure 64-bit ARM UEFI PXE client-class is written + $this->assert_str_contains($kea_conf, 'ipxe_64arm_'); + $this->assert_str_contains($kea_conf, '"data": "arm64.txt"'); + + # Ensure legacy PXE client-class is written with the default filename + $this->assert_str_contains($kea_conf, 'ipxe_legacy_'); + $this->assert_str_contains($kea_conf, '"data": "test.txt"'); + + # Disable netboot and ensure the netboot-specific entries are removed + $dhcp_server->netboot->value = false; + $dhcp_server->update(apply: true); + + $kea_conf_after = (new Command('cat /usr/local/etc/kea/kea-dhcp4.conf'))->output; + $this->assert_str_does_not_contain($kea_conf_after, '"next-server"'); + $this->assert_str_does_not_contain($kea_conf_after, 'ipxe_uefihttp_'); + $this->assert_str_does_not_contain($kea_conf_after, 'ipxe_legacy_'); + + # Revert dhcp backend + $backend->dhcpbackend->value = 'isc'; + $backend->update(apply: true); + } + + /** + * Ensures that netboot sub-fields are not validated when `netboot` is false. + */ + public function test_netboot_subfields_not_required_without_netboot(): void { + $this->assert_does_not_throw( + callable: function (): void { + $dhcp_server = new DHCPServer(id: 'lan', async: false); + $dhcp_server->netboot->value = false; + # nextserver requires a valid IPv4 when netboot is true; it should be silently ignored when false + $dhcp_server->uefihttpboot->value = ''; + $dhcp_server->nextserver->value = ''; + $dhcp_server->update(); + }, + ); + } + + /** + * Ensures that `nextserver` must be a valid IPv4 address when `netboot` is enabled. + */ + public function test_nextserver_must_be_valid_ipv4(): void { + $this->assert_throws_response( + response_id: 'IP_ADDRESS_VALIDATOR_FAILED', + code: 400, + callable: function (): void { + $dhcp_server = new DHCPServer(id: 'lan', async: false); + $dhcp_server->netboot->value = true; + $dhcp_server->nextserver->value = 'not an ip'; + $dhcp_server->validate(); + }, + ); + } + + /** + * Ensures that `uefihttpboot` must be a valid URL when `netboot` is enabled. + */ + public function test_uefihttpboot_must_be_valid_url(): void { + $this->assert_throws_response( + response_id: 'URL_VALIDATOR_FAILED', + code: 400, + callable: function (): void { + $dhcp_server = new DHCPServer(id: 'lan', async: false); + $dhcp_server->netboot->value = true; + $dhcp_server->uefihttpboot->value = 'not a url %%'; + $dhcp_server->validate(); + }, + ); + } + /** * Ensures DHCP servers can be newly created and deleted for new interfaces. */ diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsFirewallAdvancedSettingsTestCase.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsFirewallAdvancedSettingsTestCase.inc index 53cec42c..6a635153 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsFirewallAdvancedSettingsTestCase.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsFirewallAdvancedSettingsTestCase.inc @@ -21,13 +21,13 @@ class APIModelsFirewallAdvancedSettingsTestCase extends TestCase { # Update the aliasesresolveinterval value and check that the filterdns service uses the correct interval $firewall_advanced_settings = new FirewallAdvancedSettings(aliasesresolveinterval: 500, async: true); $firewall_advanced_settings->update(apply: true); - sleep(3); + sleep(5); $filterdns_ps = new Command('ps aux'); $this->assert_str_contains($filterdns_ps->output, '/usr/local/sbin/filterdns -p /var/run/filterdns.pid -i 500'); $firewall_advanced_settings = new FirewallAdvancedSettings(aliasesresolveinterval: 222, async: true); $firewall_advanced_settings->update(apply: true); - sleep(3); + sleep(5); $filterdns_ps = new Command('ps aux'); $this->assert_str_contains($filterdns_ps->output, '/usr/local/sbin/filterdns -p /var/run/filterdns.pid -i 222'); diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsFirewallRuleTestCase.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsFirewallRuleTestCase.inc index 4598f34e..214b7f13 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsFirewallRuleTestCase.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsFirewallRuleTestCase.inc @@ -189,7 +189,7 @@ class APIModelsFirewallRuleTestCase extends TestCase { $rid = $rule->tracker->value; $pfctl_rule_created = "$type in quick on $if $iptype proto $proto from $src port $srcport to $dst port " . - "$dstport ridentifier $rid flags S/SA keep state label \"USER_RULE: $descr\" label \"id:$rid\""; + "$dstport ridentifier $rid flags S/SA keep state"; $this->assert_str_contains($pfctl_rules, $pfctl_rule_created); # Update the firewall rule object with new values @@ -222,7 +222,7 @@ class APIModelsFirewallRuleTestCase extends TestCase { $rid = $rule->tracker->value; $pfctl_rule_updated = "$type in quick on $if $iptype proto $proto from $src port $srcport to $dst port " . - "$dstport ridentifier $rid label \"USER_RULE: $descr\" label \"id:$rid\""; + "$dstport ridentifier $rid"; $this->assert_str_does_not_contain($pfctl_rules, $pfctl_rule_created); $this->assert_str_contains($pfctl_rules, $pfctl_rule_updated); @@ -270,7 +270,7 @@ class APIModelsFirewallRuleTestCase extends TestCase { $dst = $rule->destination->value; $rid = $rule->tracker->value; $gw = $rule->gateway->value; - $pfctl_rule_created = "pass in quick on $if \$GW$gw $iptype from $src to $dst ridentifier $rid keep state label \"USER_RULE\" label \"id:$rid\" label \"gw:$gw\""; + $pfctl_rule_created = "pass in quick on $if \$GW$gw $iptype from $src to $dst ridentifier $rid keep state"; $this->assert_str_contains($pfctl_rules, $pfctl_rule_created); # Delete the firewall rule and gateway @@ -515,7 +515,7 @@ class APIModelsFirewallRuleTestCase extends TestCase { # Ensure the schedule is found tied to the rule in pfctl $pfctl = file_get_contents('/tmp/rules.debug'); - $this->assert_str_contains($pfctl, "s:{$sched->schedlabel->value}"); + $this->assert_str_contains($pfctl, $sched->schedlabel->value); # Update the schedule so it is inactive and ensure the rule is no longer present in pfctl $sched->timerange->value[0]['day'] = [$test_day]; @@ -527,7 +527,7 @@ class APIModelsFirewallRuleTestCase extends TestCase { $rule->sched->value = null; $rule->update(apply: true); $pfctl = file_get_contents('/tmp/rules.debug'); - $this->assert_str_contains($pfctl, "id:{$rule->tracker->value}"); + $this->assert_str_contains($pfctl, $rule->tracker->value); $this->assert_str_does_not_contain($pfctl, "s:{$sched->schedlabel->value}"); # Delete the rule and schedule