Housecarl will be a firewall manager for nftables, built the way Jarl and Steward are: housecarld (a daemon with a REST API and web UI), hc (the CLI) and SQLite. - The logo: a carved Nordic doorway in Jarl's blue (artwork/logo.svg), with a small version without the carvings, lighter on dark backgrounds. scripts/logo.py builds the web UI's copies and scripts/banner.py the README banner. - The HOUSECARL wordmark in Jarl's and Steward's angular letters, with new H, O, U and C (assets/brand.js), and the UI's color tokens. - housecarld and hc print their version; the Makefile, version package, AGENTS.md, CHANGELOG and the design sketch (docs/design.md). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
93 lines
3.9 KiB
Markdown
93 lines
3.9 KiB
Markdown
# Working on Housecarl
|
|
|
|
Notes for coding agents (and people) changing this repository. Read this
|
|
first, then [docs/design.md](docs/design.md), the plan and its open
|
|
questions.
|
|
|
|
Housecarl is a firewall manager for Linux: `housecarld` keeps the
|
|
machine's nftables ruleset and serves a REST API and a web UI; `hc` is the
|
|
CLI; SQLite holds everything. It is the third of a set with Jarl (the BIND
|
|
manager, `../jarl`) and Steward (the DHCP server, `../steward`) and copies
|
|
their ways: the same auth, socket and web UI helpers, the same release
|
|
process, the same look. When in doubt, do it the way Jarl and Steward do.
|
|
Go module `housecarl`, `CGO_ENABLED=0`, Linux only for housecarld.
|
|
|
|
Housecarl is at its start: only the version commands, the build and the
|
|
brand exist. Most rules below are for what is coming.
|
|
|
|
## Ground rules
|
|
|
|
* **The database is the source of truth.** The ruleset is rendered from
|
|
it; never read nftables' state back as configuration (an importer would
|
|
be the only exception).
|
|
* **Every change goes through one engine**: edit a copy of the
|
|
configuration, validate the whole result, render, check with
|
|
`nft -c -f`, apply with `nft -f`, and save the objects, the history
|
|
entry and the audit record together. Never write to the store from a
|
|
handler.
|
|
* **Housecarl's own table only.** Write `inet housecarl` and nothing
|
|
else; never flush the whole ruleset (Docker, libvirt and others keep
|
|
theirs).
|
|
* **Don't lock the user out.** Changes to the rules for the machine itself
|
|
are applied on probation and rolled back unless confirmed
|
|
(docs/design.md).
|
|
* **Every user-visible change updates `CHANGELOG.md`** under
|
|
`## [Unreleased]`, and the matching `docs/` page in the same change.
|
|
* **Errors** say what is wrong and how to fix it, naming the object.
|
|
* **Schema changes** append a migration; never edit a shipped one.
|
|
* `make test` runs `go vet` and a `gofmt -l` check. `goimports` isn't
|
|
installed, so fix imports by hand.
|
|
|
|
## The logo and wordmark
|
|
|
|
* The masters are `artwork/logo.svg` (the carved doorway) and
|
|
`artwork/logo-small.svg` (without its carvings, for under about 64 px).
|
|
Each is one evenodd path in a shared viewBox; their color comes from
|
|
CSS (`--logo`, lighter in the dark theme).
|
|
* `make logo` (`scripts/logo.py`) copies them into the web UI
|
|
(`assets/logo.js`, and `assets/logo.svg`, the favicon, from the small
|
|
one) and runs `scripts/banner.py`, which rebuilds `artwork/banner.svg`.
|
|
Never edit those outputs by hand.
|
|
* The wordmark's letters are paths in `assets/brand.js`, in the angular
|
|
style of Jarl's and Steward's (A, R and L are Jarl's, S and E Steward's).
|
|
`banner.py` reads them from there.
|
|
|
|
## Testing
|
|
|
|
```sh
|
|
make test # vet + gofmt check + unit tests
|
|
```
|
|
|
|
## Web UI rules
|
|
|
|
As in Jarl and Steward:
|
|
|
|
* Build DOM only with `h()` from `ui.js`, never `innerHTML`.
|
|
* The CSP is `self` only: no inline styles or scripts. Use a class, or set
|
|
`el.style.prop`.
|
|
* Colors are the CSS custom properties in `style.css`, with light and dark
|
|
values; reuse them.
|
|
* Rebuild housecarld after editing, since the files are embedded.
|
|
* Function over polish. Leave pick-list checkboxes unticked by default.
|
|
|
|
## Git and releases
|
|
|
|
The maintainer's rules:
|
|
|
|
* **Commit only when asked. Never push.** The maintainer pushes, to Gitea
|
|
at gitea.adbraun.lol.
|
|
* **Branches** are `dev-X.Y.Z`, never named like a tag.
|
|
* **A release** is a commit "Release X": it sets `VERSION`, updates the
|
|
README status line, and (for a final release) moves `[Unreleased]` to
|
|
`## [X] - YYYY-MM-DD`. The annotated tag is `vX` with message
|
|
"Housecarl X".
|
|
|
|
## Shell hygiene
|
|
|
|
* **Never kill processes by pattern** (`pkill -f`). The pattern matches
|
|
the shell running it. Find the PID with `ps` and kill that.
|
|
* **Run long-lived test servers in the background mode of your tool**, not
|
|
with `&` in a shell that exits.
|
|
* **Never apply a test ruleset to this machine's own nftables.** Test in a
|
|
network namespace or a container.
|