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 desktop: ## Run the native desktop app against localhost:8000
cd desktop && python3 -m kadence_desktop 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-install: ## Install the launcher entry and icon for your user
./desktop/packaging/install-desktop.sh ./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 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' 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: native desktop app enforces them on your machine:
* **Websites** — `/etc/hosts` is rewritten through a tiny privileged helper under * **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 polkit, and the masks a hosts file cannot express are answered by a local DNS
you can audit it with `cat /etc/hosts`. 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` * **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, blocks the bare domain plus every subdomain in your expansion list — add a bare
so the app expands them for you and tells you when a pattern like `*gram*` `*` to that list and "every" means every, answered by the DNS stub rather than by
cannot be expressed that way). Exceptions take masks too, so `*.google.com` guessed hostnames. A hosts file has no wildcards at all, so `*gram*` is reported
blocked plus `*.docs.google.com` allowed does what you would expect. 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 * **Applications** — `/proc` is watched and blocked apps are closed (or just
reported, if you prefer a warning). Entries here are globs as well: `steam*`, reported, if you prefer a warning). Entries here are globs as well: `steam*`,
`*discord*`, matched against the process name and its command line. `*discord*`, matched against the process name and its command line.
@@ -196,14 +200,15 @@ and you can fill everything in from **Settings**.
┌──────────────┐ │ • reports + achievements │ └───────────────┘ ┌──────────────┐ │ • reports + achievements │ └───────────────┘
│ Desktop app │──/api──│ • scheduler (briefing, │ │ Desktop app │──/api──│ • scheduler (briefing, │
│ Qt/QML, D-Bus│ │ report, nudges) │───────▶ Telegram ⇄ you │ Qt/QML, D-Bus│ │ report, nudges) │───────▶ Telegram ⇄ you
│ hosts + /proc│ └───────────────────────────────┘ │ hosts+DNS+ │ └───────────────────────────────┘
│ /proc │ │
└──────────────┘ │ └──────────────┘ │
enforces Postgres enforces Postgres
``` ```
* `backend/` — FastAPI app. `app/services/` holds the thinking (timer, tasks, * `backend/` — FastAPI app. `app/services/` holds the thinking (timer, tasks,
stats, report, blocker policy, scheduler, bot); `app/sources/` holds one module 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 * `frontend/` — React + TypeScript + MUI, built by Vite into the backend image and
served from the same origin (so there is no CORS to configure). served from the same origin (so there is no CORS to configure).
* **The look** — warm paper, ink type, hairline rules instead of boxes and * **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. has to stay readable for colour-blind readers in both themes.
* `desktop/` — the native app. See [`desktop/README.md`](desktop/README.md). * `desktop/` — the native app. See [`desktop/README.md`](desktop/README.md).
* `android/` — the phone client. Everything with interesting behaviour lives in a * `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). [`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 dev # backend with reload + Vite dev server
make test # backend test suite make test # backend test suite
make desktop # run the native app from the checkout 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 desktop-install # menu entry + icon
make helper-install # the privileged blocking helper make helper-install # the privileged blocking helper
make report # build and send today's report right now 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 ## Security notes
* The desktop app never runs as root. The only privileged code is * The desktop app never runs as root. The only privileged code is
`desktop/helper/kadence-helper` (~200 lines): it validates every hostname, `desktop/helper/kadence-helper` (~250 lines) and it has exactly two jobs: it
rewrites only the region between its own markers in `/etc/hosts`, writes validates every hostname, rewrites only the region between its own markers in
atomically, keeps a backup, and refuses anything that does not look like a `/etc/hosts`, writes atomically, keeps a backup, and refuses anything that does
hostname. It is authorised by polkit (`auth_admin_keep` by default — one prompt not look like a hostname — and it writes one drop-in for `systemd-resolved`
per session; `install.sh --passwordless` drops that for one user). 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, * 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 and are never sent to the browser in full. The password is never stored at
all — only a salted PBKDF2 hash. all — only a salted PBKDF2 hash.