style: format docs, fix user_permissions variable scoping in auth middleware

Apply ruff line-wrapping formatting to docs and test files.
Clarify auth middleware: extract user_permissions once before
subsystem check, removing conditional variable scoping.
This commit is contained in:
2026-07-27 18:37:11 +00:00
parent d4213fb93b
commit ca110c321d
9 changed files with 640 additions and 26 deletions
+53 -3
View File
@@ -42,7 +42,7 @@ All settings that can be passed as an environment variable also have a CLI flag
|---|---|---|---|
| -- | `MGMT_DOMAIN` | No | Domain for the management WebUI. Defaults to `$hostname.local` (mDNS). Auto-detected from system hostname. **Errors if hostname is undetectable and this is not set.** |
| `--mgmt-domain` | `MGMT_DOMAIN` | No | (same as above) |
| `--mgmt-pass` | `MGMT_PASS` | Yes | Password for HTTP basic auth protecting the WebUI. |
| `--mgmt-pass` | `MGMT_PASS` | Yes | Password for the initial admin user (default: `admin`). Creates the admin user in the SQLite database with full `rw` permissions on all subsystems. |
| `--mgmt-user` | `MGMT_USER` | No | Username for WebUI access. Defaults to `admin`. |
| `--user, -u` | `USER_NAME` | Yes* | WebUI service user (created if it does not exist). Required for non-dev mode. In `--dev` mode, auto-detected from repo owner. |
| `--path, -p` | `INSTALL_DIR` | No | Install directory. Defaults to repo root. Set to deploy from a custom path (e.g., `/opt/vacuum-wall`). |
@@ -115,7 +115,7 @@ The installer performs the following steps automatically:
- **mDNS broadcast**: Enables and starts avahi-daemon so the appliance advertises its hostname (`<hostname>.local`) on the local network.
- **Self-signed certificate**: Generates a temporary self-signed X.509 certificate for the management domain with the correct CN and SAN, placed where acme.sh would store a real cert. Skips if a certificate already exists (preserves real ACME certs).
- **Management proxy configuration**: Calls the daemon API (`POST_NGINX_DOMAINS_ADD`) to register the management domain as a regular proxy entry with paths-based config (`/` → Flask, `/ws` → WebSocket). Then applies nginx via `POST_NGINX_APPLY`.
- **Credentials**: Generates an htpasswd file using `apache2-utils` (with a Python fallback) for the management proxy's basic auth. Updates existing file if already present.
- **Admin user**: Creates the admin user with the password provided via `--mgmt-pass` in the SQLite database (`data/auth.db`). The user gets `rw` permissions on all subsystems. On re-run, updates the admin password if already present.
- **Initial configs**: Firewall config and nginx proxy config are written via daemon API (skips if already exists).
- **System config import**: On startup, the daemon reconciles any live system configurations (dnsmasq, wireguard, networkd, nginx, firewall) with the declarative JSON configs. This prevents drift when system files were edited manually.
- **Systemd units**: Installs four units (rendered from Jinja2 templates):
@@ -137,7 +137,7 @@ The installer performs the following steps automatically:
- Restarts `vacuum-walld`, `vacuum-wall`, and reloads `nginx` to pick up changes
- Preserves existing SSL certificates (skips self-signed generation if a cert exists)
- Preserves existing `config.json` files (skips initial write if file exists)
- Safely updates `htpasswd` (uses update mode instead of create mode)
- Updates admin user password if changed
This makes it safe for development workflows: simply run `bash scripts/install.sh` again to update an existing installation.
@@ -165,6 +165,21 @@ https://wall.example.com
Log in with the username and password you provided during installation.
### Environment Variables
| Variable | Default | Description |
|---|---|---|
| `VACUUM_WALL_DB_BACKEND` | `sqlite` | Database backend selection |
| `VACUUM_WALL_DB_PATH` | `data/auth.db` | SQLite database file path |
### Post-Deploy Verification
1. Confirm `config/auth/config.json` exists with JWT secret and WebAuthn RP configuration
2. Confirm `data/auth.db` exists with admin user present
3. Nginx config no longer has `auth_basic` for management domain
4. WebSocket location no longer has `auth_basic off`
5. Access the WebUI at `https://<management-domain>` — should show a login page
### Certificate Note
The initial certificate is **self-signed** and generated during installation. Your browser will show a security warning. This is expected. Once DNS is pointing to the appliance and port 80 is accessible from the internet, use the **Certs** tab in the WebUI to issue a real ACME certificate for the management domain. After issuance, go to the **Proxy** tab and click **Apply** to reload nginx with the new cert.
@@ -322,6 +337,41 @@ Verify that:
- A DHCP range is configured for the correct interface. Check dnsmasq config at `data/dnsmasq/`.
- The firewall allows DHCP traffic on the internal zone: `firewall-cmd --zone=internal --list-services` should include `dhcp` and `dns`.
### Locked Out of WebUI
If you lose access to the admin account, you can reset the password directly via SQLite:
```bash
# Stop the services
sudo systemctl stop vacuum-wall vacuum-walld
# Reset password (replace 'newpassword' with desired password)
sqlite3 data/auth.db "UPDATE users SET password_hash='NEW_HASH_HERE' WHERE username='admin';"
```
The password hash must be an Argon2id hash. You can generate one:
```bash
python3 -c "from lib.password import hash_password; print(hash_password('newpassword'))"
```
Alternatively, use the SQLite prompt to directly inspect and modify user data:
```bash
sqlite3 data/auth.db ".tables"
sqlite3 data/auth.db "SELECT username FROM users;"
sqlite3 data/auth.db "SELECT * FROM permissions WHERE username='admin';"
```
### Database Corruption
If the SQLite database becomes corrupted:
1. Stop the services: `sudo systemctl stop vacuum-wall vacuum-walld`
2. Inspect: `sqlite3 data/auth.db "PRAGMA integrity_check;"`
3. Restore from backup if needed: `cp data/auth.db.backup data/auth.db`
4. Start services: `sudo systemctl start vacuum-walld vacuum-wall`
### WebUI Not Accessible
1. Verify nginx is running: `systemctl status nginx`.