docs: make targets and counts for the guard

desktop-test runs the 39 desktop tests in the backend venv (an absolute
path, so pytest does not warn about sys.prefix); the root README explains
that a '*' in the expansion list means every subdomain, and that the desktop
app answers the zones a hosts file cannot express.
This commit is contained in:
timka123 committed 2026-10-19 18:45:50 +03:00
1 parent 50e9c68b2f
commit 5c6710ae3d
2 files changed
+26 -15

No files matched your search

+4 -1
View File
@@ -30,6 +30,9 @@ web-build: ## Build the web UI into frontend/dist
desktop: ## Run the native desktop app against localhost:8000
cd desktop && python3 -m kadence_desktop
desktop-test: ## Run the desktop app test suite (uses the backend venv)
cd desktop && $(CURDIR)/backend/.venv/bin/python -m pytest -q
desktop-install: ## Install the launcher entry and icon for your user
./desktop/packaging/install-desktop.sh
@@ -61,4 +64,4 @@ deploy: ## Push master and redeploy kadence.timka.su on sw_pl_1
deploy-logs: ## Follow the production app log
ssh sw_pl_1 'cd /opt/kadence && docker compose -f docker-compose.yml -f docker-compose.prod.yml logs -f --tail 100 app'
.PHONY: help up down logs dev test backend-venv web-build desktop desktop-install helper-install android-test android-test-core android-build android-install report set-password deploy deploy-logs
.PHONY: help up down logs dev test backend-venv web-build desktop desktop-test desktop-install helper-install android-test android-test-core android-build android-install report set-password deploy deploy-logs
+22 -14
View File
@@ -58,13 +58,17 @@ Rules live on the server (edit them in the web app or the desktop app); the
native desktop app enforces them on your machine:
* **Websites** — `/etc/hosts` is rewritten through a tiny privileged helper under
polkit. No browser extension, no proxy, works for every app on the machine, and
you can audit it with `cat /etc/hosts`.
polkit, and the masks a hosts file cannot express are answered by a local DNS
stub the helper points `systemd-resolved` at, for the zones it can route. No
browser extension, no proxy, works for every app on the machine, and you can
audit the hosts region with `cat /etc/hosts`.
* **Masks** — `youtube.com` blocks the site plus `www.` and `m.`; `*.google.com`
blocks every subdomain in your expansion list (a hosts file has no wildcards,
so the app expands them for you and tells you when a pattern like `*gram*`
cannot be expressed that way). Exceptions take masks too, so `*.google.com`
blocked plus `*.docs.google.com` allowed does what you would expect.
blocks the bare domain plus every subdomain in your expansion list — add a bare
`*` to that list and "every" means every, answered by the DNS stub rather than by
guessed hostnames. A hosts file has no wildcards at all, so `*gram*` is reported
honestly as unenforceable on the machine rather than silently ignored.
Exceptions take masks too, so `*.google.com` blocked plus `*.docs.google.com`
allowed does what you would expect.
* **Applications** — `/proc` is watched and blocked apps are closed (or just
reported, if you prefer a warning). Entries here are globs as well: `steam*`,
`*discord*`, matched against the process name and its command line.
@@ -196,14 +200,15 @@ and you can fill everything in from **Settings**.
┌──────────────┐ │ • reports + achievements │ └───────────────┘
│ Desktop app │──/api──│ • scheduler (briefing, │
│ Qt/QML, D-Bus│ │ report, nudges) │───────▶ Telegram ⇄ you
│ hosts + /proc│ └───────────────────────────────┘
│ hosts+DNS+ │ └───────────────────────────────┘
│ /proc │ │
└──────────────┘ │
enforces Postgres
```
* `backend/` — FastAPI app. `app/services/` holds the thinking (timer, tasks,
stats, report, blocker policy, scheduler, bot); `app/sources/` holds one module
per integration; `app/api/` is a thin HTTP layer. 63 tests under `backend/tests`.
per integration; `app/api/` is a thin HTTP layer. 71 tests under `backend/tests`.
* `frontend/` — React + TypeScript + MUI, built by Vite into the backend image and
served from the same origin (so there is no CORS to configure).
* **The look** — warm paper, ink type, hairline rules instead of boxes and
@@ -214,7 +219,7 @@ and you can fill everything in from **Settings**.
has to stay readable for colour-blind readers in both themes.
* `desktop/` — the native app. See [`desktop/README.md`](desktop/README.md).
* `android/` — the phone client. Everything with interesting behaviour lives in a
plain-JVM `:core` module, so 225 tests run on a laptop with nothing but a JDK. See
plain-JVM `:core` module, so 234 tests run on a laptop with nothing but a JDK. See
[`android/README.md`](android/README.md).
---
@@ -226,6 +231,7 @@ make up # docker compose up --build
make dev # backend with reload + Vite dev server
make test # backend test suite
make desktop # run the native app from the checkout
make desktop-test # desktop app test suite (uses the backend venv)
make desktop-install # menu entry + icon
make helper-install # the privileged blocking helper
make report # build and send today's report right now
@@ -279,11 +285,13 @@ a login screen instead of a header the desktop app fills in for you.
## Security notes
* The desktop app never runs as root. The only privileged code is
`desktop/helper/kadence-helper` (~200 lines): it validates every hostname,
rewrites only the region between its own markers in `/etc/hosts`, writes
atomically, keeps a backup, and refuses anything that does not look like a
hostname. It is authorised by polkit (`auth_admin_keep` by default — one prompt
per session; `install.sh --passwordless` drops that for one user).
`desktop/helper/kadence-helper` (~250 lines) and it has exactly two jobs: it
validates every hostname, rewrites only the region between its own markers in
`/etc/hosts`, writes atomically, keeps a backup, and refuses anything that does
not look like a hostname — and it writes one drop-in for `systemd-resolved`
pointing the routable zones at the unprivileged DNS stub, which it removes again
before the stub stops. It is authorised by polkit (`auth_admin_keep` by default
— one prompt per session; `install.sh --passwordless` drops that for one user).
* Tokens live in the database and in `.env`, are masked in every API response,
and are never sent to the browser in full. The password is never stored at
all — only a salted PBKDF2 hash.