From 55d82e1d9c29e98e8c6f90921a7d823d29d97c26 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Thu, 2 Apr 2026 15:00:25 -0600 Subject: [PATCH 01/11] fix(CertificateAuthority): add missing 'caref' field #873 This commit fixes an issue where the object relation system expected a 'caref' value to determine which CAs would impacted by deletions. However, since this model did not have this field it was simply ignored and considered all CAs as impacted by deletions. --- .../local/pkg/RESTAPI/Models/CertificateAuthority.inc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc index 0f121969..b7decc77 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc @@ -5,6 +5,7 @@ namespace RESTAPI\Models; use RESTAPI\Core\Model; use RESTAPI\Fields\Base64Field; use RESTAPI\Fields\BooleanField; +use RESTAPI\Fields\ForeignModelField; use RESTAPI\Fields\IntegerField; use RESTAPI\Fields\StringField; use RESTAPI\Fields\UIDField; @@ -20,6 +21,7 @@ use RESTAPI\Validators\X509Validator; class CertificateAuthority extends Model { public StringField $descr; public UIDField $refid; + public ForeignModelField $caref; public BooleanField $trust; public BooleanField $randomserial; public IntegerField $serial; @@ -42,6 +44,13 @@ class CertificateAuthority extends Model { help_text: 'The unique ID assigned to this certificate authority for internal system use. This value is ' . 'generated by this system and cannot be changed.', ); + $this->caref = new ForeignModelField( + model_name: 'CertificateAuthority', + model_field: 'refid', + allow_null: true, + read_only: true, + help_text: 'The reference ID of the assigned root certificate authority.', + ); $this->trust = new BooleanField( default: false, indicates_true: 'enabled', From 7cbd075ac50ddc6002fbf16d5c830b177f46d139 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Thu, 2 Apr 2026 15:00:51 -0600 Subject: [PATCH 02/11] fix(CertificateAuthority): don't delete intermediate ca when root ca is deleted #873 This behavior no longer matches the behavior of the webConfigurator and should be removed. --- .../usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc index b7decc77..b062be90 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc @@ -144,12 +144,6 @@ class CertificateAuthority extends Model { $this->del_config("crl/$crl->id"); } - # Delete an intermediate CAs signed by this CA - $ca_q = CertificateAuthority::query(reverse: true, caref: $this->refid->value, id__except: $this->id); - foreach ($ca_q->model_objects as $ca) { - $this->del_config("ca/$ca->id"); - } - parent::_delete(); } From 30aac210fa6f7d854e2dcca815669efaa20f2864 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Thu, 2 Apr 2026 15:01:13 -0600 Subject: [PATCH 03/11] test(CertificateAuthority): ensure only target ca is deleted #873 --- .../APIModelsCertificateAuthorityTestCase.inc | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) 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 c0436596..5ec6ffe9 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 @@ -6,6 +6,7 @@ use RESTAPI\Core\Command; use RESTAPI\Core\Model; use RESTAPI\Core\TestCase; use RESTAPI\Models\CertificateAuthority; +use RESTAPI\Models\CertificateAuthorityGenerate; class APIModelsCertificateAuthorityTestCase extends TestCase { const EXAMPLE_CRT = "-----BEGIN CERTIFICATE----- @@ -148,5 +149,23 @@ R02Pul8ulWQ8Kl3Q3pou8As7W1mMzA2DxQ== }, ); } - # TODO: Need test to ensure crt must be CA capable + + /** + * Ensures that only the targeted CA is deleted when a specific CA deletion is requested. Regression test for #873. + */ + public function test_multi_ca_deletion(): void { + # Create 3 CAs for testing + $ca1 = new CertificateAuthorityGenerate(descr: 'ca1', keytype: "RSA", keylen: 2048); + $ca1->create(); + $ca2 = new CertificateAuthorityGenerate(descr: 'ca2', keytype: "RSA", keylen: 2048); + $ca2->create(); + $ca3 = new CertificateAuthorityGenerate(descr: 'ca3', keytype: "RSA", keylen: 2048); + $ca3->create(); + + # Delete CA 2 and ensure CA 1 and CA 3 still exist + CertificateAuthority::delete_many(id: $ca2->id); + $this->assert_is_true(CertificateAuthority::query(descr: $ca1->descr->value)->exists()); + $this->assert_is_false(CertificateAuthority::query(descr: $ca2->descr->value)->exists()); + $this->assert_is_true(CertificateAuthority::query(descr: $ca3->descr->value)->exists()); + } } From 4a1b3ead7f11e119738aaeb1d8fc1e90a5be18fd Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Thu, 2 Apr 2026 15:05:27 -0600 Subject: [PATCH 04/11] chore(deps-dev): run npm audit fix --- package-lock.json | 102 +++++++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 46 deletions(-) diff --git a/package-lock.json b/package-lock.json index e21ff0b0..a8730200 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,10 @@ { - "name": "pfSense-pkg-RESTAPI", + "name": "pfsense-api", "lockfileVersion": 3, "requires": true, "packages": { "": { + "name": "pfsense-api", "devDependencies": { "@prettier/plugin-php": "^0.24.0", "@stoplight/spectral-cli": "^6.15.0", @@ -11,10 +12,11 @@ } }, "node_modules/@asyncapi/specs": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-4.3.1.tgz", - "integrity": "sha512-EfexhJu/lwF8OdQDm28NKLJHFkx0Gb6O+rcezhZYLPIoNYKXJMh2J1vFGpwmfAcTTh+ffK44Oc2Hs1Q4sLBp+A==", + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-6.11.1.tgz", + "integrity": "sha512-A3WBLqAKGoJ2+6FWFtpjBlCQ1oFCcs4GxF7zsIGvNqp/klGUHjlA3aAcZ9XMMpLGE8zPeYDz2x9FmO6DSuKraQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.11" } @@ -274,9 +276,9 @@ } }, "node_modules/@stoplight/spectral-core": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.19.5.tgz", - "integrity": "sha512-i+njdliW7bAHGsHEgDvH0To/9IxiYiBELltkZ7ASVy4i+WXtZ40lQXpeRQRwePrBcSgQl0gcZFuKX10nmSHtbw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.21.0.tgz", + "integrity": "sha512-oj4e/FrDLUhBRocIW+lRMKlJ/q/rDZw61HkLbTFsdMd+f/FTkli2xHNB1YC6n1mrMKjjvy7XlUuFkC7XxtgbWw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -294,7 +296,7 @@ "ajv-formats": "~2.1.1", "es-aggregate-error": "^1.0.7", "jsonpath-plus": "^10.3.0", - "lodash": "~4.17.21", + "lodash": "~4.17.23", "lodash.topath": "^4.5.2", "minimatch": "3.1.2", "nimma": "0.2.3", @@ -335,10 +337,11 @@ } }, "node_modules/@stoplight/spectral-formatters": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-formatters/-/spectral-formatters-1.4.3.tgz", - "integrity": "sha512-03Nc6nhjMO9aHhJPgBH4zDwMPklKLWEMtvx+PMmzfStCndMjJkf8ki7O/55u3myZ1TwxBzln9z9tXPLSL3KKhw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-formatters/-/spectral-formatters-1.5.0.tgz", + "integrity": "sha512-lR7s41Z00Mf8TdXBBZQ3oi2uR8wqAtR6NO0KA8Ltk4FSpmAy0i6CKUmJG9hZQjanTnGmwpQkT/WP66p1GY3iXA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@stoplight/path": "^1.3.2", "@stoplight/spectral-core": "^1.19.4", @@ -359,10 +362,11 @@ } }, "node_modules/@stoplight/spectral-functions": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-functions/-/spectral-functions-1.9.3.tgz", - "integrity": "sha512-jy4mguk0Ddz0Vr76PHervOZeyXTUW650zVfNT2Vt9Ji3SqtTVziHjq913CBVEGFS+IQw1McUXuHVLM6YKVZ6fQ==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-functions/-/spectral-functions-1.10.1.tgz", + "integrity": "sha512-obu8ZfoHxELOapfGsCJixKZXZcffjg+lSoNuttpmUFuDzVLT3VmH8QkPXfOGOL5Pz80BR35ClNAToDkdnYIURg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@stoplight/better-ajv-errors": "1.0.3", "@stoplight/json": "^3.17.1", @@ -372,7 +376,7 @@ "ajv": "^8.17.1", "ajv-draft-04": "~1.0.0", "ajv-errors": "~3.0.0", - "ajv-formats": "~2.1.0", + "ajv-formats": "~2.1.1", "lodash": "~4.17.21", "tslib": "^2.8.1" }, @@ -425,37 +429,39 @@ } }, "node_modules/@stoplight/spectral-ruleset-bundler": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-bundler/-/spectral-ruleset-bundler-1.6.0.tgz", - "integrity": "sha512-8CU7e4aEGdfU9ncVDtlnJSawg/6epzAHrQTjuNu1QfKAOoiwyG7oUk2XUTHWcvq6Q67iUctb0vjOokR+MPVg0Q==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-bundler/-/spectral-ruleset-bundler-1.6.3.tgz", + "integrity": "sha512-AQFRO6OCKg8SZJUupnr3+OzI1LrMieDTEUHsYgmaRpNiDRPvzImE3bzM1KyQg99q58kTQyZ8kpr7sG8Lp94RRA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@rollup/plugin-commonjs": "~22.0.2", "@stoplight/path": "1.3.2", "@stoplight/spectral-core": ">=1", - "@stoplight/spectral-formats": "^1.7.0", + "@stoplight/spectral-formats": "^1.8.1", "@stoplight/spectral-functions": ">=1", "@stoplight/spectral-parsers": ">=1", "@stoplight/spectral-ref-resolver": "^1.0.4", "@stoplight/spectral-ruleset-migrator": "^1.9.6", "@stoplight/spectral-rulesets": ">=1", - "@stoplight/spectral-runtime": "^1.1.0", + "@stoplight/spectral-runtime": "^1.1.2", "@stoplight/types": "^13.6.0", "@types/node": "*", "pony-cause": "1.1.1", - "rollup": "~2.79.0", - "tslib": "^2.3.1", + "rollup": "~2.79.2", + "tslib": "^2.8.1", "validate-npm-package-name": "3.0.0" }, "engines": { - "node": "^12.20 || >= 14.13" + "node": "^16.20 || ^18.18 || >= 20.17" } }, "node_modules/@stoplight/spectral-ruleset-migrator": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-migrator/-/spectral-ruleset-migrator-1.11.1.tgz", - "integrity": "sha512-z2A1Ual3bU7zLDxYqdHaxYgyirb7TVDaWXc9ONEBAo5W1isio0EHV59ujAUEOUHCLcY5ubd0eYeqgSjqPIQe8w==", + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-migrator/-/spectral-ruleset-migrator-1.11.3.tgz", + "integrity": "sha512-+9Y1zFxYmSsneT5FPkgS1IlRQs0VgtdMT77f5xf6vzje9ezyhfs7oXwbZOCSZjEJew8iVZBKQtiOFndcBrdtqg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@stoplight/json": "~3.21.0", "@stoplight/ordered-object-literal": "~1.0.4", @@ -498,29 +504,30 @@ "dev": true }, "node_modules/@stoplight/spectral-rulesets": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-rulesets/-/spectral-rulesets-1.20.2.tgz", - "integrity": "sha512-7Y8orZuNyGyeHr9n50rMfysgUJ+/zzIEHMptt66jiy82GUWl+0nr865DkMuXdC5GryfDYhtjoRTUCVsXu80Nkg==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-rulesets/-/spectral-rulesets-1.22.0.tgz", + "integrity": "sha512-l2EY2jiKKLsvnPfGy+pXC0LeGsbJzcQP5G/AojHgf+cwN//VYxW1Wvv4WKFx/CLmLxc42mJYF2juwWofjWYNIQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@asyncapi/specs": "^4.1.0", + "@asyncapi/specs": "^6.8.0", "@stoplight/better-ajv-errors": "1.0.3", "@stoplight/json": "^3.17.0", - "@stoplight/spectral-core": "^1.8.1", - "@stoplight/spectral-formats": "^1.7.0", - "@stoplight/spectral-functions": "^1.5.1", - "@stoplight/spectral-runtime": "^1.1.1", + "@stoplight/spectral-core": "^1.19.4", + "@stoplight/spectral-formats": "^1.8.1", + "@stoplight/spectral-functions": "^1.9.1", + "@stoplight/spectral-runtime": "^1.1.2", "@stoplight/types": "^13.6.0", "@types/json-schema": "^7.0.7", "ajv": "^8.17.1", - "ajv-formats": "~2.1.0", + "ajv-formats": "~2.1.1", "json-schema-traverse": "^1.0.0", "leven": "3.1.0", "lodash": "~4.17.21", - "tslib": "^2.3.0" + "tslib": "^2.8.1" }, "engines": { - "node": ">=12" + "node": "^16.20 || ^18.18 || >= 20.17" } }, "node_modules/@stoplight/spectral-runtime": { @@ -662,10 +669,11 @@ } }, "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -831,10 +839,11 @@ "dev": true }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1982,10 +1991,11 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" From bb1383b11198ab8d5b043f128308e680f9c9b1bd Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Thu, 2 Apr 2026 15:05:50 -0600 Subject: [PATCH 05/11] style: run prettier on changed files --- .../RESTAPI/Tests/APIModelsCertificateAuthorityTestCase.inc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 5ec6ffe9..b8d95035 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 @@ -155,11 +155,11 @@ R02Pul8ulWQ8Kl3Q3pou8As7W1mMzA2DxQ== */ public function test_multi_ca_deletion(): void { # Create 3 CAs for testing - $ca1 = new CertificateAuthorityGenerate(descr: 'ca1', keytype: "RSA", keylen: 2048); + $ca1 = new CertificateAuthorityGenerate(descr: 'ca1', keytype: 'RSA', keylen: 2048); $ca1->create(); - $ca2 = new CertificateAuthorityGenerate(descr: 'ca2', keytype: "RSA", keylen: 2048); + $ca2 = new CertificateAuthorityGenerate(descr: 'ca2', keytype: 'RSA', keylen: 2048); $ca2->create(); - $ca3 = new CertificateAuthorityGenerate(descr: 'ca3', keytype: "RSA", keylen: 2048); + $ca3 = new CertificateAuthorityGenerate(descr: 'ca3', keytype: 'RSA', keylen: 2048); $ca3->create(); # Delete CA 2 and ensure CA 1 and CA 3 still exist From 627520af5874957de1ace9cf99ba7e05c7c0751a Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Thu, 2 Apr 2026 15:06:53 -0600 Subject: [PATCH 06/11] build: build and release for pfSense Plus 26.03 --- .github/workflows/release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3506c55f..b612b428 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,6 +40,8 @@ jobs: PFSENSE_VERSION: "25.11" - FREEBSD_VERSION: FreeBSD-16.0-CURRENT PFSENSE_VERSION: "25.11.1" + - FREEBSD_VERSION: FreeBSD-16.0-CURRENT + PFSENSE_VERSION: "26.03" steps: - uses: actions/checkout@v6 From e289024ab99b7108ed0b9a79b601a10bed0c257a Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Thu, 2 Apr 2026 15:41:40 -0600 Subject: [PATCH 07/11] ci: sha-pin all actions --- .github/workflows/build.yml | 20 +++++++++---------- .github/workflows/quality.yml | 18 ++++++++--------- .github/workflows/release.yml | 28 +++++++++++++-------------- .github/workflows/schedule_weekly.yml | 2 +- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d52d13ea..b66b3eb8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,7 @@ jobs: FREEBSD_ID: freebsd16 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup FreeBSD build VM run: | /usr/local/bin/VBoxManage controlvm ${{ matrix.FREEBSD_VERSION }} poweroff || true @@ -46,7 +46,7 @@ jobs: /usr/local/bin/VBoxManage controlvm ${{ matrix.FREEBSD_VERSION }} poweroff || true /usr/local/bin/VBoxManage snapshot ${{matrix.FREEBSD_VERSION}} restore initial - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: pfSense-pkg-RESTAPI-${{ env.BUILD_VERSION }}-${{ matrix.FREEBSD_ID }}.pkg path: pfSense-pkg-RESTAPI-${{ env.BUILD_VERSION }}-${{ matrix.FREEBSD_ID }}.pkg @@ -62,8 +62,8 @@ jobs: - PFSENSE_VERSION: pfSense-2.8.1-RELEASE FREEBSD_ID: freebsd15 steps: - - uses: actions/checkout@v6 - - uses: actions/download-artifact@v8 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: pfSense-pkg-RESTAPI-${{ env.BUILD_VERSION }}-${{ matrix.FREEBSD_ID }}.pkg path: pfSense-pkg-RESTAPI-${{ env.BUILD_VERSION }}-${{ matrix.FREEBSD_ID }}.pkg @@ -96,7 +96,7 @@ jobs: /usr/local/bin/VBoxManage controlvm ${{ matrix.PFSENSE_VERSION }} poweroff || true /usr/local/bin/VBoxManage snapshot ${{ matrix.PFSENSE_VERSION }} restore initial - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: openapi-${{ matrix.PFSENSE_VERSION }}.json path: openapi-${{ matrix.PFSENSE_VERSION }}.json @@ -112,14 +112,14 @@ jobs: - PFSENSE_VERSION: pfSense-2.8.1-RELEASE FREEBSD_ID: freebsd15 steps: - - uses: actions/checkout@v6 - - uses: actions/download-artifact@v8 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: openapi-${{ matrix.PFSENSE_VERSION }}.json path: openapi-${{ matrix.PFSENSE_VERSION }}.json - name: Install Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: node-version: "20" @@ -142,9 +142,9 @@ jobs: FREEBSD_ID: freebsd15 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/download-artifact@v8 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: pfSense-pkg-RESTAPI-${{ env.BUILD_VERSION }}-${{ matrix.FREEBSD_ID }}.pkg path: pfSense-pkg-RESTAPI-${{ env.BUILD_VERSION }}-${{ matrix.FREEBSD_ID }}.pkg diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 2f0644ce..c2450ab3 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -5,8 +5,8 @@ jobs: check_prettier: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: node-version: 20 - name: Install npm packages @@ -17,8 +17,8 @@ jobs: check_black: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: psf/black@stable + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: psf/black@c6755bb741b6481d6b3d3bb563c83fa060db96c9 # 26.3.1 lint_php: runs-on: ubuntu-latest @@ -27,9 +27,9 @@ jobs: matrix: PHP_VERSION: ["8.2"] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: "Setup PHP ${{ matrix.PHP_VERSION }}" - uses: shivammathur/setup-php@v2 + uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 with: php-version: "${{ matrix.PHP_VERSION }}" coverage: "none" @@ -46,9 +46,9 @@ jobs: matrix: PYTHON_VERSION: ["3.10", "3.11"] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Python ${{ matrix.PYTHON_VERSION }} - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.PYTHON_VERSION }} - name: Install dependencies @@ -62,7 +62,7 @@ jobs: runs-on: ubuntu-latest needs: ["lint_php"] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Check phpdoc build run: | wget https://phpdoc.org/phpDocumentor.phar -O phpdoc diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b612b428..47e0b6c0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,7 +44,7 @@ jobs: PFSENSE_VERSION: "26.03" steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup FreeBSD build VM run: | @@ -64,13 +64,13 @@ jobs: /usr/local/bin/VBoxManage controlvm ${{ matrix.FREEBSD_VERSION }} poweroff || true /usr/local/bin/VBoxManage snapshot ${{matrix.FREEBSD_VERSION}} restore initial - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: pfSense-${{ matrix.PFSENSE_VERSION }}-pkg-RESTAPI.pkg path: pfSense-${{ matrix.PFSENSE_VERSION }}-pkg-RESTAPI.pkg - name: Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1 with: files: pfSense-${{ matrix.PFSENSE_VERSION }}-pkg-RESTAPI.pkg @@ -78,9 +78,9 @@ jobs: runs-on: self-hosted needs: [release_pkg] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/download-artifact@v8 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: pfSense-${{ env.DEFAULT_PFSENSE_VERSION }}-pkg-RESTAPI.pkg path: pfSense-${{ env.DEFAULT_PFSENSE_VERSION }}-pkg-RESTAPI.pkg @@ -116,13 +116,13 @@ jobs: /usr/local/bin/VBoxManage snapshot pfSense-${{ env.DEFAULT_PFSENSE_VERSION }}-RELEASE restore initial - name: Upload OpenAPI schema - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: openapi.json path: openapi.json - name: Upload GraphQL schema - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: schema.graphql path: schema.graphql @@ -135,16 +135,16 @@ jobs: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Pages - uses: actions/configure-pages@v5.0.0 + uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 - name: Make website directory run: mkdir ./www - name: Setup python - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ env.PYTHON_VERSION }} @@ -155,13 +155,13 @@ jobs: mv ./site/* ./www/ - name: Download OpenAPI schema - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: openapi.json path: openapi.json - name: Download GraphQL schema - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: schema.graphql path: schema.graphql @@ -207,10 +207,10 @@ jobs: mv ./.phpdoc/build/* ./www/php-docs/ - name: Upload artifact - uses: actions/upload-pages-artifact@v4.0.0 + uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4.0.0 with: path: "./www" - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4.0.5 + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 diff --git a/.github/workflows/schedule_weekly.yml b/.github/workflows/schedule_weekly.yml index 22d277bc..4e643a72 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@v10 + - uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.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 e60a3a41efd530dc9041a183d1a95a08f62c3e20 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Thu, 2 Apr 2026 19:01:03 -0600 Subject: [PATCH 08/11] docs: update supported versions --- docs/INSTALL_AND_CONFIG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/INSTALL_AND_CONFIG.md b/docs/INSTALL_AND_CONFIG.md index 4451ff5e..31ef2f4e 100644 --- a/docs/INSTALL_AND_CONFIG.md +++ b/docs/INSTALL_AND_CONFIG.md @@ -21,6 +21,7 @@ run pfSense. It's recommended to follow Netgate's [minimum hardware requirements - pfSense Plus 25.07.1 - pfSense Plus 25.11 - pfSense Plus 25.11.1 +- pfSense Plus 26.03 !!! Warning Installation of the package on unsupported versions of pfSense may result in unexpected behavior and/or system instability. From 0dfe719f3efa446427ca5f0a245e19e78aded7bc Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Thu, 2 Apr 2026 19:55:44 -0600 Subject: [PATCH 09/11] refactor(CertificateAuthority): make caref a StringField Avoids infinite recursion trying to relate objects to themselves. --- .../usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc index b062be90..341d43ee 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc @@ -21,7 +21,7 @@ use RESTAPI\Validators\X509Validator; class CertificateAuthority extends Model { public StringField $descr; public UIDField $refid; - public ForeignModelField $caref; + public StringField $caref; public BooleanField $trust; public BooleanField $randomserial; public IntegerField $serial; @@ -44,9 +44,7 @@ class CertificateAuthority extends Model { help_text: 'The unique ID assigned to this certificate authority for internal system use. This value is ' . 'generated by this system and cannot be changed.', ); - $this->caref = new ForeignModelField( - model_name: 'CertificateAuthority', - model_field: 'refid', + $this->caref = new StringField( allow_null: true, read_only: true, help_text: 'The reference ID of the assigned root certificate authority.', From cf3b6d783c972f7ae6d613034fcb9b18e1760c62 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Thu, 2 Apr 2026 21:50:52 -0600 Subject: [PATCH 10/11] test(CertificateAuthority): ensure digest_alg is set for test CAs --- .../RESTAPI/Tests/APIModelsCertificateAuthorityTestCase.inc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 b8d95035..f579a870 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 @@ -155,11 +155,11 @@ R02Pul8ulWQ8Kl3Q3pou8As7W1mMzA2DxQ== */ public function test_multi_ca_deletion(): void { # Create 3 CAs for testing - $ca1 = new CertificateAuthorityGenerate(descr: 'ca1', keytype: 'RSA', keylen: 2048); + $ca1 = new CertificateAuthorityGenerate(descr: 'ca1', keytype: 'RSA', keylen: 2048, digest_alg: 'sha256'); $ca1->create(); - $ca2 = new CertificateAuthorityGenerate(descr: 'ca2', keytype: 'RSA', keylen: 2048); + $ca2 = new CertificateAuthorityGenerate(descr: 'ca2', keytype: 'RSA', keylen: 2048, digest_alg: 'sha256'); $ca2->create(); - $ca3 = new CertificateAuthorityGenerate(descr: 'ca3', keytype: 'RSA', keylen: 2048); + $ca3 = new CertificateAuthorityGenerate(descr: 'ca3', keytype: 'RSA', keylen: 2048, digest_alg: 'sha256'); $ca3->create(); # Delete CA 2 and ensure CA 1 and CA 3 still exist From 69e6f502b1065d3db2361fb3d170aa0e24549c6e Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Fri, 3 Apr 2026 10:17:43 -0600 Subject: [PATCH 11/11] test(CertificateAuthority): use full ca generate configs --- .../APIModelsCertificateAuthorityTestCase.inc | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) 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 f579a870..699e3fa5 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 @@ -155,11 +155,53 @@ R02Pul8ulWQ8Kl3Q3pou8As7W1mMzA2DxQ== */ public function test_multi_ca_deletion(): void { # Create 3 CAs for testing - $ca1 = new CertificateAuthorityGenerate(descr: 'ca1', keytype: 'RSA', keylen: 2048, digest_alg: 'sha256'); + $ca1 = new CertificateAuthorityGenerate( + descr: 'ca1', + trust: true, + randomserial: true, + is_intermediate: false, + keytype: 'RSA', + keylen: 2048, + digest_alg: 'sha256', + lifetime: 3650, + dn_country: 'US', + dn_state: 'UT', + dn_city: 'Salt Lake City', + dn_organization: 'ACME Org', + dn_organizationalunit: 'IT', + ); $ca1->create(); - $ca2 = new CertificateAuthorityGenerate(descr: 'ca2', keytype: 'RSA', keylen: 2048, digest_alg: 'sha256'); + $ca2 = new CertificateAuthorityGenerate( + descr: 'ca2', + trust: true, + randomserial: true, + is_intermediate: false, + keytype: 'RSA', + keylen: 2048, + digest_alg: 'sha256', + lifetime: 3650, + dn_country: 'US', + dn_state: 'UT', + dn_city: 'Salt Lake City', + dn_organization: 'ACME Org', + dn_organizationalunit: 'IT', + ); $ca2->create(); - $ca3 = new CertificateAuthorityGenerate(descr: 'ca3', keytype: 'RSA', keylen: 2048, digest_alg: 'sha256'); + $ca3 = new CertificateAuthorityGenerate( + descr: 'ca3', + trust: true, + randomserial: true, + is_intermediate: false, + keytype: 'RSA', + keylen: 2048, + digest_alg: 'sha256', + lifetime: 3650, + dn_country: 'US', + dn_state: 'UT', + dn_city: 'Salt Lake City', + dn_organization: 'ACME Org', + dn_organizationalunit: 'IT', + ); $ca3->create(); # Delete CA 2 and ensure CA 1 and CA 3 still exist