* refactor: rename legacy 'screenly' dirs to 'anthias' with auto-migration
For legacy reasons the host directories storing the cloned repo, user
assets, and config + DB still carried the old 'screenly' name. Rename
all three to their 'anthias' equivalents, plus the in-container paths,
the screenly.db / screenly.conf filenames, /tmp/screenly.watchdog,
/etc/sudoers.d/screenly_overrides, the ansible role, and the nginx URL
location. Existing installations are migrated automatically:
~/screenly/ -> ~/anthias/
~/screenly_assets/ -> ~/anthias_assets/
~/.screenly/ -> ~/.anthias/
screenly.db -> anthias.db
screenly.conf -> anthias.conf (paths rewritten in the body)
/etc/sudoers.d/screenly_overrides -> /etc/sudoers.d/anthias_overrides
Migration is driven by two new helpers:
- bin/migrate_legacy_paths.sh: idempotent host-side rename. Self-relocates
if invoked from inside the dir being renamed. Rewrites both relative
and absolute path values inside screenly.conf. Leaves dir-level
back-compat symlinks at the old paths and file-level symlinks
(screenly.db, screenly.conf) inside the migrated config dir so
user automation / one-version downgrade still find familiar names.
- bin/migrate_in_container_paths.sh: defensive /data/.screenly and
/data/screenly_assets symlinks invoked from the container start
scripts, in case an older docker-compose.yml is still mounting the
legacy paths during a partial upgrade.
Wired into bin/install.sh (renames ~/screenly before clone_repo, then
runs the in-repo helper after) and bin/upgrade_containers.sh (runs the
helper near the top before regenerating docker-compose.yml).
Out of scope (intentional): the screenly/anthias-* Docker Hub namespace,
the Screenly/Anthias GitHub repo URLs, the screenly_ose Balena fleet,
api.screenlyapp.com / apt.screenlyapp.com legacy URLs, and brand URLs
in docs.
Tests: added tests/test_migrate_legacy_paths.py (4 cases: full migration,
absolute-path conf rewrite, idempotent rerun, fresh-install no-op) and
tests/test_backup_helper.py::RecoverLegacyTarballTest (recover() still
accepts pre-rename .tar.gz backups). Ruff clean. All 6 new tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* style: apply ruff format to new test files
CI's `ruff format --check` flagged tests/test_backup_helper.py and
tests/test_migrate_legacy_paths.py. Reformatted; behaviour unchanged,
6/6 migration-related tests still pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test: suppress SonarCloud S5042 on write-mode tarfile.open in fixtures
The two new fixture-building calls in tests/test_backup_helper.py use
`tarfile.open(..., 'w:gz')` (write mode), which Sonar's python:S5042
rule flags as "expanding this archive file" without distinguishing
read from write. arcnames are hardcoded test inputs with no
path-traversal surface, so the warning is a false positive here.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address Copilot review feedback
- lib/backup_helper.py: harden recover() against tar path traversal
(Zip Slip / CVE-2007-4559). New _safe_tar_member() rejects absolute
paths, '..' components, non-regular-non-directory members
(symlinks/hardlinks/devices), members outside the allowed top-level
dirs, and any post-normalisation path that escapes $HOME. Iterates
members manually instead of bulk extractall(), and passes
filter='data' on Python with PEP-706 extraction filters
(3.11.4+/3.12+) for belt-and-suspenders defence.
- tests/test_backup_helper.py: BackupHelperTest now patches HOME to a
per-test tmpdir so `tearDown` no longer rmtree's a real ~/anthias
checkout when run on a developer workstation. Also added
test_recover_skips_path_traversal_member, which proves a hostile
tarball entry like `../evil.txt` is logged-and-skipped, not written
outside $HOME.
- docs/raspberry-pi5-ssd-install-instructions.md: capitalise "This"
after the period.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: add missing leading slash to repo dir heading
The heading for the cloned repo dir was rendered as
`home/${USER}/anthias/`, while every other heading in the section uses
absolute paths like `/home/${USER}/.anthias/`. Same fix applied to the
legacy-path mention in the note below it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
10 KiB
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 NGINX component (
anthias-nginx) forwards requests to the backend and serves static files. It also acts as a reverse proxy. - The viewer (
anthias-viewer) is what drives the screen (e.g., shows web page, image or video). - The web app component (
anthias-server) — which consists of the front-end and back-end code – is what the user interacts with via browser. - The Celery (
anthias-celery) component is for aynschronouslt queueing and executing tasks outside the HTTP request-response cycle (e.g., doing assets cleanup). - The WebSocket (
anthias-websocket) component is used for forwarding requests from NGINX to the backend. - Redis (
redis) is used as a database, cache and message broker. - 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 on your machine before proceeding.
- Anthias is using Docker's 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 --usefirst.
Assuming you're in the source code repository, simply run:
$ ./bin/start_development_server.sh
# The console output was truncated for brevity.
# ...
[+] Running 6/6
✔ Network anthias_default Created 0.1s
✔ Container anthias-redis-1 Started 0.2s
✔ Container anthias-anthias-server-1 Started 0.2s
✔ Container anthias-anthias-celery-1 Started 0.3s
✔ Container anthias-anthias-websocket-1 Started 0.4s
✔ Container anthias-anthias-nginx-1 Started 0.5s
Note
Running the script will install Python 3.11, pyenv, and 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:
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.
$ ENVIRONMENT=production \
./bin/generate_dev_mode_dockerfiles.sh
$ MODE=build \
./bin/upgrade_containers.sh
Django admin site
Create a superuser account:
$ 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.
$ 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.
$ 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 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 for details.
Starting the bundler in development mode
To start Bun in development (watch) mode, run the following command:
$ 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:
$ 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:
$ 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 lets you run GitHub Actions locally. This is useful for testing the CI/CD pipeline locally.
Installation instructions can be found here.
After installing and setting up act, run the following command:
$ 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.
After installing uv, run the following commands:
# 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:
$ uv run ruff check /path/to/file.py
Managing releases
Creating a new release
Check what the latest release is:
$ git pull
$ git tag
# Running the `git tag` command should output something like this:
# 0.16
# ...
# v0.18.6
Create a new release:
$ git tag -a v0.18.7 -m "Test new automated disk images"
Push release:
$ git push origin v0.18.7
Delete a broken release
$ 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 toanthias/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 enabledinitialized— tells whether access point service (for Wi-Fi connectivity) runs or notanthias.conf— configuration file for web interface settingsanthias.db– database file containing current assets information.- On pre-rename installations this directory is
~/.screenly/containingscreenly.conf/screenly.db; the installer migrates them.
/etc/systemd/system/
wifi-connect.service— starts the Balenawifi-connectprogram to dynamically set the Wi-Fi config on the device via the captive portalanthias-host-agent.service— starts the Python scripthost_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
sudoersconfiguration file that allows pi user to execute certainsudocommands without being a superuser (i.e.,root)
/usr/share/plymouth/themes/anthias
anthias.plymouth— Plymouth config file (sets module name,ImageDirandScriptFiledir)anthias.script– plymouth script file that loads and scales the splash screen image during the boot processsplashscreen.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 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