mirror of
https://github.com/Screenly/Anthias.git
synced 2026-06-13 10:44:18 -04:00
* refactor(server): collapse nginx + websocket containers into uvicorn
Replace the nginx + gunicorn + gevent-websocket trio with a single
uvicorn ASGI server inside `anthias-server`:
* HTTP, /static/, /anthias_assets/, /static_with_mime/, and /hotspot
are now served from Django (WhiteNoise + small file-serving views in
`anthias_app/views_files.py` that re-implement nginx's IP allowlists).
* WebSockets move from a separate gevent process talking ZMQ to Django
Channels with a Redis-backed channel layer, fanned out by celery via
`channel_layer.group_send`.
* TLS termination is handled by uvicorn directly when SSL_CERTFILE /
SSL_KEYFILE are set; `bin/enable_ssl.sh` now writes a compose
override (no longer ansible) and a companion `bin/disable_ssl.sh`
removes it. Cert + key live under `~/.anthias/ssl/`.
* `bin/upgrade_containers.sh` removes the legacy `anthias-nginx` and
`anthias-websocket` containers on upgrade so they don't linger.
* Drop `gunicorn`, `gevent`, `gevent-websocket`, and the `websocket`
uv group from `pyproject.toml`; add `channels`, `channels-redis`,
`daphne`, `uvicorn[standard]`, and `whitenoise`.
Notes on hardening: `--forwarded-allow-ips` defaults to off so the IP
allowlist can't be bypassed via a spoofed `X-Forwarded-For`; operators
behind a reverse proxy can opt in via the `FORWARDED_ALLOW_IPS` env
var. Backup uploads previously sized by nginx's `client_max_body_size
4G` are preserved by setting `DATA_UPLOAD_MAX_MEMORY_SIZE = None`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address review feedback on uvicorn migration
* Drop USE_X_FORWARDED_HOST (inconsistent with the deliberate
--forwarded-allow-ips hardening; without a proxy, X-Forwarded-Host is
client-controlled).
* Remove daphne — uvicorn runs production and the test environment now
uses it too (bin/prepare_test_environment.sh).
* Replace _safe_join's parents-membership check with Path.is_relative_to.
* Drop AllowedHostsOriginValidator wrapper (no-op under ALLOWED_HOSTS=['*'])
and document where to put it back if hosts are ever locked down.
* Rename DOCKER_CIDR → DOCKER_BRIDGE_CIDR with a comment that this is
defense-in-depth, not a real perimeter (LAN clients via the published
port also appear in 172.16/12).
* Add anthias_app/tests.py covering the IP allowlists, mime override,
hotspot gating, and traversal/symlink rejection in _safe_join (17 tests).
* Note the single-worker ZmqPublisher bind constraint in start_server.sh
so a future scale-up doesn't EADDRINUSE on tcp://0.0.0.0:10001.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(security): clear SonarCloud hotspots on uvicorn migration
* Restrict views_files.anthias_assets / static_with_mime / hotspot to
GET via @require_GET (Sonar S3752, x3): they are read-only file
servers and should reject other methods at the view boundary.
* Mark RFC1918 / Docker-bridge CIDR literals as NOSONAR S1313 (x4):
they are intentional, well-known private network ranges.
* Mark `http://*` in CSRF_TRUSTED_ORIGINS as NOSONAR S5332 with a
comment explaining devices ship over HTTP and operators opt into TLS
via bin/enable_ssl.sh.
Existing 17 view tests continue to pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: clear remaining static-analysis findings
* ruff format -- the previous tests.py reformatted itself; CI's
`ruff format --check` now passes.
* CodeQL py/path-injection on _safe_join: rewrite using
os.path.realpath + os.path.commonpath, which CodeQL recognises as a
sanitiser for path-injection sinks. Behaviour is identical to the
Path.is_relative_to version (both reject `..` and symlink escapes;
the 17 tests in anthias_app/tests.py still pass).
* SonarCloud NOSONAR markers: switch to the codebase's bare `# NOSONAR`
form (matches host_agent.py and tests/test_backup_helper.py); the
earlier `# NOSONAR <rule>` form was not being honoured.
* Centralise the test-fixture IPs in module-level constants so S1313
is suppressed in one place rather than at every callsite.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(security): inline path-injection check in views
CodeQL only treats os.path.commonpath as a sanitiser when the check
sits in the same function as the file-system sink — calling
_safe_join() from a separate function still leaves the open()/isfile()
sinks tainted (4 alerts on PR #2757).
Repeat the realpath + commonpath check inline in anthias_assets and
static_with_mime so CodeQL can prove the post-check path stays under
the configured root. _safe_join is kept for the SafeJoinTest unit
tests and as a documented helper.
Existing 17 tests in anthias_app/tests.py continue to pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(security): use realpath+startswith path sanitiser for CodeQL
CodeQL's path-injection model recognises the canonical
`realpath(...).startswith(base + sep)` pattern but apparently not
`os.path.commonpath(...) == root` in this codepath. Switch the inline
check in anthias_assets and static_with_mime to startswith so the
analyser can prove the post-check path stays under the configured
root.
Behaviour is identical: traversal and symlink-escape still 404
(verified by SafeJoinTest + view tests).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address Copilot review feedback
* lib/utils.py imported channels/asgiref at module level. The viewer
container imports lib.utils via viewer/__init__.py but its uv
dependency group does not ship channels, so the viewer would
ImportError on startup. Move the channels imports into
YoutubeDownloadThread.run() (server/celery-only path) so lib.utils
remains importable from the viewer.
* Drop the unused _safe_join() helper and its three SafeJoinTest
cases — the views inline a realpath+startswith sanitiser (CodeQL
needs the check in the same function as the sink), and the helper
was only being exercised in isolation. Add an equivalent
symlink-escape test against anthias_assets so the actual code path
used by the views is covered.
* Refresh the anthias_django/settings.py docstring + Django doc URLs
from /3.2/ → /4.2/ to match the pinned Django version.
15 view tests pass (was 17 — lost 3 SafeJoinTest + gained 1 symlink
test against the real view).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: refresh architecture diagram for uvicorn migration
Drop the anthias-nginx and anthias-websocket nodes (and their edges)
from docs/d2/anthias-diagram-overview.d2 — the user now talks
directly to anthias-server (uvicorn handling HTTP + /ws), Celery
fans out asset-update events through the Redis-backed Channels
layer, and the viewer fetches media from anthias-server over HTTP.
Regenerate the SVG with d2 v0.7.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address Copilot SSL + CSRF / WS-origin feedback
* Dual uvicorn listeners when SSL is enabled (Copilot #1, #2). HTTP on
$HTTP_PORT (default 8080) for inter-container traffic — viewer +
webview hit anthias-server over plain HTTP on the Docker network and
cannot validate uvicorn's self-signed cert. HTTPS on $HTTPS_PORT
(default 8443) for external clients. bin/enable_ssl.sh now appends
443:8443 to the compose ports list (instead of using `!override` to
swap 80:8080 for 443:8080), so port 80 stays available for backward
compatibility and the Docker-network HTTP port keeps working.
* Drop CSRF_TRUSTED_ORIGINS = ['http://*', 'https://*'] (Copilot #3).
Verified via Django shell: those leading wildcards are ignored by
Django 4.2 (only subdomain wildcards like https://*.example.com are
honoured), so the setting was a no-op. Same-origin POSTs still pass
through Django's built-in Origin/Host check.
* Re-add channels.security.websocket.AllowedHostsOriginValidator to
the WebSocket router (Copilot #5). Currently a no-op under
ALLOWED_HOSTS=['*'], but tightening ALLOWED_HOSTS later will now
also tighten /ws.
Smoke test (dev + SSL override):
- HTTP http://localhost:8000/ -> 200
- HTTPS https://localhost:8443/ -> 200
- HTTP http://localhost:8443/ -> 000 (TLS-only, expected)
- internal http://localhost:8080/ -> 200
- 15 view tests still pass.
Note: Copilot #4 (Docker-bridge CIDR is bypassable via the published
port) is documented in views_files.py as defense-in-depth and matches
the original nginx posture; switching to app-layer auth is out of
scope for this PR.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(ssl): switch from in-uvicorn TLS to a Caddy sidecar
The previous SSL implementation gave anthias-server two uvicorn
listeners (HTTP + HTTPS) so the viewer/webview could keep talking
plain HTTP over the Docker network while external clients got TLS.
That dual-listener dance is non-zero overhead and complicates signal
handling. Switch to the standard reverse-proxy pattern instead.
When SSL is enabled by bin/enable_ssl.sh:
* anthias-server stays a single uvicorn listener on plain HTTP 8080
(no SSL_CERTFILE/SSL_KEYFILE knobs, no dual-port logic).
* A Caddy sidecar (caddy:2-alpine, only present when the override is
installed) terminates TLS on host port 443, redirects 80→443, and
reverse-proxies to anthias-server:8080 — so X-Forwarded-Proto /
X-Forwarded-For are forwarded as-is by Caddy.
* The override removes anthias-server's external port mapping
(`ports: !override []`), so all external traffic must enter through
Caddy and the IP allowlists in views_files.py see the original LAN
client IP rather than the docker-bridge gateway. Inter-container
traffic is unchanged.
* `FORWARDED_ALLOW_IPS=*` is set on anthias-server in the override —
safe because anthias-server is no longer reachable from outside the
Docker network — and `SECURE_PROXY_SSL_HEADER` is added in Django
settings so request.is_secure() returns True for HTTPS callers.
* When SSL is *not* enabled there is zero new container, zero new
config — the base compose file is untouched and Caddy isn't pulled
or run.
bin/disable_ssl.sh now also removes the anthias-caddy container
before deleting the override, so HTTPS-only state is fully reversed.
Smoke-tested with a temporary Caddy override:
- HTTPS via Caddy: 200
- HTTP via Caddy: 301 → https://...
- Direct anthias-server: refused (port mapping dropped by override)
- WebSocket upgrade: 101 Switching Protocols
- request.is_secure() with X-Forwarded-Proto=https: True
- 15 anthias_app view tests still pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(views_files): document IP-allowlist threat model
Spell out exactly when the docker-bridge CIDR check is and isn't a
real perimeter:
* No-SSL default: anthias-server is published as 80:8080, so requests
arrive with REMOTE_ADDR set to the docker bridge gateway (172.x) and
LAN clients aren't actually excluded. Trying to plug the gap with
auth would be security theatre — credentials would travel in
plaintext over the LAN anyway.
* SSL via the Caddy sidecar: Caddy terminates TLS, rewrites
X-Forwarded-For, uvicorn honours it (FORWARDED_ALLOW_IPS=*), and the
check sees the real client IP — so the bypass is closed for any
deployment that actually cares about confidentiality.
This is documentation only; no behavioural change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(ssl): add --domain (auto Let's Encrypt) + drop openssl shim
bin/enable_ssl.sh now has three modes instead of two:
* Default (no args) — Caddy issues per-SNI certs lazily from its
built-in local CA via `tls internal { on_demand }`. Drops the
openssl self-signed-cert generation step entirely; Caddy persists
the CA in the anthias-caddy-data volume and rotates leaf certs
itself. Browsers still warn (CA is local) but no openssl/cert
hygiene is needed on the host.
* `--domain example.com [--email you@example.com] [--staging]` —
Caddy auto-issues + renews from Let's Encrypt. Caddy auto-creates
the HTTP→HTTPS redirect for hostname sites. Use `--staging` to point
at the ACME staging endpoint while testing, so the production rate
limits aren't burned.
* `--cert /path/to/cert.pem --key /path/to/key.pem [--domain ...]` —
unchanged: bring your own cert, Caddy serves it as-is with
`auto_https off`.
Verified:
- All three Caddyfiles pass `caddy validate`.
- Default mode end-to-end: HTTPS=200 with cert from "Caddy Local
Authority - ECC Intermediate", per-SNI SANs (DNS:localhost,
IP Address:192.168.99.99 etc.), HTTP→HTTPS=301, /ws upgrade=101,
anthias-server's external port mapping is dropped so direct access
is refused.
Docs (CLAUDE.md, docs/README.md, docs/developer-documentation.md)
updated to describe the Caddy sidecar instead of in-uvicorn TLS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address self-review findings on PR #2757
* Gate SECURE_PROXY_SSL_HEADER on FORWARDED_ALLOW_IPS
(anthias_django/settings.py): without the gate, a client on a
plain-HTTP deploy could send `X-Forwarded-Proto: https` and flip
`request.is_secure()`. Django reads the header from META directly,
independent of uvicorn's --proxy-headers flag, so the previous
unconditional setting was actually exploitable in non-SSL mode
(secure-cookied sessions would drop on the next plain-HTTP request,
redirects would point at https:// URLs that don't exist).
Verified live: non-SSL → SECURE_PROXY_SSL_HEADER is None and
is_secure() with spoofed XFP=https returns False; SSL via Caddy
override → header is set and is_secure() returns True.
* Replace the isfile() pre-check + open() in anthias_assets and
static_with_mime with a try/except FileNotFoundError around open()
(anthias_app/views_files.py). Eliminates a (tiny but real) TOCTOU
window between the stat and the open. IsADirectoryError handled
too, since `realpath('/dir/')` resolves to the directory and open()
would otherwise 500.
* Comment FORWARDED_ALLOW_IPS=* assumption in bin/enable_ssl.sh: the
wildcard is only safe because the override drops anthias-server's
external port mapping, so any future edit that re-adds a host:port
publication has to either tighten the wildcard to Caddy's IP/CIDR
or unset it.
* Replace ANSI-C escape sequences in the Caddyfile generator with
plain multi-line strings. `read -r -d ''` was the first attempt
but it strips trailing newlines, which collapsed `auto_https off`
onto the same line as `}` in cert mode. Multi-line literals with
echo "$VAR" are unambiguous and Caddy validates all three modes
cleanly again.
* Add a docker-volume cleanup hint to bin/disable_ssl.sh: Caddy's
local CA persists in anthias_anthias-caddy-data so an enable →
disable → enable cycle reuses the same CA (intentional — browsers
that trusted it stay trusted), and operators who want a fresh CA
now have the exact `docker volume rm` command in the script's
output.
15 view tests still pass; default + SSL Caddyfiles still validate;
default + SSL endpoints still return 200 / 301 / 101 in smoke tests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address Copilot's host/MIME hardening feedback
Two security tightenings on top of the prior SECURE_PROXY_SSL_HEADER
gate (which Copilot flagged on a stale snapshot — that one's already
fixed in 07b784b9):
* `ALLOWED_HOSTS` is now driven by the `ALLOWED_HOSTS` env var, with
`*` kept as the default so flexible LAN-by-IP / mDNS access still
works out of the box. Operators on hardened LANs can opt into a
strict allowlist (`ALLOWED_HOSTS=192.168.1.50,anthias.local,...`)
to defend against DNS-rebinding without us guessing the right set
of hostnames at install time. Verified the env override parses to
`['192.168.1.50', 'anthias.local', 'localhost']`.
* `static_with_mime` now allowlists the `?mime=` query param against
a small set of download-only types
(`application/{gzip,octet-stream,x-gzip,x-tar,x-tgz,zip}`) instead
of accepting whatever the caller sends. Closes the XSS footgun
where `?mime=text/html` would have served a stored file as HTML.
The frontend's only legitimate caller (the backup download) sends
`application/x-tgz`, which is in the allowlist; anything else
falls back to mimetypes.guess_type. Added
`test_mime_override_rejects_html` to lock that behaviour in.
16 view tests pass; ruff clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
286 lines
10 KiB
Markdown
286 lines
10 KiB
Markdown
# Developer documentation
|
|
|
|
## Understanding the components that make up Anthias
|
|
|
|
Here is a high-level overview of the different components that make Anthias:
|
|
|
|

|
|
|
|
These components and their dependencies are mostly installed and handled with Ansible and Docker.
|
|
|
|
* The **web app** component (`anthias-server`) is the single HTTP entrypoint, served by uvicorn (ASGI). It runs the Django front-end + REST API, serves static assets via WhiteNoise, streams uploaded media at `/anthias_assets/`, and exposes the WebSocket endpoint at `/ws` via Django Channels. Always plain HTTP — TLS is opt-in via the **anthias-caddy** sidecar that `bin/enable_ssl.sh` installs (Caddy local CA by default, or Let's Encrypt with `--domain`).
|
|
* The **viewer** (`anthias-viewer`) is what drives the screen (e.g., shows web page, image or video). It fetches media from `anthias-server` over HTTP.
|
|
* The **Celery** (`anthias-celery`) component is for asynchronously queueing and executing tasks outside the HTTP request-response cycle (e.g., yt-dlp downloads, asset cleanup). It pushes asset-update events to connected WebSocket clients via the Redis-backed Channels layer.
|
|
* **Redis** (`redis`) is used as the Celery broker/result backend and as the Channels channel layer.
|
|
* The **database** component uses **SQLite** for storing the assets information.
|
|
|
|
## Dockerized development environment
|
|
|
|
To simplify development of the server module of Anthias, we've created a Docker container. This is intended to run on your local machine with the Anthias repository mounted as a volume.
|
|
|
|
> [!IMPORTANT]
|
|
> * Make sure that you have [installed Docker](https://docs.docker.com/engine/install/) on your machine before proceeding.
|
|
> * Anthias is using Docker's [buildx](https://docs.docker.com/engine/reference/commandline/buildx/) for the image builds. This is used both for cross compilation as well as for local caching. You might need to run `docker buildx create --use` first.
|
|
|
|
Assuming you're in the source code repository, simply run:
|
|
|
|
```bash
|
|
$ ./bin/start_development_server.sh
|
|
|
|
# The console output was truncated for brevity.
|
|
# ...
|
|
|
|
[+] Running 4/4
|
|
✔ Network anthias_default Created 0.1s
|
|
✔ Container anthias-redis-1 Started 0.2s
|
|
✔ Container anthias-anthias-server-1 Started 0.3s
|
|
✔ Container anthias-anthias-celery-1 Started 0.4s
|
|
```
|
|
|
|
> [!NOTE]
|
|
> Running the script will install Python 3.11, [pyenv](https://github.com/pyenv/pyenv),
|
|
> and [uv](https://docs.astral.sh/uv/) inside a Docker container on your machine.
|
|
> This is to ensure that the development environment is consistent across different
|
|
> machines.
|
|
>
|
|
> The script currently supports Debian-based systems and macOS.
|
|
|
|
unning the command above will start the development server and you should be able to
|
|
access the web interface at `http://localhost:8000`.
|
|
|
|
To stop the development server, run the following:
|
|
|
|
```bash
|
|
docker compose -f docker-compose.dev.yml down
|
|
```
|
|
|
|
## Building containers on the Raspberry Pi
|
|
|
|
> [!NOTE]
|
|
> Make sure that you have Docker installed on the device before proceeding.
|
|
|
|
```bash
|
|
$ ENVIRONMENT=production \
|
|
./bin/generate_dev_mode_dockerfiles.sh
|
|
$ MODE=build \
|
|
./bin/upgrade_containers.sh
|
|
```
|
|
|
|
## Django admin site
|
|
|
|
Create a superuser account:
|
|
|
|
```bash
|
|
$ export COMPOSE_FILE=docker-compose.dev.yml
|
|
$ docker compose exec anthias-server \
|
|
python manage.py createsuperuser
|
|
# You will be prompted to enter a username, an email address, and a password.
|
|
```
|
|
|
|
Once you have created a superuser account, you can open the Django admin site at `http://localhost:8000/admin/` (with a trailing slash)
|
|
and login with the credentials you just created.
|
|
|
|
|
|
## Testing
|
|
### Running the unit tests
|
|
|
|
Build and start the containers.
|
|
|
|
```bash
|
|
$ uv run python -m tools.image_builder \
|
|
--dockerfiles-only \
|
|
--disable-cache-mounts \
|
|
--service celery \
|
|
--service redis \
|
|
--service test
|
|
$ docker compose \
|
|
-f docker-compose.test.yml up -d --build
|
|
```
|
|
|
|
Run the unit tests.
|
|
|
|
```bash
|
|
$ docker compose \
|
|
-f docker-compose.test.yml \
|
|
exec anthias-test bash ./bin/prepare_test_environment.sh -s
|
|
|
|
# Integration and non-integration tests should be run separately as the
|
|
# former doesn't run as expected when run together with the latter.
|
|
|
|
$ docker compose \
|
|
-f docker-compose.test.yml \
|
|
exec anthias-test ./manage.py test --exclude-tag=integration
|
|
|
|
$ docker compose \
|
|
-f docker-compose.test.yml \
|
|
exec anthias-test ./manage.py test --tag=integration
|
|
```
|
|
|
|
### The QA checklist
|
|
|
|
We've also provided a [checklist](/docs/qa-checklist.md) that can serve as a guide for testing Anthias manually.
|
|
|
|
## Generating CSS and JS files
|
|
|
|
To get started, you need to start the development server first. See this [section](#dockerized-development-environment)
|
|
for details.
|
|
|
|
### Starting the bundler in development mode
|
|
|
|
To start [Bun](https://bun.sh/) in development (watch) mode, run the following command:
|
|
|
|
```bash
|
|
$ docker compose -f docker-compose.dev.yml exec anthias-server \
|
|
bun run dev
|
|
```
|
|
|
|
This runs `bun build --watch` for JS/TS and `sass --watch` for SCSS in parallel.
|
|
Making changes to the TypeScript, TSX, or SCSS files will automatically trigger a recompilation,
|
|
generating the corresponding bundle and CSS files.
|
|
|
|
### Formatting and linting TypeScript code
|
|
|
|
To run the linting and formatting checks on the TypeScript code, run the following command:
|
|
|
|
```bash
|
|
$ docker compose -f docker-compose.dev.yml exec anthias-server \
|
|
bun run lint:check
|
|
$ docker compose -f docker-compose.dev.yml exec anthias-server \
|
|
bun run format:check
|
|
```
|
|
|
|
If you want to fix the linting errors and formatting issues, run the following command:
|
|
|
|
```bash
|
|
$ docker compose -f docker-compose.dev.yml exec anthias-server \
|
|
bun run lint:fix
|
|
$ docker compose -f docker-compose.dev.yml exec anthias-server \
|
|
bun run format:fix
|
|
```
|
|
|
|
### Closing the transpiler
|
|
|
|
Just press `Ctrl-C` to close the bundler watch.
|
|
|
|
## Linting Python code locally
|
|
|
|
The project uses `ruff` for linting the Python codebase. While the linter is being run on the CI/CD pipeline,
|
|
you can also run it locally. There are several ways to do this.
|
|
|
|
### Run the linter using `act`
|
|
|
|
[`act`](https://nektosact.com/) lets you run GitHub Actions locally. This is useful for testing the CI/CD pipeline locally.
|
|
Installation instructions can be found [here](https://nektosact.com/installation/index.html).
|
|
|
|
After installing and setting up `act`, run the following command:
|
|
|
|
```bash
|
|
$ act -W .github/workflows/python-lint.yaml
|
|
```
|
|
|
|
The command above will run the linter on the all the Python files in the repository. If you want to run the linter
|
|
on a specific file, you can try the commands in the next section.
|
|
|
|
### Running the linter using `uv`
|
|
|
|
You have to install `uv` first. You can find the installation instructions
|
|
[here](https://docs.astral.sh/uv/getting-started/installation/).
|
|
|
|
After installing uv, run the following commands:
|
|
|
|
```bash
|
|
# Install the dependencies
|
|
$ uv venv
|
|
$ uv pip install --group dev-host
|
|
$ uv run ruff check .
|
|
```
|
|
|
|
To run the linter on a specific file, run the following command:
|
|
|
|
```bash
|
|
$ uv run ruff check /path/to/file.py
|
|
```
|
|
|
|
|
|
## Managing releases
|
|
### Creating a new release
|
|
|
|
Check what the latest release is:
|
|
|
|
```bash
|
|
$ git pull
|
|
$ git tag
|
|
|
|
# Running the `git tag` command should output something like this:
|
|
# 0.16
|
|
# ...
|
|
# v0.18.6
|
|
```
|
|
|
|
Create a new release:
|
|
|
|
```bash
|
|
$ git tag -a v0.18.7 -m "Test new automated disk images"
|
|
```
|
|
|
|
Push release:
|
|
```bash
|
|
$ git push origin v0.18.7
|
|
```
|
|
|
|
### Delete a broken release
|
|
|
|
```bash
|
|
$ git tag -d v0.18.5 [±master ✓]
|
|
Deleted tag 'v0.18.5' (was 9b86c39)
|
|
|
|
$ git push --delete origin v0.18.5 [±master ✓]
|
|
```
|
|
|
|
## Directories and files explained
|
|
|
|
In this section, we'll explain the different directories and files that are
|
|
present in a Raspberry Pi with Anthias installed.
|
|
|
|
### `/home/${USER}/anthias/`
|
|
|
|
* All of the files and folders from the Github repo should be cloned into this directory.
|
|
* On installations created before the rename, this directory is `/home/${USER}/screenly/` — the installer migrates it to `anthias/` on upgrade and leaves a back-compat symlink at the old path for one release.
|
|
|
|
### `/home/${USER}/.anthias/`
|
|
|
|
* `default_assets.yml` — configuration file which contains the default assets that get added to the assets list if enabled
|
|
* `initialized` — tells whether access point service (for Wi-Fi connectivity) runs or not
|
|
* `anthias.conf` — configuration file for web interface settings
|
|
* `anthias.db` – database file containing current assets information.
|
|
* On pre-rename installations this directory is `~/.screenly/` containing `screenly.conf` / `screenly.db`; the installer migrates them.
|
|
|
|
|
|
### `/etc/systemd/system/`
|
|
|
|
* `wifi-connect.service` — starts the Balena `wifi-connect` program to dynamically set the Wi-Fi config on the device via the captive portal
|
|
* `anthias-host-agent.service` — starts the Python script `host_agent.py`, which subscribes from the Redis component and performs a system call to shutdown or reboot the device when the message is received.
|
|
|
|
### `/etc/sudoers.d/anthias_overrides`
|
|
|
|
* `sudoers` configuration file that allows pi user to execute certain `sudo` commands without being a superuser (i.e., `root`)
|
|
|
|
### `/usr/share/plymouth/themes/anthias`
|
|
|
|
* `anthias.plymouth` — Plymouth config file (sets module name, `ImageDir` and `ScriptFile` dir)
|
|
* `anthias.script` – plymouth script file that loads and scales the splash screen image during the boot process
|
|
* `splashscreen.png` — the spash screen image that is displayed during the boot process
|
|
|
|
## Debugging the Anthias WebView
|
|
|
|
```
|
|
export QT_LOGGING_DEBUG=1
|
|
export QT_LOGGING_RULES="*.debug=true"
|
|
export QT_QPA_EGLFS_DEBUG=1
|
|
```
|
|
|
|
The Anthias WebView is a custom-built web browser based on the [Qt](https://www.qt.io/) toolkit framework.
|
|
The browser is assembled with a Dockerfile and built by a `webview/build_qt#.sh` script.
|
|
|
|
For further info on these files and more, visit the following link: [https://github.com/Screenly/Anthias/tree/master/webview](https://github.com/Screenly/Anthias/tree/master/webview)
|