aafeher/nftui
GitHub: aafeher/nftui
nftui 是一个基于 Go 和 Bubble Tea 框架构建的 Linux nftables 防火墙终端管理界面,让用户无需直接操作 nft CLI 即可浏览和编辑完整的防火墙规则集。
Stars: 1 | Forks: 0
# nftui
[](https://github.com/aafeher/nftui/actions/workflows/ci.yml)
[](https://github.com/aafeher/nftui/actions/workflows/codeql.yml)
[](https://codecov.io/gh/aafeher/nftui)
[](https://scorecard.dev/viewer/?uri=github.com/aafeher/nftui)
[](https://github.com/aafeher/nftui/releases/latest)
[](LICENSE)
[](go.mod)
[](#requirements)
[](https://github.com/aafeher/nftui/releases)
`nftui` 是一个用于在 Linux 上管理 `nftables` 的终端用户界面。浏览从内核获取的实时规则集,使用针对每种条件和操作类型构建的完整结构化编辑器来编辑规则,并将更改应用回内核 —— 而无需直接接触 `nft` CLI。
使用 Go 和 [Bubble Tea](https://github.com/charmbracelet/bubbletea) 框架构建。通过 `google/nftables` (https://github.com/google/nftables) 库经 netlink 与内核进行通信。
## 功能
### 规则集浏览与管理
- 以树状视图展示所有表和链,并带有从内核获取的实时数据。骨架(表、链、集合、命名对象)在启动时立即渲染;每个链的规则计数异步填充,因此具有许多链的规则集在后台接收规则列表时仍保持交互性(每个链行在其获取完成前会短暂显示 `[loading rules...]`)。
- 每个链的规则列表,其中包含对每个解析出的表达式的人类可读的渲染。该列表采用了窗口化技术 —— 仅对适合屏幕的规则进行序列化和绘制,因此拥有 1000+ 条规则的链与只有 10 条规则的链在滚动时的开销相同。内联过滤器 (`/`) 会在第一次匹配时缓存每条规则的小写文本,因此在大型链上,后续的按键操作也能保持响应迅速。
- 规则详情视图,按条件类别划分为多个标签页。
- 对表、链和规则的完整 CRUD 操作:创建、重命名/编辑属性、删除(带确认)、在链内上下重排规则、在前面插入/在末尾追加。
### 规则编辑器 — 支持的条件
| 类别 | 匹配项 |
|----------|---------|
| **CT (conntrack)** | state, direction, status, mark, secmark, expiration, helper, l3proto, protocol, proto-src, proto-dst, labels, eventmask, ip saddr / daddr, bytes, packets, avgpkt (附带 direction), zone, count |
| **IPv4 header** | saddr, daddr (CIDR), protocol, ttl, length, dscp, version, hdrlength, id, frag-off, checksum |
| **IPv6 header** | saddr, daddr (CIDR), length, nexthdr, hoplimit, version, dscp (6-bit), flowlabel (20-bit) |
| **TCP** | sport, dport, sequence, ackseq, flags (MultiSelect), window, checksum, urgptr, doff |
| **UDP / UDPLITE** | sport, dport, length, checksum |
| **SCTP** | sport, dport, vtag, checksum, **chunk** (RFC 4960 chunk-type 匹配:data / init / init-ack / sack / heartbeat / heartbeat-ack / abort / shutdown / shutdown-ack / error / cookie-echo / cookie-ack / ecne / cwr / shutdown-complete / auth / asconf-ack / i-data / forward-tsn / asconf / i-forward-tsn —— 同时支持单纯存在性检查和基于类型的子字段约束:chunk-type Select 驱动一个子字段 Select(DATA 的 `tsn` / `stream` / `ssn` / `ppid`;INIT 的 `init-tag` / `a-rwnd` / `os` / `mis` / `init-tsn`;SACK 的 `cum-tsn-ack` / `a-rwnd` / `num-gap-ack-blocks` / `num-dup-tsns`;等等),外加一个值输入框,该输入会进行大端编码以匹配 1 / 2 / 4 字节宽度) |
| **Meta (interface)** | iifname, oifname, iif, oif, iiftype, oiftype, iifgroup, oifgroup |
| **Meta (proto / socket / packet)** | length, protocol (EtherType), nfproto, l4proto, mark, priority, skuid, skgid, cgroup, rtclassid, pkttype, cpu |
### 规则编辑器 — 支持的操作
- **Verdicts**: `accept`, `drop`, `return`, `jump `, `goto ` —— 为 jump / goto 目标提供链名称输入。
- **Reject**: `with icmp type`, `with icmpx type`, `with tcp reset` —— 具备协议族感知能力(ICMP 类型 Select 会根据 ip / ip6 / inet / bridge 表发生变化)。
- **Log**: prefix, level (emerg…debug), NFLOG group, snaplen, queue-threshold —— 在保存前对被内核拒绝的组合进行预验证(例如,在 NFLOG 模式下禁止使用 `level`)。
- **Counter**: 在匿名 counter 上编辑 packet 和 byte 计数(典型用法是重置为 0)。
- **Limit**: rate, unit (second/minute/hour/day/week), burst, type (packets/bytes), over。
### 编辑器交互体验
- 每个标签页对相关字段进行分组;**Tab** / **Shift+Tab** 可在子输入项之间移动焦点。
- 已修改的字段会高亮显示;清空输入项将移除底层的匹配条件。
- **F2** 通过 netlink (`NLM_F_REPLACE`) 验证并应用所有更改。
- 底部的帮助行始终列出当前视图中所有可用的按键绑定。
## 系统要求
- **Linux**,且内核需支持 `nftables`。
- **Go 1.25+** 用于从源码构建。
- 运行时需要 **`CAP_NET_ADMIN`**(通过 `sudo` 运行或使用 `setcap` 授予该能力)。
- 至少 **80x24** 字符的终端。低于此尺寸,nftui 将显示调整大小提示,而不是显示拥挤的布局。
运行时**不需要** `nft` CLI 来进行核心的读取 / 编辑 / 写入操作 —— 通信直接通过 netlink 进行。`nft` 二进制文件仅用于少数特定操作,在这些操作中,通过 CLI 传递比重建内核状态更安全(表重命名、基础链重建)。
## 安装
```
git clone https://github.com/aafeher/nftui.git
cd nftui
go build -o nftui .
```
### 预构建包
每个[发布版本](https://github.com/aafeher/nftui/releases)都附带了针对 `amd64` 和 `arm64` 的原生包,它们均由与压缩包相同的二进制文件构建而成,并列在 `checksums.txt` 中(因此 cosign 签名涵盖它们):
| 格式 | 发行版 | 安装 |
|--------|---------|---------|
| `.deb` | Debian / Ubuntu | `sudo apt install ./nftui__linux_amd64.deb` |
| `.rpm` | Fedora / RHEL / openSUSE | `sudo dnf install ./nftui__linux_amd64.rpm` |
| `.apk` | Alpine | `sudo apk add --allow-untrusted ./nftui__linux_amd64.apk` |
| `.pkg.tar.zst` | Arch | `sudo pacman -U ./nftui__linux_amd64.pkg.tar.zst` |
| `.ipk` | OpenWrt (opkg) | `opkg install ./nftui__linux_amd64.ipk` |
每个包都会将 `nftui` 安装到 `/usr/bin`,将 man page 安装到 `/usr/share/man/man1`,并声明 `nftables` 运行时依赖。这些二进制文件是静态的(无 CGO),因此它们可以在 glibc 和 musl 系统上运行。
OpenWrt 正在从 `opkg` 迁移到 `apk`,因此在匹配的架构上,`.apk` 应该服务于较新的基于 apk 的 OpenWrt,而 `.ipk` 涵盖现有的 opkg 版本。其他架构(mips, armv7)的路由器不在此范围内 —— 请在那里从源码构建。
**Arch / AUR:** 发布的 `.pkg.tar.zst` 可以直接使用 `pacman -U` 安装,不需要 AUR。nftui 本身不发布到 AUR;欢迎社区维护者采纳参考的 [`packaging/aur/PKGBUILD`](packaging/aur/PKGBUILD)(基于发布 tarball 的 `-bin` 包)。
**Gentoo:** 该仓库是一个标准的 Go 模块,因此 `go build -o nftui .` 是最简单的途径。为本地 overlay 提供了两个社区可维护的参考 ebuild:[`nftui-1.1.0.ebuild`](packaging/gentoo/nftui-1.1.0.ebuild) 通过 `go-module.eclass` 从源码构建,而 [`nftui-bin-1.1.0.ebuild`](packaging/gentoo/nftui-bin-1.1.0.ebuild) 安装预构建的发布二进制文件;请安装其中之一(它们共享 `/usr/bin/nftui` 且相互阻塞)。有关 overlay 设置,请参阅 [`packaging/gentoo/README.md`](packaging/gentoo/README.md)。nftui 不维护 Portage / GURU 条目。
### Nix flake
该仓库提供了一个 [`flake.nix`](flake.nix),其中包含用于 `x86_64-linux` 和 `aarch64-linux` 的 `buildGoModule` 包,一个镜像 CI 工具链的 `devShell`,以及一个可运行的 `apps.default`:
```
nix build # builds into ./result/bin/nftui (+ man page)
nix run # builds and runs (needs CAP_NET_ADMIN at runtime)
nix develop # toolchain: go, gopls, goreleaser, nftables, mandoc
```
在首次执行 `nix build` 时,`vendorHash` 被故意设置为 `lib.fakeHash` —— Nix 会在错误信息中打印出真实的 `sha256-…`,用户将其粘贴到 `flake.nix` 中(每当 `go.sum` 更改时需重新固定)。这使得二进制发布(Goreleaser)和 Nix 构建保持独立:Nix 路径不会阻塞发布流程。
### Docker
[`Dockerfile`](Dockerfile) 构建了一个小型的(约 17 MB)镜像,其中捆绑了 nftui 在运行时所需的 `nft(8)` CLI:
```
docker build -t nftui:local .
# 带版本的构建(设置 `nftui --version`):
docker build -t nftui:1.1.0 --build-arg VERSION=1.1.0 .
```
nftui 管理**主机**规则集,因此容器需要主机网络命名空间、`NET_ADMIN` 能力以及一个交互式 TTY:
```
docker run --rm -it --network host --cap-add NET_ADMIN nftui:local
```
标志将直接传递,例如 `… nftui:local --read-only`。
一个 [`docker-compose.yml`](docker-compose.yml) 配置了相同的选项。请使用 `run`(而不是 `up`),以便 TUI 获得真实的 TTY:
```
docker compose run --rm nftui
```
该容器以 root 用户身份运行,并依赖 `--cap-add NET_ADMIN` 以及容器边界进行隔离;使用 `--network host` 时,它会编辑主机的 nftables —— 这与在主机上直接运行二进制文件的权限范围相同(请参阅[权限模型与部署强化](#privilege-model--deployment-hardening))。
### 运行
使用 `sudo`:
```
sudo ./nftui
```
…或者一次性为二进制文件授予所需的能力:
```
sudo setcap cap_net_admin=ep ./nftui
./nftui
```
### 安装 man page(可选)
```
sudo install -m 0644 man/nftui.1 /usr/share/man/man1/
sudo mandb # if your system uses man-db (Debian / Ubuntu / Fedora …)
man nftui # then it's available everywhere
```
在不安装的情况下从源码树中预览它:
```
man -l man/nftui.1
```
## 命令行标志
| 标志 | 描述 |
|------|-------------|
| `--table ` | 将树状视图限制为单个表 —— 包括其链、集合和命名对象。匹配是针对每个族按名称进行的,因此如果 `inet filter` 和 `ip filter` 同时存在,`--table filter` 会将它们同时包括在内。未知的名称会在 TUI 启动之前退出,并打印可用表列表。 |
| `--config ` | 在 TUI 启动**之前**,通过 `nft -f ` 应用给定的 nftables 规则集。**这会改变正在运行的规则集** —— 该文件可能包含 `flush ruleset`。用于为测试建立已知状态。在 `--table` 之前解析,因此加载后的内核状态是 `--table` 要验证的对象。 |
| `--read-only` | 禁用所有写入路径:没有规则的添加/插入/移动/删除/编辑/保存,没有链/表/集合的创建/删除,没有计数器重置。被阻止的按键会在行变暗(根据底部完整性原则),并且在每个主视图中,标题旁边会显示一个 `[READ-ONLY MODE]` 标记。适用于安全浏览、审计,或与 `--config` 配合使用,以便在无意外编辑风险的情况下检查夹具。 |
| `--help` (以及 `-h`) | 打印包含单行描述和使用示例的完整标志列表,然后退出。输出指向 stdout(因此您可以通过管道传递给 `less`);显式的 `--help` 以状态码 0 退出。无效的标志会将相同的使用说明输出到 stderr 并以状态码 2 退出。 |
| `--version` | 向 stdout 打印 `nftui ` 并以状态码 0 退出。版本是在发布构建时注入的;从源码构建的二进制文件会报告 Go 构建信息模块版本,如果是普通的 `go build`,则报告为 `dev`。 |
示例:
```
sudo ./nftui --table filter # show only table(s) named 'filter'
sudo ./nftui --table missing # exits: "table 'missing' not found. Available tables: …"
sudo ./nftui --config examples/example-nftables-01.conf # load the manual-test fixture, then browse it
sudo ./nftui --read-only # safe browsing — every write key is dimmed and inert
sudo ./nftui --config new.conf --table filter # apply new.conf, then restrict the view to its 'filter' table
./nftui --version # print the version and exit (no privileges needed)
```
如果没有 `--config`,正在运行的规则集将保持不变。如果没有 `--table`,将显示所有表。如果没有 `--read-only`,则所有 CRUD 操作均可用。
## 权限模型与部署强化
nftui 通过 netlink 读取和写入内核的 nftables 规则集,这需要 **`CAP_NET_ADMIN`** 能力。它**自身没有身份验证或授权机制**:任何能够以该能力启动 nftui 的用户都可以重写防火墙。因此,nftui 的安全性仅取决于您授予该权限的方式 —— 如果授予的范围过广,该二进制文件就会成为一个*被迷惑的代理人* (confused deputy)。请在 OS 层强制实施访问控制。推荐两种模式。
### 推荐:使用带限制规则的 `sudo`
通过 `sudo` 运行 nftui,并限制谁可以这样做。创建一个专用组(例如 `nftadm`),添加受信任的操作员,并使用 `visudo` 添加规则:
```
# /etc/sudoers.d/nftui(使用以下命令编辑:visudo -f /etc/sudoers.d/nftui)
# 让 nftadm 组以 root 身份运行 nftui —— 并且仅限于此。
%nftadm ALL=(root) /usr/local/bin/nftui
```
- 使用**绝对路径**,这样 `PATH` 中较早出现的不同 `nftui` 就无法被替换。
- 对于交互式使用,请保持开启密码提示(没有 `NOPASSWD`):`sudo` 会在每次调用时写入一条 auth-log 条目,为您提供“谁在何时操作”的记录。
- 然后,操作员运行 `sudo nftui`。nftui 会读取 `SUDO_USER`,因此如果启用了[审计日志](#audit-logging),每次应用的更改都会记录 `sudo` 背后的人类操作员,而不仅仅是 `root`。
对于只读/浏览角色,仅向更广泛的组授予 `--read-only` 形式。`sudo` 会精确匹配命令**及其参数**,因此此规则允许 `sudo nftui --read-only`,但不允许不受限制的 `sudo nftui`:
```
%nftview ALL=(root) /usr/local/bin/nftui --read-only
```
### 替代方案:受组限制的 `setcap` 二进制文件
如果您必须在没有 `sudo` 的情况下运行(例如自动化),请将该能力授予文件,但要限制**谁可以执行它** —— 绝不要让它对全局可执行:
```
sudo chown root:nftadm /usr/local/bin/nftui
sudo chmod 750 /usr/local/bin/nftui # root: rwx, nftadm: r-x, others: none
sudo setcap cap_net_admin+ep /usr/local/bin/nftui
```
- 该能力依附于**文件**,而不是用户,因此 `chmod 755` + `setcap` 实际上等于将防火墙重写权力交给了每个本地账户。使用 `chmod 750` 并配合专用组才能将其限制在范围内。
- `setcap` 二进制文件绕过了 `sudo`,因此**没有 sudo auth-log 条目**,`SUDO_USER` 也是空的 —— 请依赖 `NFTUI_AUDIT_LOG` 来获取更改记录(它仍然会捕获真实的 UID/用户)。
- 保持该二进制文件及其父目录只能由 `root` 写入,这样带有能力的文件就不会被替换。
### 纵深防御
- 开启[审计日志](#audit-logging) (`NFTUI_AUDIT_LOG`),这样每次突变都会被归属并加上时间戳 —— OS 控制*谁可以运行* nftui;审计日志记录*他们更改了什么*。
- 对于永远不应改变状态的检查/审计角色,请使用 `--read-only`。
- `sudo` 与 **PAM** 集成,因此重新身份验证、MFA 或时间/主机限制(`pam_time`、`pam_access`)都在 PAM 层进行配置 —— 这就是 nftui 的“PAM 包装”;该工具故意不添加自身的访问控制。
## 审计日志
为了进行变更管理和合规性审查(例如 SOC 2 / PCI-DSS),nftui 可以记录其应用的每次规则集突变。将 `NFTUI_AUDIT_LOG` 环境变量设置为可写入的文件路径:
```
sudo NFTUI_AUDIT_LOG=/var/log/nftui-audit.log ./nftui
```
当该变量**未设置或为空时,审计功能关闭**,nftui 的行为与以前完全相同 —— 突变路径上没有文件 I/O。当设置此变量后,每次应用的更改(创建/删除/重命名表、链和集合;添加/插入/移动/删除/编辑规则;添加/删除集合元素;删除/重置命名对象;`--config` 加载;规则集清空)都会追加一个包含 JSON 对象的行:
```
{"time":"2026-06-19T10:30:00.12Z","uid":0,"user":"root","sudo_user":"alice","op":"delete-rule","target":"ipv4 filter input handle 7","result":"ok"}
```
每条记录都包含 UTC 时间戳、有效的 UID 和用户、`sudo` 背后的人类操作员(`sudo_user`,来自 `SUDO_USER`)、操作、目标对象以及结果(`result` 为 `ok` 或 `error`,失败时会带有 `error` 字段 —— 被拒绝的尝试也会被记录)。特性:
- **仅追加 (Append-only)** —— nftui 只进行追加;它从不轮转、截断或回读该文件。请使用 `logrotate` 轮转它,或将这些行发送到 SIEM。
- **0600** —— 该文件创建为仅所有者可读写。
- **失败放行 (Fail-open)** —— 如果无法打开该路径,nftui 会打印一条警告并继续运行而不进行审计;损坏的审计路径永远不会阻塞防火墙管理。请确保 nftui 进程可写入该路径。
## 按键绑定
### 主树视图(表 + 链)
| 按键 | 操作 |
|-----|--------|
| `↑` / `k` | 向上移动选择 |
| `↓` / `j` | 向下移动选择 |
| `Enter` / `→` / `←` | 展开 / 折叠 |
| `F3` | 打开链(规则列表) |
| `n` | 新建表 |
| `c` | 新建链 |
| `e` | 编辑选定的表或链 |
| `d` | 删除选定的表或链 |
| `/` | 搜索 |
| `r` | 从内核刷新 |
| `q` / `Esc` / `Ctrl+C` | 退出 |
### 链视图(规则列表)
| 按键 | 操作 |
|-----|--------|
| `↑` / `k` | 向上移动选择 |
| `↓` / `j` | 向下移动选择 |
| `F3` | 查看规则 |
| `F4` | 编辑规则 |
| `a` | 在末尾追加规则 |
| `i` | 在选定项之前插入规则 |
| `K` (Shift+k) | 向上移动选定的规则 |
| `J` (Shift+j) | 向下移动选定的规则 |
| `d` | 删除规则 |
| `/` | 按子字符串过滤规则(verdict、条件关键字、注释) |
| `Esc` | 返回 |
| `q` | 退出 |
在过滤器处于活动状态时,`↑` / `↓` 可在过滤后的列表中导航,`Enter` / `F3` 会打开选定的规则进行查看,`F4` 会打开编辑器,而 `Esc` 会清除过滤器。
### 规则编辑器
| 按键 | 操作 |
|-----|--------|
| `F5` / `F6` | 上一个 / 下一个标签页 |
| `Tab` / `Shift+Tab` | 下一个 / 上一个字段 |
| `F2` | 保存(验证 + 应用到内核) |
| `Esc` / `F3` | 返回 |
| `q` / `Ctrl+C` | 退出 |
## 示例规则集
`examples/example-nftables-01.conf` 是标准的手动测试夹具。它涵盖了上述记录的所有功能,并使用 `nft -c -f` 针对主机内核进行了验证。如果想要一个切合实际、符合最佳实践的起点,而不是功能展示,`examples/example-host-firewall.conf` 是一个经过强化的单机防火墙(默认拒绝除 SSH/HTTP/HTTPS 之外的入站连接,出站不受限制,拒绝转发)。仅在覆盖 nftables 状态没有问题的系统上显式加载它们:
```
sudo nft -c -f examples/example-nftables-01.conf # syntax check
sudo nft flush ruleset # reset (DANGER on prod)
sudo nft -f examples/example-nftables-01.conf # apply
```
## 项目布局
```
main.go program entry point
nft/ kernel-talking core
rule.go expression → Rule structure parser
nft_linux.go netlink CRUD operations (Linux build tag)
nft_stub.go no-op stubs for non-Linux builds
expr/ per-expression format helpers
nftserializer/ ruleset → human-readable output
ui/ Bubble Tea TUI
main_window.go top-level model (tree view)
chain_view.go rule list
rule_view.go rule detail (read-only)
rule_edit.go rule editor with tabbed FieldEditors
field_*.go one file per FieldEditor
examples/example-nftables-01.conf manual-test fixture
man/nftui.1 man page (groff/mandoc; see "Installation")
CHANGELOG.md per-version release notes (Keep a Changelog format)
```
## 测试
```
go test ./... # unit tests (no kernel required)
sudo nft -c -f examples/example-nftables-01.conf # validate the fixture
```
### 集成测试
带有 `integration` 构建标签的测试使用 TUI 所使用的相同辅助工具,对实时的 netlink 读取**和**写入路径进行了验证:通过 `nft -f` 应用规则集并将其读回,加上创建/重命名/删除表和链,以及添加/插入/移动/删除规则,并在每一步之后对读回的内核状态进行断言。它们被排除在默认的 `go test ./...` 之外,并且在不以 root 身份运行时会自行跳过,因此普通的 `go test` 保持可移植性。
```
sudo -E go test -tags=integration ./nft/ -v
```
每个测试都会创建一个唯一命名的表(带有时间戳后缀,因此并发运行和遗留状态不会发生冲突),并在 `t.Cleanup` 中将其销毁,即使断言失败也是如此。`nft` 二进制文件必须位于 PATH 中;如果缺少,请从您发行版的 `nftables` 包中安装它。
### 持续集成
[`.github/workflows/ci.yml`](.github/workflows/ci.yml) 在每次向 `main` / `develop` 发起 push 和 pull request 时运行相同的检查:
- **构建与单元测试** —— `gofmt -l`、`go vet ./...`(默认和 `integration` 构建标签)、`go build ./...`,以及 `go test -race ./...`。
- **集成测试** —— 安装 `nftables` 包,然后运行 `sudo -E go test -tags=integration -v ./nft/`,以便测试工具具备应用实时规则集所需的 `CAP_NET_ADMIN`。在 `nft` 树上写入覆盖率配置文件(`-coverpkg=./nft/...`)并在作业日志中打印总计 —— 实时的 netlink 路径对单元测试配置文件是不可见的,因此这是可以观察到其覆盖率的地方。仅在单元测试作业通过后才运行。
- **漏洞扫描** —— 针对模块和 Go 标准库运行 `govulncheck ./...`。作为其独立的检查(与构建并行),仅当从 nftui 的调用图中可到达已知漏洞时,它才会使运行失败。
- **可重现构建检查** —— 使用 `goreleaser build --snapshot` 构建两次发布二进制文件,如果两者不同则失败,从而验证 `mod_timestamp` / `-trimpath` / 无 CGO 构建是逐字节可重现的。
- **Nix flake 构建** —— 在 Nix 运行器上,`nix flake check` + `nix build .#default` 端到端构建 [`flake.nix`](flake.nix)(在沙箱中编译 nftui 并运行其单元测试套件),因此 flake 不会悄悄损坏。首次运行必须固定 `flake.nix` 的 `vendorHash` —— 它作为占位符提供,失败的构建会打印出要粘贴的真实值。
依赖项和 GitHub-Actions 的更新通过 Dependabot(`.github/dependabot.yml`,每周)自动化,当上游版本发布和安全修复落地时,它会打开 PR。`github.com/google/nftables` 被排除在这些 PR 之外,因为它是被有意保持在固定的快照版本的。
Go 版本通过 `actions/setup-go@v6` 的 `go-version-file: go.mod` 来自 `go.mod`,因此更新模块的 Go 版本会在同一次提交中更新 CI。在同一引用上的并发运行会取消较早的运行中的作业(`cancel-in-progress: true`)。
## 发布流程
发布由 [Goreleaser](https://goreleaser.com/) 和标签触发的工作流([`.github/workflows/release.yml`](.github/workflows/release.yml))驱动:
1. 将 `CHANGELOG.md` 中的 `[Unreleased]` 部分提升为 `[X.Y.Z] - `。
2. `git tag vX.Y.Z` 和 `git push --tags`。
3. 发布工作流从 `CHANGELOG.md` 中提取匹配的 `[X.Y.Z]` 部分,然后运行 Goreleaser,它会构建可重现的 Linux `amd64` / `arm64` 二进制文件(`CGO_ENABLED=0 -trimpath -ldflags='-s -w'`,`mod_timestamp` 固定为提交时间),将二进制文件与 `LICENSE`、`README.md`、`CHANGELOG.md` 和 `man/nftui.1` 一起打包成 `tar.gz`,同时还会生成 `.deb` / `.rpm` / `.apk` / Arch `.pkg.tar.zst` / OpenWrt `.ipk` 包(通过 nfpm,同一个二进制文件),为每个制品写入一个 SHA-256 的 `checksums.txt`,并发布 GitHub Release,其中以经过精心整理的说明作为正文。
4. 该版本通过供应链证明进行了强化:`checksums.txt` 使用 **cosign** 进行签名(无密钥 —— 签名通过 Fulcio/Rekor 绑定到工作流的 OIDC 身份,无需存储私钥),每个压缩包都会生成一份 **Syft SBOM**,并且针对压缩包、校验和以及下文的依赖 tarball 记录了 **SLSA 构建来源** 证明。
5. 一个可重现的 `nftui--deps.tar.xz`(Go 模块缓存,来自 `scripts/gen-deps-tarball.sh`)被上传用于离线源码构建 —— 主要是 Gentoo 源码 ebuild,其 `go-module.eclass` 禁止在构建时进行网络访问。其内容由 `go.sum` 固定,因此它依赖于构建来源证明,而不是 `checksums.txt`(已签名)。
验证下载的发布版本:
```
# 1. 对 checksum 文件的签名(keyless cosign)。将签名者固定到此
# repo 的 release workflow 以及 GitHub 的 OIDC issuer —— 通配符身份/issuer
# ('.*') 仅能证明签名本身是有效的,而不能证明是*我们*生成了
# 它,因此它会接受来自任何 Fulcio 身份的签名,从而使
# keyless verification 失去意义。
cosign verify-blob --certificate checksums.txt.pem --signature checksums.txt.sig \
--certificate-identity-regexp '^https://github\.com/aafeher/nftui/\.github/workflows/release\.yml@refs/tags/v' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
checksums.txt
# 2. 根据可信的 checksum 验证 archive
sha256sum --check --ignore-missing checksums.txt
# 3. build provenance(将这些字节绑定到此 repo 的 release workflow)
gh attestation verify nftui__linux_amd64.tar.gz --repo /nftui
```
要在不发布的情况下本地验证配置:
```
goreleaser check # config syntax only
goreleaser release --snapshot --clean --skip=publish,sign,sbom # build into dist/
```
`sign` / `sbom` 在本地会被跳过,因为它们需要 CI 运行器的 `cosign` OIDC 身份和 `syft`;来源证明仅限工作流使用。快照输出(`dist/`)被 gitignore 忽略,因此工作树保持整洁。
## 发布历史
各版本的发布说明位于 [CHANGELOG.md](CHANGELOG.md) 中,采用 [Keep a Changelog](https://keepachangelog.com/) 格式。迄今为止的主要里程碑:
- **v0.1.0** (2026-05-24) — 首个可发布的版本:完整的 CT / meta / IP / 端口匹配,所有 verdict 操作,完整的规则集 CRUD。
- **v0.2.0** (2026-05-24) — NAT 语句(`snat`、`dnat`、`masquerade`)、`queue`、`quota`。
- **v0.3.0** (2026-05-24) — 扩展的协议匹配(ICMP / ICMPv6、SCTP、DCCP、AH、ESP、COMP、Ethernet、VLAN、ARP、IPv6 扩展头)。
- **v0.4.0** (2026-05-24) — 集合、映射和命名对象。
- **v0.5.0** (2026-05-25) — 集合 / 映射 / 命名对象的完善与强化(interval-set 删除修复、dynset 标志、CIDR 支持、verdict 映射)。
- **v0.6.0** (2026-05-29) — 反馈渠道的一致性和瞬时提示的 UX:自动淡出的树状提示、统一的 Reset / Delete 错误路由。
- **v0.7.0** (2026-05-29) — 错误消息(`CAP_NET_ADMIN` 建议、被拒绝规则的显示)和导航(树状视图中的 `/` 搜索,`chainView` 中的 `/` 过滤)。
- **v0.8.0** (2026-05-30) — CLI 标志(`--table`、`--config`、`--read-only`、`--help`)、发布润色(CHANGELOG、man page)、`sctp chunk` 编辑器、异步增量加载。
- **v0.9.0** (2026-06-19) — 发布基础设施(集成测试工具、CI 工作流、虚拟化规则列表、Goreleaser 发布管道、Nix flake 打包)加上企业就绪的强化流程:供应链证明(cosign / SBOM / SLSA 来源)、CI 漏洞扫描、可选的突变审计日志、纵深防御标识符验证以及治理和部署文档(`SECURITY.md`、`CONTRIBUTING.md`、`CODE_OF_CONDUCT.md`)。
- **v1.0.0** (2026-06-20) — 首个稳定版本:拓宽了安装路径(Debian / RPM、Alpine / Arch / OpenWrt 包、Docker 镜像、社区 Gentoo / AUR 参考),证明了可重现性和 Nix-flake CI 通道,`--version` 标志,用于离线源码构建的 Go 模块依赖 tarball,以及 IPv6 源 / 目的地址渲染。
- **v1.1.0** (2026-06-21) — 终端适配与导航 UX,外加一轮安全 / CI 强化:80x24 最小限制以及边框限制和调整大小提示、备用屏幕渲染、规则编辑器中的滚动到焦点和规则视图中的滚动、紧凑的链标题;修复了退出时刷新规则集和规则渲染两次的问题;加入了 OpenSSF Scorecard / CodeQL / Codecov、Go fuzz 目标和 SHA 固定的 actions。
## 许可证
MIT — 详见 [LICENSE](LICENSE)。
标签:Awesome, EVTX分析, Go, netlink, nftables, Ruby工具, 日志审计, 系统管理, 终端UI, 请求拦截, 防火墙