Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
b32d590
fix: re-enable pf when boot leaves it disabled
thedancingdeveloper Jul 21, 2026
ab63ab3
fix: allow isolated static WAN seeds
thedancingdeveloper Jul 21, 2026
9dc1d44
test: extend FreeBSD packet and API coverage
thedancingdeveloper Jul 21, 2026
2d336e6
test: run ICMP checks inside the client jail
thedancingdeveloper Jul 21, 2026
a62c31e
test: assert the about memory object shape
thedancingdeveloper Jul 21, 2026
97890d9
test: strengthen appliance boot smoke assertions
thedancingdeveloper Jul 21, 2026
4933f4d
test: mark UDP delivery only after payload receipt
thedancingdeveloper Jul 21, 2026
a2ba98d
test: verify PF and rule persistence across reboot
thedancingdeveloper Jul 21, 2026
68371d7
feat: pre-validate target config before destructive restore steps (#535)
mack42 Jul 21, 2026
2492886
feat: single DB transaction for config restore (#158, #535)
mack42 Jul 21, 2026
02db98f
feat: post-apply verification of DB and pf state after restore (#535)
mack42 Jul 21, 2026
d539eff
fix: commit-confirm cannot arm without a valid rollback target (#535)
mack42 Jul 21, 2026
b226da0
test: failure injection at every restore apply stage (#535)
mack42 Jul 21, 2026
cba6d56
docs: backup/restore atomicity model — validation, single DB transact…
mack42 Jul 21, 2026
8a5c274
fix: verify_applied must not string-compare rules against real pfctl …
mack42 Jul 21, 2026
1f93f71
Merge pull request #579 from ZerosAndOnesLLC/fix/535-restore-hardening
mack42 Jul 21, 2026
4353b49
feat: use dummynet FQ-CoDel for traffic shaping (#532)
mack42 Jul 19, 2026
4945440
fix: satisfy strict clippy in shaping backend
mack42 Jul 19, 2026
08d0da3
fix: clean dummynet cfg clippy branch
mack42 Jul 19, 2026
30cd906
feat(release): sign and attest update artifacts
mack42 Jul 19, 2026
a245ad8
Merge pull request #577 from thedancingdeveloper/fix/static-wan-optio…
mack42 Jul 22, 2026
5faa23c
feat: complete FQ-CoDel lifecycle and FreeBSD qualification
thedancingdeveloper Jul 22, 2026
7cd3e51
feat: enforce signed release verification end to end
thedancingdeveloper Jul 22, 2026
58cf526
style: move pf_reconcile_tests to end of file (clippy items_after_tes…
mack42 Jul 22, 2026
b917a74
Merge pull request #575 from thedancingdeveloper/fix/pf-disabled-boot…
mack42 Jul 22, 2026
2b08ebf
fix: smoke-boot seed must use key_only for ssh_auth_method
mack42 Jul 22, 2026
78a11a7
merge: rebase CoDel implementation onto upstream main
thedancingdeveloper Jul 22, 2026
719d033
chore: ignore local review status ledger
thedancingdeveloper Jul 22, 2026
a964737
Merge pull request #576 from thedancingdeveloper/test/freebsd-enhance…
mack42 Jul 22, 2026
c65aa37
fix: compile in the update-signing key, sign local releases, self-hea…
mack42 Jul 22, 2026
c5a5d16
Merge pull request #581 from thedancingdeveloper/feat/542-supply-chain
mack42 Jul 22, 2026
e1151d4
feat(vpn): dual-stack WireGuard tunnel addresses (#471 phase 1)
mack42 Jul 22, 2026
da9f07b
feat(vpn): IPv6-aware peer auto-IP assignment (#471 phase 2)
mack42 Jul 22, 2026
c9cec97
feat(vpn): NAT66 egress for IPv6 tunnel subnets (#471 phase 3)
mack42 Jul 22, 2026
73cecf4
feat(vpn): dual-stack client config generation (#471 phase 4)
mack42 Jul 22, 2026
59519ed
feat(ui): dual-stack WireGuard tunnel support on the VPN page (#471 p…
mack42 Jul 22, 2026
847f767
Merge pull request #587 from ZerosAndOnesLLC/feat/471-wg-ipv6
mack42 Jul 22, 2026
f84db97
fix(backup): route restored resolv.conf through aifw-sudo-install (#307)
mack42 Jul 22, 2026
bef35ce
Merge pull request #588 from ZerosAndOnesLLC/fix/307-resolv-conf-sudo…
mack42 Jul 22, 2026
93bf7a0
fix(backup): round-trip rDNS resolver config in snapshots (#589)
mack42 Jul 22, 2026
34a24a8
Merge pull request #590 from ZerosAndOnesLLC/fix/589-backup-dns-resolver
mack42 Jul 22, 2026
c2a4a47
fix(ui): make AppShell content margin react to viewport breakpoint (#…
mack42 Jul 22, 2026
55fe9ea
Merge pull request #591 from ZerosAndOnesLLC/fix/585-appshell-breakpo…
SirPullaLot Jul 22, 2026
9a5286a
fix(ui): override transitive sharp to >=0.35.3 (GHSA-f88m-g3jw-g9cj)
mack42 Jul 22, 2026
99ba2b1
Merge pull request #592 from ZerosAndOnesLLC/fix/dependabot-29-sharp-…
SirPullaLot Jul 22, 2026
9787fe7
fix(security): move UI auth to HttpOnly session cookies (#304)
mack42 Jul 22, 2026
e43ad36
Merge pull request #593 from ZerosAndOnesLLC/fix/304-cookie-auth
mack42 Jul 23, 2026
74703c8
fix(plugins): apply saved settings to running plugins (#586)
mack42 Jul 23, 2026
031581a
Merge pull request #594 from ZerosAndOnesLLC/fix/586-plugin-config-re…
SirPullaLot Jul 23, 2026
0d99160
fix(ui): retry WebSocket ticket fetch in global provider (#584)
mack42 Jul 23, 2026
7a002e7
Merge pull request #595 from ZerosAndOnesLLC/fix/584-ws-ticket-retry
SirPullaLot Jul 23, 2026
5b2335b
feat(nat): render NAT64/NAT46 as real pf af-to translation rules (#531)
mack42 Jul 23, 2026
c41da3c
feat(nat): family/prefix validation for cross-family NAT rules (#531)
mack42 Jul 23, 2026
3aa3a96
feat(pf): real-parser dry-run gate + strict add_rule errors (#531)
mack42 Jul 23, 2026
573fed4
feat(nat): combined-class anchor loads + aifw-nat anchor alignment (#…
mack42 Jul 23, 2026
01d1d5e
feat(nat): real-parser gate on create/update + API error surfacing (#…
mack42 Jul 23, 2026
efe361b
feat(ui): NAT64/NAT46 rule UX on the NAT page (#531)
mack42 Jul 23, 2026
01258ce
feat(cli): thorough NAT64/NAT46 UX (#531)
mack42 Jul 23, 2026
80a5a73
test(freebsd): t09 cross-family af-to traffic tests (#531)
mack42 Jul 23, 2026
fc1814b
feat(dns): wire DNS64 through to rDNS (#531)
mack42 Jul 23, 2026
a06d3f3
fix(pf): pass ICMPv6 neighbor discovery in generated pf.conf (#531)
mack42 Jul 23, 2026
368e5ca
test(setup): fix ND guard anchor search (nat-anchor substring false m…
mack42 Jul 23, 2026
2287fff
test(freebsd): NAT46 listener must bind IPv6 (plain nc -l is v4-only)
mack42 Jul 23, 2026
91326aa
test(freebsd): t03 leading-zero hour breaks POSIX arithmetic (octal)
mack42 Jul 23, 2026
513924b
test+docs: DNS64 e2e (t10) and NAT64/NAT46 doc flips (#531)
mack42 Jul 23, 2026
afa9b54
fix: review findings for #531 (PR #597)
mack42 Jul 23, 2026
a1dc917
chore: drop local .claude directory accidentally committed
mack42 Jul 23, 2026
88036c7
test(freebsd): t10 per-instance rdns lock paths
mack42 Jul 23, 2026
a30a718
test(freebsd): t10 rdns instances drop to nobody (no rdns account on …
mack42 Jul 23, 2026
2232a96
test(freebsd): t10 zone SOA on one line (rdns zone parser takes 7 pla…
mack42 Jul 23, 2026
693d359
Merge pull request #597 from ZerosAndOnesLLC/feat/531-nat64-af-to
SirPullaLot Jul 23, 2026
ccf842c
fix(release): pre-release gate applies before any asset is public
mack42 Jul 23, 2026
e309c72
Merge pull request #598 from ZerosAndOnesLLC/fix/prerelease-from-start
mack42 Jul 23, 2026
e4743fd
chore: bump rDNS pin to 04d5975 (DNS64)
mack42 Jul 23, 2026
0a781df
Merge pull request #599 from ZerosAndOnesLLC/chore/bump-rdns-dns64
SirPullaLot Jul 23, 2026
765d0e4
release: v5.110.0
mack42 Jul 23, 2026
679b6f2
Merge pull request #600 from ZerosAndOnesLLC/release/v5.110.0
SirPullaLot Jul 23, 2026
4d45864
fix: appliance post-upgrade sweep findings (#601)
mack42 Jul 23, 2026
0c70242
fix: absolute visudo in aifw-restart.sh too; update sudoers-refresh g…
mack42 Jul 23, 2026
e6f7025
Merge pull request #602 from ZerosAndOnesLLC/fix/601-appliance-sweep
SirPullaLot Jul 23, 2026
c93b6ca
release: v5.110.1
mack42 Jul 23, 2026
ae56e8a
Merge pull request #603 from ZerosAndOnesLLC/release/v5.110.1
mack42 Jul 23, 2026
6d9e2f3
fix(release): root-owned build artifacts no longer break signing
mack42 Jul 24, 2026
1da8be1
Merge pull request #604 from ZerosAndOnesLLC/fix/release-output-owner…
SirPullaLot Jul 24, 2026
04ef026
fix: FreeBSD-target warnings + UI restart-flow hangs
mack42 Jul 24, 2026
b30c7a2
fix(setup): qualify pw invocations the removed import served
mack42 Jul 24, 2026
dbbe4ae
feat(ids): manual alert purge (UI/CLI), auto space reclaim, 7-day ret…
mack42 Jul 24, 2026
3e48861
release: v5.111.0
mack42 Jul 24, 2026
592afda
Merge pull request #605 from ZerosAndOnesLLC/fix/freebsd-target-warnings
SirPullaLot Jul 24, 2026
5f2858c
Merge pull request #606 from ZerosAndOnesLLC/feat/ids-clear-alerts
SirPullaLot Jul 24, 2026
a26f0a0
Merge pull request #607 from ZerosAndOnesLLC/release/v5.111.0
SirPullaLot Jul 24, 2026
23f3061
fix(build): companion checkouts restore the operator's branch; update…
mack42 Jul 24, 2026
75e75c2
fix(build): hand companion repos back to the operator after root builds
mack42 Jul 24, 2026
7d5fda2
Merge pull request #608 from ZerosAndOnesLLC/fix/companion-checkout-r…
SirPullaLot Jul 24, 2026
dd048a8
chore: move builds to FreeBSD 15.1-RELEASE
mack42 Jul 24, 2026
be32afc
Merge pull request #610 from ZerosAndOnesLLC/chore/freebsd-15.1
SirPullaLot Jul 24, 2026
0547d85
Merge remote-tracking branch 'origin/main' into pr-580-fix
mack42 Jul 24, 2026
34f4036
fix: update_queue now uses insert_queue_on after upstream rename
mack42 Jul 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ assignees: ''
e.g. 5.8.0

**FreeBSD Version**
e.g. FreeBSD 15.0-RELEASE
e.g. FreeBSD 15.1-RELEASE

**Component**
Which part of AiFw is affected?
Expand Down
106 changes: 101 additions & 5 deletions .github/workflows/build-iso.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ on:

permissions:
contents: write
id-token: write
attestations: write

env:
FREEBSD_VERSION: "15.0"
FREEBSD_VERSION: "15.1"

jobs:
build-ui:
Expand Down Expand Up @@ -187,6 +189,10 @@ jobs:
if [ -f "$f" ] && [ ! -f "${f}.xz" ]; then
xz -T0 -9 "$f"
sha256 "${f}.xz" > "${f}.xz.sha256"
# build-iso.sh hashed the uncompressed file, which no
# longer exists after xz — drop its checksum so we never
# sign or publish a sum nobody can verify.
rm -f "${f}.sha256"
fi
done
cd /home/runner/work/AiFw/AiFw
Expand All @@ -195,6 +201,45 @@ jobs:
mkdir -p /home/runner/work/AiFw/AiFw/output
cp /usr/obj/aifw-iso/output/* /home/runner/work/AiFw/AiFw/output/

# Scan the SOURCE tree, not output/: the release artifacts are
# xz-compressed images syft cannot see inside, so an SBOM of output/
# would be an empty inventory. The source scan covers Cargo.lock and
# aifw-ui/package-lock.json — the dependency set actually compiled
# into this release.
- name: Generate release CycloneDX SBOM
uses: anchore/sbom-action@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6
with:
path: .
format: cyclonedx-json
output-file: output/aifw-release.cdx.json
upload-artifact: false

- name: Sign release checksums
env:
MINISIGN_SECRET_KEY: ${{ secrets.MINISIGN_SECRET_KEY }}
MINISIGN_PASSWORD: ${{ secrets.MINISIGN_PASSWORD }}
run: |
set -euo pipefail
test -n "$MINISIGN_SECRET_KEY" || { echo "MINISIGN_SECRET_KEY is required" >&2; exit 1; }
sudo apt-get update
sudo apt-get install -y minisign
key_file="$RUNNER_TEMP/minisign.key"
trap 'rm -f "$key_file"' EXIT
printf '%s' "$MINISIGN_SECRET_KEY" > "$key_file"
chmod 600 "$key_file"
pubkey=freebsd/overlay/usr/local/etc/aifw/update-signing.pub
cp "$pubkey" output/update-signing.pub
for checksum in output/*.sha256; do
# minisign reads the key password from stdin when there is no
# tty; harmless if the key is passwordless.
printf '%s\n' "${MINISIGN_PASSWORD:-}" | \
minisign -S -s "$key_file" -m "$checksum" -x "${checksum}.minisig"
# Verify against the COMMITTED public key immediately: catches a
# rotated/mismatched MINISIGN_SECRET_KEY before anything ships,
# since appliances verify with the key compiled from this file.
minisign -Vm "$checksum" -x "${checksum}.minisig" -p "$pubkey"
done

- name: Upload ISO artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
Expand Down Expand Up @@ -223,6 +268,25 @@ jobs:
path: output/aifw-components-*.json
retention-days: 5

- name: Upload SBOMs and signatures
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: supply-chain
path: |
output/*.cdx.json
output/*.minisig
output/update-signing.pub
retention-days: 5

- name: Attest release artifacts
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
with:
subject-path: |
output/aifw-*.iso.xz
output/aifw-*.img.xz
output/aifw-update-*.tar.xz
output/aifw-release.cdx.json

smoke-boot:
name: Appliance boot smoke (qemu)
needs: build-iso
Expand Down Expand Up @@ -263,7 +327,6 @@ jobs:
name: boot-smoke-artifacts
path: smoke-artifacts/
retention-days: 7

release:
name: Create GitHub Release
# smoke-boot gates the release: an image nobody booted never ships (#533).
Expand Down Expand Up @@ -296,6 +359,25 @@ jobs:
name: components
path: release-assets/

- name: Download supply-chain assets
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: supply-chain
path: release-assets/

- name: Verify signatures before publication
run: |
set -euo pipefail
sudo apt-get update
sudo apt-get install -y minisign
# The committed key from checkout — the same file compiled into
# the appliance updater — not a copy that traveled with the
# artifacts being verified.
pubkey=freebsd/overlay/usr/local/etc/aifw/update-signing.pub
for checksum in release-assets/*.sha256; do
minisign -Vm "$checksum" -x "${checksum}.minisig" -p "$pubkey"
done

- name: Extract version from tag
id: version
run: if [ -n "${{ inputs.version }}" ]; then
Expand All @@ -309,7 +391,12 @@ jobs:
with:
name: "AiFw v${{ steps.version.outputs.version }}"
draft: false
prerelease: ${{ contains(github.ref_name, '-rc') || contains(github.ref_name, '-beta') || contains(github.ref_name, '-alpha') }}
# ALWAYS pre-release: field appliances auto-pull /releases/latest,
# which skips pre-releases. A plain v* tag used to publish stable
# instantly — an untested build every appliance would grab the
# moment CI finished. Promote after testing with:
# gh release edit <tag> --prerelease=false --latest
prerelease: true
generate_release_notes: true
files: |
release-assets/*
Expand All @@ -335,6 +422,15 @@ jobs:
### Verify Downloads

```bash
sha256sum -c aifw-${{ steps.version.outputs.version }}-amd64.iso.sha256
sha256sum -c aifw-${{ steps.version.outputs.version }}-amd64.img.sha256
minisign -Vm aifw-${{ steps.version.outputs.version }}-amd64.iso.xz.sha256 \
-x aifw-${{ steps.version.outputs.version }}-amd64.iso.xz.sha256.minisig \
-p update-signing.pub
sha256sum -c aifw-${{ steps.version.outputs.version }}-amd64.iso.xz.sha256
```

GitHub build provenance can also be verified with:

```bash
gh attestation verify aifw-${{ steps.version.outputs.version }}-amd64.iso.xz \
--repo ${{ github.repository }}
```
37 changes: 37 additions & 0 deletions .github/workflows/fq-codel-freebsd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: FQ-CoDel FreeBSD qualification

on:
pull_request:
paths:
- "aifw-common/src/ratelimit.rs"
- "aifw-core/src/shaping.rs"
- "freebsd/overlay/usr/local/libexec/aifw*dummynet*"
- "freebsd/tests/t08-fq-codel.sh"
- ".github/workflows/fq-codel-freebsd.yml"
workflow_dispatch:

permissions:
contents: read

jobs:
functional:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Exercise real FreeBSD dummynet
uses: vmactions/freebsd-vm@77ed28d336d03fe19a3f4f7266c1d2c4714dd79d # v1.5.2
with:
release: "15.0"
usesh: true
prepare: |
install -m 755 freebsd/overlay/usr/local/libexec/aifw-dummynet-control /usr/local/libexec/aifw-dummynet-control
run: |
sh freebsd/tests/t08-fq-codel.sh 2>&1 | tee fq-codel-results.txt
- name: Upload raw result
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: fq-codel-freebsd-${{ github.sha }}
path: fq-codel-results.txt
if-no-files-found: warn
2 changes: 1 addition & 1 deletion .github/workflows/freebsd-functional.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
- name: Run harness in FreeBSD VM
uses: vmactions/freebsd-vm@77ed28d336d03fe19a3f4f7266c1d2c4714dd79d # v1.5.2
with:
release: "15.0"
release: "15.1"
usesh: true
copyback: true
prepare: |
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,8 @@ node_modules/
freebsd/release/
freebsd/ui-export/

# Local-only review/status ledger
/status.md

# CLAUDE.md is project policy and is tracked in the repo — do not ignore it.
Cargo.lock
4 changes: 4 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ Central type: `Database` struct in `aifw-core/src/db.rs` wrapping `SqlitePool`.
- `Authorization: ApiKey <key>` header
- `?ticket=<id>` query param (WebSocket/SSE) — single-use, 30-second
ticket issued by `POST /auth/ws-ticket` (see `auth::ws_ticket`).
- `aifw_at` HttpOnly session cookie (browser UI; SEC-M7 #304, see
`auth::cookies`) — fallback when no header/ticket is present. Cookie-authed
non-GET requests must also send the `X-AiFw-Csrf` header; the UI never
stores the JWT in `localStorage`.

**AppState** holds all engines as `Arc<T>`, shared `Arc<dyn PfBackend>`, and `SqlitePool`. Passed to handlers via Axum's `State` extractor.

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ resolver = "2"

[workspace.package]

version = "5.109.4"
version = "5.111.0"
edition = "2024"
license = "MIT"
repository = "https://github.com/ZerosAndOnesLLC/AiFw"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ High-performance firewall for FreeBSD built in Rust on top of pf. Optional AI/ML
## Features

- **Stateful packet filtering** via FreeBSD's pf with anchor isolation
- **NAT** — SNAT, DNAT/RDR, masquerade, binat (NAT64/NAT46 in development — rule types exist, cross-family translation data plane is being built, #531)
- **NAT** — SNAT, DNAT/RDR, masquerade, binat, NAT64/NAT46 (real cross-family translation via pf af-to, FreeBSD 15+, with DNS64 in the resolver)
- **Connection tracking** — real-time state table monitoring, top talkers, protocol breakdown
- **Rate limiting & traffic shaping** — HFSC/PriQ queues, per-IP overload tables, SYN flood protection (CoDel via dummynet FQ-CoDel in development, #532)
- **AI/ML threat detection** *(optional, WIP)* — experimental port scan, DDoS, brute force, C2 beacon, DNS tunnel detection with auto-response (disabled by default, not yet production-ready)
Expand Down
Loading
Loading