milestone 14: build, package, sign and publish releases

This commit is contained in:
2026-08-08 12:38:29 +02:00
parent 6c507992e4
commit cdacc560b7
48 changed files with 7272 additions and 543 deletions
+24 -6
View File
@@ -38,7 +38,7 @@ Serves a household LAN (≈220 devices). Portfolio-grade public repo with ext
- DNSSEC validation (DO bit passthrough only).
- DoQ (QUIC), HTTP/2 upstream transport.
- Clustering / distributed state.
- Prebuilt binaries / published Docker images / project website. Repo + documented build-it-yourself path only.
- Project website. The repository, its README and `docs/` are the whole published surface.
---
@@ -142,7 +142,8 @@ IPv4 + IPv6 full parity for: client identity, rate limiting, logging, group assi
### 3.15 CI
- Self-hosted **Gitea + Gitea Actions runner**.
- Jobs: `zig build test`, fuzz smoke, integration tests, OpenAPI contract tests (live server validated against `openapi.yaml`), frontend build, cross-compile both targets. aarch64 test execution via qemu-user if the runner is x86_64.
- Every blocking check lives in one reusable workflow, `.gitea/workflows/gates.yml`. `ci.yml` calls it on `master` pushes and pull requests; `release.yml` calls the same file before it publishes, so a release cannot skip a check that CI runs.
- Jobs: `zig build test`, fuzz smoke, integration tests, OpenAPI contract tests (live server validated against `openapi.yaml`), frontend build and tests, `dist` + `verify-dist` for both targets, and a container job that builds the image and asserts its binaries are byte-identical to the packaged ones. aarch64 test execution via qemu-user if the runner is x86_64.
---
@@ -568,7 +569,7 @@ Requirements: responsive desktop/mobile; route loaders for initial fetch; TanSta
- `nxdns check` — validate config, probe upstreams, load each enabled listener's certificate and verify its key pairs with it; exit 2 on failure, 0 with warnings.
- `nxdns export [--out file.zon]`
- `nxdns import <file.zon> [--force]`
- `nxdns version` — app version, Zig version string, build date, git commit.
- `nxdns version` — app version, Zig version string, git commit. No build date: the version and the commit identify a build exactly, and a date is one more input a reproducible build would have to pin.
---
@@ -635,7 +636,7 @@ Exit: documented deployment works end-to-end on the Pi 5.
- Blocklist lookup p95 < 1 ms.
- Cached response p95 < 5 ms.
- Memory with ~1M blocked domains < 100 MiB.
- Stripped static binary < 10 MiB per arch (excluding embedded frontend assets; < 15 MiB with them).
- Stripped static binary per arch: < 15,728,640 bytes with the embedded frontend assets, < 10,485,760 bytes without them. `zig build verify-dist` asserts both.
---
@@ -649,7 +650,24 @@ Exit: documented deployment works end-to-end on the Pi 5.
---
## 20. Success Criteria
## 20. Publication
The project publishes released binaries and container images from its own Gitea
instance. Building from source stays fully supported and documented; it is no
longer the only path.
- **Trigger.** Pushing an annotated, GPG-signed tag `vX.Y.Z` to `git.mial.net/mokhtar/nxdns`. Nothing else publishes. Pre-release tags are rejected.
- **Version.** The tag is authoritative. `build.zig.zon`'s `.version` must equal the tag, and the packaging gate asserts it. Nowhere else stores a version.
- **Artifacts.** Per architecture (`x86_64-linux-musl`, `aarch64-linux-musl`) a `.tar.gz` holding the stripped ReleaseSafe binary, `LICENSE`, `THIRD-PARTY-NOTICES` and the README. Plus one `SHA256SUMS` covering both tarballs and the image digest, and one detached `SHA256SUMS.asc`.
- **Images.** One multi-architecture image at `git.mial.net/mokhtar/nxdns`, tagged with the exact version and `latest`. No `:edge`. `latest` moves only forward. The builder stage runs on `$BUILDPLATFORM`, so no release build needs qemu.
- **Signing.** A GPG signing subkey held only by Gitea signs `SHA256SUMS`. The tag itself is signed by the primary key, and the release job pins that primary fingerprint before it does anything else. Verification is documented in `docs/how-to/verify-a-release.md`.
- **Gates.** `release.yml` runs `gates.yml` — the same file CI runs — and publishes nothing if any gate fails.
- **Licensing.** EUPL-1.2. `THIRD-PARTY-NOTICES` is generated from `licenses/inventory.zon` and a drift test fails when a dependency changes without a matching notice entry.
- **Deferred.** Bit-for-bit reproducibility across machines, and SBOM generation, are deliberate deferrals. See `specs/milestone-14.md` ruling 12.
---
## 21. Success Criteria
1. `nxdns run` starts cleanly on Zig 0.16.0 stable, static musl, both arches.
2. UDP + TCP resolution works; blocked domains return the configured response; precedence per §3.10.
@@ -667,7 +685,7 @@ Exit: documented deployment works end-to-end on the Pi 5.
---
## 21. Working Notes
## 22. Working Notes
- `dns/`, `filter/`, `local/`, `cache/` stay pure (no `Io`, no sockets). Servers, upstream clients, and storage take `io: Io`.
- Verify stdlib behavior against `../zig` (tag 0.16.0) instead of memory — the std.Io migration invalidated older knowledge once already.