Repository navigation
Releases
v0.44.5
0.44.5
Who should upgrade
Every host on 0.44.0. 0.44.5 fixes the installer and the uninstaller,
start-up and shutdown, device identification by MAC address, backup and
restore, and the terminal UI. It changes no configuration schema.
Upgrade soon if:
- you script installs or run them without a terminal: the installer now
makes its refusals before it turns off the systemd-resolved stub or
installs Warden, and its exit statuses say what happened (see
Exit statuses); - a host serves many clients: the service unit raises the open-file limit,
and the daemon asks for a larger UDP receive buffer; - you use Nodes: a list cached before 0.41 is no longer dropped from the
node workspace, and a primary whose API address arrives late no longer
exits at boot; - you uninstalled Warden and plan to install it again: a configuration that
uninstall.shkept is now adopted instead of refused.
A host on 0.41.x, 0.42.0 or 0.43.0 can upgrade straight to 0.44.5. Read the
0.44.0 notes
first: they cover what such a host must know before it upgrades, and
everything in them is new to it too.
How to upgrade
Fetch the installer fresh and run its upgrade mode:
curl -fsSL https://get.purge.cc | sudo sh -s -- --upgrade- From 0.41.x, upgrade in place with
--upgradetoo. Do not uninstall
first. - From an unpacked bundle, run
sudo ./scripts/install.sh --upgrade --binary ./wardenin the bundle
directory. - To preview, add
--dry-run.get.shnow hands the flag to the installer
once. - Over an existing install,
get.shnow runs the installer's
existing-install check before it replaces the installed bundle. If that
check refuses, the installed bundle stays, andget.shexits with the
installer's status. Before, such a refused run left the new bundle in
place and deleted the old one. A refusal from a later check, such as the
upgrade check, the configuration check or the network check, still comes
after the swap.
WhenPURGE_VERSIONpins a release whose installer predates these
checks,get.shskips them, prints one line that says so, and keeps the
0.44.0 order. - If you run Warden under your own unit file instead of the shipped one,
addLimitNOFILE=65536to it. The shipped unit now sets it; a drop-in
that sets a lowerLimitNOFILEoverrides it.
Exit statuses
install.sh --help now lists them:
| Status | Meaning |
|---|---|
| 0 | Success. |
| 2 | Invalid arguments. With --upgrade: a prerequisite of the upgrade check is missing or wrong, such as the dig tool or a setting; nothing was changed, and the message says which. |
| 3 | Fresh install: installed, but the service was still loading its blocklists when the wait ended, so DNS was not verified. Nothing failed: watch it with journalctl -u purge-warden -f. With --upgrade: the upgrade check refused the new version before anything was changed. |
| 5 | Installed, but the service stopped while it was starting, or DNS resolution or filtering failed verification. |
| other | Refused or failed; the message says which. |
A fresh install now waits up to 600 seconds, counted in real time, for the
first list download. A slow download ends with exit status 3 and the
commands to watch it finish, instead of exit status 5 and a message that
blamed the upstream resolver.
Before you upgrade
- Scripts without a terminal. On a host where systemd-resolved holds
port 53, an install without a terminal now refuses and names--yes.
Before, it stopped at the question with a message that blamed another
service. Add--yesto such scripts. The installer asks at the end of
its preflight checks and turns the stub listener off only after its last
refusal, so a refused install no longer has already turned off the
systemd-resolved stub listener. - A configuration kept by
uninstall.sh(without--purge).
install.shnow adopts it: it checks it with the new binary and keeps it,
and the--lan-cidrflag and the other first-install settings do not
apply. A schema-4 configuration
kept this way is refused until it is migrated: the refusal names the
section "Schema-4 config kept by uninstall.sh" of
docs/UPGRADE_RECOVERY.md, which migrates it offline with the bundle's
binary. A schema-3 configuration kept this way has no migration route:
rununinstall.sh --purgeand install again. The installer checks a kept
configuration after it has installed thedigand CA certificate
packages it needs, so a refusal can leave those packages installed. To
start from scratch instead, rununinstall.sh --purgefirst. - A stray backup directory. If an earlier release left
/etc/purge-warden/backupson a host whose[backup] dirpoints
elsewhere, check withls -ld /etc/purge-warden/backupsand move it out
of/etc/purge-wardenas root: the next backup would archive it. - A daemon home left by an older
--purge. Hosts purged with
uninstall.sh --purgefrom 0.44.0 or older may still have a
/home/purge-warden(or/home/purge-shield) directory owned by a
deleted account. The installer now warns about it. If you do not need its
files, remove it withsudo rm -rf --one-file-system /home/purge-warden.
Changes
Installer
- A host with another program on port 53 next to the systemd-resolved stub
is refused before the stub is turned off. The refusal names that
program's line inssand says the stub change would not free it. - A configuration path that is a dangling link or a directory is refused
before the installer changes anything. - A configuration kept by
uninstall.shthat fails the new check names its
schema, says that--upgradecannot run on that host, and names
uninstall.sh --purgewith what it deletes. The exit status stays 6. - The network check before an install now tests
lists.purge.cc, which the
first start needs for the blocklists, instead of a distribution mirror. --dry-runno longer prints success marks for steps it skipped. A
fresh-install preview ends withDry run complete, and shows the home and
token steps instead of warning that the user and the configuration are
missing.- The refusal over an existing install names a command that works where you
run it: the get.purge.cc one-liner afterget.sh,
--upgrade --binary <bundle directory>/wardenin a bundle. An incomplete install namesuninstall.sh(which keeps the
configuration for the next install) instead of--upgrade, which refuses
it. - Hints printed during a
get.shrun name the installed bundle, not the
temporary copy thatget.shdeletes when it ends. - When the installer exits early, its last lines still reach the screen and
the log. - The check for the systemd-resolved stub no longer misses it from time to
time. Before, an install could stop withport 53 is already in useon a
host where only the stub held the port. install.sh --helpsays what--upgradedoes and lists the exit
statuses.
Uninstaller
uninstall.sh --restore-resolvedpoints/etc/resolv.confback at the
systemd-resolved stub when it is the absolute link to
/run/systemd/resolve/resolv.confthat the installer writes and the stub
listens after the restart. Otherwise it warns and leaves the link.uninstall.sh --purgeremoves the daemon home thatinstall.shcreated
(/home/purge-wardenor/home/purge-shield, owned by the daemon user).
It leaves any other home in place with a warning, and for a home outside
those two paths says to remove it by hand if it was the daemon's.uninstall.sh --purgerun from the installed bundle says that the bundle
in/usr/local/lib/purge-wardenremains and prints the command to remove
it.- Without
--purge,uninstall.shrefuses to keep a configuration in the
middle of a migration or a relocation: the next install would refuse it,
and the binary that finishes the step would be gone. The refusal names the
command that prints the next step. uninstall.shremoves the.s6-oldcopies that an interrupted upgrade left
next to the binary and the unit files. They blocked a later--upgrade.- On a host with firewalld,
uninstall.shsays when DNS is still allowed
and prints the commands to close it:
sudo firewall-cmd --permanent --remove-service=dns && sudo firewall-cmd --reload. --dry-runno longer reports removals it only previewed.- The
--purgehelp and the removal plan name where each token lives: the
plaintext IPC token and the cluster token under/var/lib/purge-warden,
the token hashes andsecrets.tomlunder/etc/purge-warden.
Start-up, reload and shutdown
- A standalone host (no cluster) keeps serving DNS when the node corpus
store cannot open, and logs an error. It runs without the node corpus:
list bodies held only in a parser cache need a download. A stray entry in
the corpus cache no longer stops a start, a reload or a node command. A
host with a cluster still refuses to start. - A change to the global
[local_dns]section applies on reload. Before, it
needed a restart, and every later reload was refused until then. - Messages for a change that needs a restart now say that the daemon refuses
every later reload until that restart. In the terminal UI, a Tracking save
that changes the retention or the log mode shows this as a warning. - Any entry in
packs/that is not a pack file (<id>.txt), such as an
editor swap file, a backup file or a subdirectory, is ignored with a
warning instead of failing the next start.warden statuslists such
entries. Backups leave them out and print the same warning. - The boot refusal for a configuration that does not load names the next
step: lint, restore (when an archive exists) and restart. The refusals for a relocation in
progress, a secrets file with the wrong mode and the secondary bootstrap
end with ...
v0.44.0
0.44.0
Who should upgrade
Every host on 0.41.x, 0.42.0 or 0.43.0. 0.42.0 and 0.43.0 were
pre-releases, and get.purge.cc served 0.41.0 as its stable version, so most
hosts come straight from 0.41.0. If yours does, everything in 0.42.0 and
0.43.0 is new to you too: read the 0.42.0 and
0.43.0 notes first. The notes below cover what changed since
0.43.0 and what a 0.41.0 host must know before it upgrades.
Upgrade a 0.42.0 or 0.43.0 host soon if Warden's files are on btrfs, or on
another filesystem that can renumber its device at boot (ZFS, NFS, overlayfs,
device-mapper). On those hosts, a reboot after a policy change could stop the
daemon with receipt identity mismatch and leave DNS down. 0.44.0 no
longer compares the device number. A host already in that state can upgrade:
see From a failed daemon.
How to upgrade
Fetch the installer fresh and run its upgrade mode:
curl -fsSL https://get.purge.cc | sudo sh -s -- --upgrade- Do not rerun a copy of
get.shsaved from 0.41.0 or 0.42.0. The bundle
shipsdocs/UPGRADE_RECOVERY.md, and those copies refuse it with
the bundle contains an unexpected path. They install nothing. - To preview the upgrade, add
--dry-run:
curl -fsSL https://get.purge.cc | sudo sh -s -- --upgrade --dry-run.
The preview now changes nothing. Before,--dry-runon the command line
replaced the installed bundle. - From an unpacked bundle, run
sudo ./scripts/install.sh --upgrade --binary ./wardenin the bundle
directory. - Source installs: build with
cargo build --release, then run
sudo ./scripts/install.sh --upgradefrom the checkout.make installis
for a first install only and skips the configuration check.make upgrade
from a 0.43.0 or older tree overwrites thewardenwrapper and skips the
check. The daemon kept running the old version. To fix such a host, run
sudo ./scripts/install.sh --upgradefrom the new tree; it upgrades the
daemon and puts the wrapper back.make upgradefrom the 0.44.0 tree
refuses such a host and changes nothing. - get.purge.cc publishes the bundle for x86_64 only. On aarch64,
get.sh
stops withdownload failedand points at building from source. Build as
BUILDING.mddescribes, then run
sudo ./scripts/install.sh --upgrade --binary <path>from the checkout, or
sudo ./scripts/install.sh --upgrade --build-from-source.
The upgrade still runs as one transaction: it checks the configuration with
the new binary first, migrates a 0.41 configuration, starts the new version,
and checks that it answers and blocks. If a step fails, it puts the old
version back. If it ends with exit status 75 or RECOVERY REQUIRED, or a
crash or power loss stopped it, follow docs/UPGRADE_RECOVERY.md. The file
ships in the bundle, under /usr/local/lib/purge-warden/docs/ for a
get.purge.cc install.
From a failed daemon
On a 0.42.0 or 0.43.0 host, the upgrade now also accepts a daemon that
systemd reports as failed, so you can upgrade a host whose installed
version no longer starts. A 0.41.x host still needs a running daemon.
activatingmeans systemd is still retrying: wait until
systemctl is-active purge-warden.serviceprintsactiveorfailed.inactivemeans the daemon was stopped: start it, then upgrade.- A host that resolves names through its own Warden resolves nothing while
the daemon is down, so the download fails. Add a temporarynameserver
line to/etc/resolv.conffor the upgrade, and remove it afterwards. - If the new version fails its check, the upgrade puts the old version back,
starts it once and exits withthe exact old ELF and unit were restored.
See "Upgrading a failed daemon" in docs/UPGRADE_RECOVERY.md.
Cluster secondaries on 0.41
A 0.41 cluster secondary still cannot be upgraded in place. The upgrade
refuses it with nothing changed. Its cluster_local_policy_conflict finding,
listed by the command the upgrade prints
(<candidate-elf> --config <master> migrate v4-to-v5 --check --json), now
gives the steps. Take the node out of the cluster, upgrade both nodes, then
join again:
- On the secondary, still on 0.41, run
warden cluster leave. If it asks
for a resolver, runwarden cluster leave --upstream <addr:port>. - Upgrade the secondary as a standalone node.
- Upgrade the primary.
- On the primary, run
warden cluster create --migrate-legacy --san <primary address>, then
warden cluster apply --preview-id <id>, then
systemctl restart purge-warden. If the primary's API is off or listens
on loopback, add--api-listen <addr:port>with an address the secondary
can reach. - On the primary, run
warden cluster invite. - On the secondary, run
warden cluster join --peer <primary https origin> --invitation-file <file>,
thenwarden cluster apply --preview-id <id>, then restart it.
See "Cluster secondaries" in docs/UPGRADE_RECOVERY.md.
Before you upgrade
- Wildcard, regex and
$importantrules (0.41). Configuration schema 5
reads some of these rules differently. If the check finds one, the upgrade
stops with nothing changed and prints the command that lists the findings.
You can now accept them: list the findings with the command the upgrade
prints (<candidate-elf> --config <master> migrate v4-to-v5 --check --json),
write a choices file, and run the upgrade again with it:
curl -fsSL https://get.purge.cc | sudo WARDEN_UPGRADE_MIGRATION_CHOICES=/root/choices.json sh -s -- --upgrade.
Put the variable aftersudo, not before it. A finding that allows only
defercannot be accepted. See "Migration findings" in
docs/UPGRADE_RECOVERY.md. - IP blocklists. If
[ip_blocklists]is enabled, every source must be a
publichttps://URL, with no user name or password and no private or
loopback address. 0.41 skipped such sources with a warning, so they
filtered nothing; 0.42.0 and 0.43.0 refused to start.warden config lint
and the upgrade check now refuse them, and the upgrade stops with nothing
changed. Change each such source to a publichttps://URL without a
user name or password, or remove it, first. - Backups made by 0.41. 0.44.0 restores only schema-5 archives. It
refuses an archive from 0.41 or earlier with a message such as
schema-4 archive (Warden 0.41 or earlier); live config untouchedand
explains how to copy its settings by hand. If you may need one of those
archives, restore it before you upgrade. Runwarden config backuponce
the upgrade is done. - Disk space. Each policy write keeps undo data in the configuration
directory for at least 24 hours. It is now capped at 2 GiB per
configuration. A write that would pass the cap is refused with
UndoStoreFulluntil older data expires. The REST API answers such a
refusal with 429 instead of 503. - Anti-bypass is now off by default. Up to 0.43.0 it was on by default
but blocked nothing withoutextra_domains, so filtering does not change. A
section that listsextra_domainskeeps it on.enabled = truewith no
domains still warns. To stop the warning, list the resolver names to
refuse inextra_domains, or setenabled = false.
warden lists add services/resolversadds a resolver list as an ordinary
block list instead; it does not feed anti-bypass.
Changes
Upgrade and rollback
- The upgrade saves the publication store
(.warden-cluster-publicationsin/var/lib/purge-warden) before the new
version starts, and puts it back if the upgrade rolls back. It prints the
copy aspublication store snapshot: <dir>, under
/var/tmp/purge-warden-store.*. On a node with the cluster enabled where
the new version published a newer policy epoch, the upgrade does not put
the store back: it exits 75 withRECOVERY REQUIRED, and you follow end
state c indocs/UPGRADE_RECOVERY.md. See "Publication store snapshot"
indocs/UPGRADE_RECOVERY.md. - When the migration check blocks, the message now names
WARDEN_UPGRADE_MIGRATION_CHOICESand the "Migration findings" section. - A configuration with a
[[retired]]entry dated in the past now upgrades.
The check no longer reports the date as being in the future. .s6-oldfiles left by a killed upgrade still make the next upgrade
refuse with nothing changed. The steps it prints now include putting the
publication store back.
Start-up and reload
systemctl reloadduring start-up no longer stops the daemon. A reload
received while the daemon starts is applied once DNS serves. Before, it
ended the process and systemd did not restart it.- If the REST API certificate or key cannot be read at start, Warden logs
the error and serves DNS with the REST API off, instead of restarting in a
loop. A primary created withwarden cluster createstill refuses to
start. - Nodes start-up steps that fail, for example on a busy configuration lock
or a damaged Nodes state, no longer stop a daemon that serves DNS. They are
retried every 2 seconds and shown asProblem:lines in
warden node statusuntil they succeed. - A Nodes listener that cannot be restored at start (address gone, port
taken) is skipped and shown as aProblem:line inwarden node status.
DNS and the other listeners keep serving. warden start --safe-modeno longer exits whenconfig.tomlis invalid.- A primary or standalone host now starts when a list has no downloaded copy
yet (for example a list added while the daemon was stopped), or when its
node-corpus bookkeeping fails. It logs the problem and serves DNS with the
lists it has, instead of restarting in a loop. - An ...
v0.43.0
Superseded by v0.44.0: upgrade with https://get.purge.cc.
0.43.0
Coming from 0.41.0
If you upgrade from 0.41.0, everything in 0.42.0 is new to you too: Warden
Nodes (beta), the reworked terminal UI, and the new operator rules with
configuration schema 5. Read the 0.42.0 notes for those
changes. The notes below cover what is new since 0.42.0, and how the
upgrade from 0.41.0 works now.
Upgrading
Upgrade an existing install with the installer's upgrade mode:
curl -fsSL https://get.purge.cc | sudo sh -s -- --upgradeor sudo ./scripts/install.sh --upgrade from an unpacked bundle or a
checkout. Without --upgrade the installer refuses a host that already has
Warden and tells you to rerun it with the flag.
0.41.0 keeps its configuration at schema 4, and 0.43.0 needs schema 5. The
upgrade now migrates the configuration inside its own transaction, so the
manual warden migrate v4-to-v5 step that the 0.42.0 notes asked for is not
needed on this path. In order, the upgrade:
- checks the configuration with the new binary, before it changes anything;
- stops the daemon and the scheduled backup, and keeps the old binary and
service unit; - plans and applies the migration;
- installs the new binary and unit, starts them, and checks that the new
daemon answers and blocks; - only then finalizes the migration.
If the check finds something that blocks the migration, the upgrade stops
before it changes anything and prints the command that lists the findings. A
failure, or a Ctrl-C, a hangup or a plain kill (SIGTERM) before the final
step, rolls the configuration back and starts 0.41.0 again. The migration
moves the allow and deny rules you added in 0.41.0 into Custom Lists. The
old allow and deny commands now refuse to write: create a Custom List with
warden custom-list and mount it on a profile with warden profile mount.
The health check expects the new daemon to answer on the loopback address,
resolve one name and block another with a 0.0.0.0 answer. If your setup
answers blocked names in another way, or blocks everything, read "How the
upgrade runs" in docs/UPGRADE_RECOVERY.md before you upgrade. An upgrade
that fails the check rolls back.
If the upgrade ends with exit status 75 (most of these messages say
RECOVERY REQUIRED), or was stopped by a crash or a power loss, follow
docs/UPGRADE_RECOVERY.md. It ships in the bundle as
docs/UPGRADE_RECOVERY.md, under /usr/local/lib/purge-warden/docs/ for a
get.purge.cc install. Some installer messages name the section to read;
otherwise start at "End states after exit 75", or at "Killed or crashed
upgrades" after a crash or power loss. The manual warden migrate v4-to-v5
commands are described there as a recovery tool, not as an upgrade step. A
file left with the .s6-old suffix by a killed upgrade makes the next
upgrade refuse before it changes anything, with the steps to recover.
Also in the upgrade:
- A host already on 0.42.0 has schema 5, so the upgrade runs no migration.
It replaces the binary and the units. --upgradeno longer needs a LAN range (--lan-cidr), and its plan no
longer lists the settings that only a fresh install uses (LAN range,
listen address, upstream, lists, run user).- Starting 0.43.0 on a schema 4 configuration, or running
warden config linton one, now says thatinstall.sh --upgrade
migrates it. - If a signal stops the installer after the upgrade has committed, it says
so and exits with status 4. The new version is installed and running; run
the same command again to finish the remaining steps. - The upgrade keeps your configuration where it is. A host installed before
0.43.0 keeps/var/lib/purge-warden/config.toml; see
Configuration under /etc/purge-warden. - On such a host the installer prepares the
backupsdirectory as the
purge-wardenuser. Abackupsdirectory that is a symbolic link is
left as it is, with a warning.
Before you downgrade
- Open the dashboard once (
warden dashboard). If it shows Policy recovery,
pressr(Recover) until the change is committed or aborted. The 0.42.0
dashboard cannot read the recovery record that 0.43.0 writes for an
interrupted batch of Query Log rules. - If you moved the configuration with
warden config relocate, move it back
first withconfig relocate --reverse, run the same way as the move (see
below). Releases before 0.43.0 do not know the move. - 0.41.0 cannot read a schema 5 configuration. Once the upgrade has
finalized the migration, a 0.41.0 binary cannot start on it.
Query Log: hold rules, apply them together
In the Query Log, Enter on a row opens the rule dialog. Its Hold rule button
now holds an ALLOW or DENY rule for that domain on the Custom Lists you
pick, instead of opening a plan for that one domain. A "HELD RULES — NOT
ACTIVE YET" card shows how many rules are waiting. You can hold up to 32
rule-and-list pairs at a time, fewer if the daemon allows fewer, for one or
more domains, on the same list or on different lists.
Press v to review them. The held rules are a table with ACTION, DOMAIN and
LIST columns: ←/→ pick a cell, and e or a click on the selected cell edits
the action, the domain or the lists. An edit is checked like a new hold, and
Esc drops it. Delete or Remove takes one rule out, Discard all drops them
all after you confirm, and Review all shows a single plan. Apply saves every
held rule as one change with one reload, instead of one apply per domain.
Held rules do nothing until you apply them, and they live only in the open
dashboard session: quitting discards them, after asking first. An Apply
already submitted may still complete; the next warden dashboard shows its
outcome. If an apply fails or is cancelled, every held rule stays held.
Creating a New List from the picker is still a separate change with its own
plan and Apply. On a read-only node, apply rules on the primary.
Configuration under /etc/purge-warden
A fresh install, from the installer or from warden init without
--config, now creates the configuration at
/etc/purge-warden/config.toml. The files it includes, such as Custom List
packs and list files imported from this machine, sit beside it. Downloaded
list caches, data and node state stay under /var/lib/purge-warden, and the
new configuration sets
[backup] dir = "/var/lib/purge-warden/backups" for backup archives.
An existing host keeps /var/lib/purge-warden/config.toml, and no second
configuration is created. warden init refuses to create one under /etc
while the old one exists.
Moving an existing configuration: warden config relocate
warden config relocate moves the configuration of a host installed before
0.43.0 from /var/lib/purge-warden to /etc/purge-warden. Moving is
optional, and the upgrade never does it for you.
- It runs offline and as root. Stop
purge-wardenand
purge-warden-backup.timerfirst, and run the real binary,
/usr/local/libexec/purge-warden/warden. Thewardencommand on your
PATHruns as the service user, which the move refuses.--configis
refused too: the two paths are fixed. - Run
warden config backupfirst. The move also refuses a configuration
without an absolute[backup] dir. --dry-runruns every check and prints the plan, and moves nothing.- Every file moves by rename, so it keeps its owner and mode.
/etcand
/var/lib/purge-wardenmust be on the same filesystem and mount;
otherwise the move refuses and changes nothing. - Node identity and cluster pairing survive the move. List files imported
from this machine move with the configuration; downloaded list caches,
state and backup archives stay in/var/lib/purge-warden. - When
restoreconis installed, the move relabels the new location. - A run that stops part way prints the one command that rolls it back, and
the daemon refuses to start until that command has run. --reversemoves the configuration back to/var/lib/purge-warden.
After the move, start purge-warden and the backup timer again, and wait
until warden status answers. warden config relocate --help lists the
exit codes.
Rewrite and negative answers
A rewritten answer that holds records starts with a CNAME from the name the
client asked for to the rewrite target. Two things change:
- The CNAME always names the target you configured, the one policy checked.
Before, it took the name from the first upstream record. Fresh, cached and
stale answers behave the same. - A rewrite whose upstream chain leads back to the name the client asked for
is refused and answered as blocked. The rewrite step also counts toward
the CNAME chain limit,[cache] cname_max_depth.
An NXDOMAIN answer whose upstream answer holds CNAME records now keeps them,
with the NXDOMAIN code and an SOA record. Before, the answer section was
emptied. For a rewrite, the CNAME from the asked name to the target is kept
too. An NXDOMAIN or NODATA answer with no records still has an empty answer
section, with no rewrite CNAME.
Nodes
On a primary, a change that touches only policy now applies without
rebuilding the list corpus. This holds when the lists are unchanged and IP
blocklists are off before and after the change. Turning IP blocklists on or
off, or changing a list, still rebuilds. If the commit fails after the new
policy is swapped in, the change is not reported as applied.
Backups
- On a node whose configuration is still under
/var/lib/purge-warden,
warden config backuprefused list files that the node also hard-links
into its list corpus. It now archives them, and still refuses any other
hard link. - On Fedora 44 every scheduled back...
v0.42.0
Superseded by v0.44.0: upgrade with https://get.purge.cc.
0.42.0
Warden Nodes — policy and list synchronization (BETA)
Warden can now run as a cooperating set of nodes instead of a single
resolver. One node acts as the primary; the others join it, authenticate,
and receive its policy and blocklist state, so a change made once is
reflected everywhere without hand-copying configuration between machines.
Onboarding is guided: the primary issues a short-lived association token,
the joining node presents it, and the pair establishes an authenticated,
certificate-pinned channel. Nodes are durable — they survive restarts and
reappear with their last known state rather than vanishing from the
cluster.
This is a beta. It is off unless you configure it, a single-node
install is completely unaffected, and the synchronization protocol may
still change incompatibly between releases. Try it on machines you can
afford to re-provision, and report what breaks.
Reworked terminal UI
The Dashboard and Query Log have been rebuilt around the layouts operators
actually kept open.
- The Dashboard presents block rate, traffic, query types, upstream and
memory state as consistent cards with explicit labels, responsive
scrolling, and hour/date inspection — and keeps real warnings in the
header instead of hiding them behind decoration. - The Query Log has one filter row (Domain, Client, Period, Blocked, and
an Advanced view), a single-key picker, a 3-hour preset, and shared
modal styling throughout. Long error messages no longer destroy your
in-progress form input; drafts survive. - Device labels are now persistent, named categories you can reorder from
the Configuration view, and device dialogs follow the same layout rules
as the rest of the interface. - Polling and disk writes moved off the input event loop, so the
interface stays responsive while it refreshes.
Safer operator rules and configuration changes
The policy engine behind operator-defined rules has been reworked end to
end, with an emphasis on never leaving the daemon in a half-written state.
- Policy writes are transactional: a change either applies completely or
not at all, and a failed write cannot strand a partial rule set. - The configuration schema has moved forward (v4 → v5). The migration is
deterministic and keeps a backup; a daemon that cannot migrate refuses to
start on the unknown schema rather than guessing. - Reloads are generation-safe: a new configuration is validated as a
complete generation before it replaces the active one, so a broken
reload keeps the last good policy serving. - Cluster policy artifacts are coherent across nodes: every member of a
synchronized set evaluates the same policy generation.
Existing v4 configurations need one manual step before the new daemon will
start: run warden migrate v4-to-v5 --check to preview the migration, then
apply it. The daemon deliberately refuses to boot on a v4 file instead of
guessing at your intent.
Fixes
- Draft text in TUI forms is preserved across long profile errors,
refreshes, and view changes. - DoH upstreams that require HTTP/2 now work; previously such providers
answered every query with a failure while the daemon reported healthy. - The security update to the HTTP/2 dependency (
h20.4.16) is included.
v0.41.0
0.41.0
List refresh integrity
List updates now take a more deliberate path from download to the active
corpus. The aim is to keep a working list set available while an update is
being checked, and to refuse incomplete or inconsistent data before it can
replace that set.
Refreshes publish as complete generations
Each configured source is resolved to one canonical identity before refresh.
Conflicting aliases are rejected during configuration checks and strict
startup. A reload that finds a conflict keeps the active configuration rather
than replacing it with an invalid one.
Cache data is admitted and published as a complete, validated generation, not
as a mixture of old and new source bodies. A refresh checks staged input before
it becomes active. If a refresh is refused or fails, an already accepted corpus
remains available instead of serving a partial update. Storage errors during
staging also prevent that generation from being published.
The refresh status distinguishes a degraded refresh from a healthy one and
keeps retrying within bounded work. Forced refresh requests for the same list
manager join existing work instead of starting competing writers.
Lower-peak refresh path, with explicit limits
With a cache directory enabled, decoded HTTP data streams into a private
disk-backed generation. The parser and shard builder then work from staged
data, and publication waits for complete validation. This avoids retaining a
whole downloaded body and a whole replacement corpus on the normal refresh
path at the same time.
Input bodies, entries, parser lines, and format detection all have limits.
Size calculations fail safely on overflow, and staged content is checked again
before publication. URLs with embedded credentials are rejected before cache
metadata is accepted, while cache identity continues to use the exact resolved
URL.
This is bounded streaming, not a fixed process-memory promise. Peak memory
still depends on the installed domain set, configured limits, allocator
behavior, and operating-system cache. Running without a cache directory keeps
a supported, memory-resident fallback bounded by the configured body limit,
but it is not the lower-peak refresh mode.
Safer configuration changes and recovery
Configuration writes are serialized so concurrent commands do not overwrite
one another. The configuration format upgrade is transactional and
crash-safe, with recovery controls for an interrupted change. Existing
configurations retain their active state if validation cannot complete.
Dependency maintenance
The HTTP/2 implementation was updated to close RUSTSEC-2026-0258, which could
allow a peer to consume resources with an unbounded stream of empty DATA
frames.
Together, these changes make list refreshes easier to reason about: updates
become visible only as complete validated results, failures preserve the last
accepted data where available, and status reports show when refresh work needs
attention.