Skip to content

Development Setup

OpenTremor is split into several independently packaged modules that all live in one repository, each as a top-level directory with its own pyproject.toml/package.json, tests and LICENSE. This page covers developing against OpenTremor-core (the server). For a full local stack (core + an analyzer + dashboard + MongoDB) in one command, see the docker-compose.yaml at the repository root.

ToolVersionPurpose
Python3.14.xRuntime
Poetry1.8+Dependency management
DockeranyMongoDB for integration tests

Terminal window
git clone <opentremor-repo-url> opentremor
cd opentremor/OpenTremor-core
poetry install

This installs runtime and dev dependencies (pytest, black, isort, …) but no analyzer — GET /analyzers returns an empty list until you install one. To run the full test suite (including the tests that exercise a real analyzer end-to-end), pull in the analyzers as well. They are already sibling directories in the clone (OpenTremor-analyzer-terraform-plan, OpenTremor-analyzer-terraform-code-change, OpenTremor-analyzer-blackhole — each is independent of the others), so the path dependencies resolve with no extra setup:

Terminal window
poetry install --with internal

Terminal window
docker compose up mongodb -d
poetry run python src/tools/init_mongo.py

A default superadmin account is available out of the box via auth.default_admin_email/default_admin_password — in configs/opentremor-core-local.yaml when running the server directly, or in the workspace root’s shared configs/opentremor-local.yaml when running either docker stack. See Configuration Reference — auth.


Terminal window
poetry run uvicorn opentremor_core.controllers.app:app \
--reload \
--host 0.0.0.0 \
--port 8000

Or with the bundled server entrypoint (reads HOST, PORT, CONFIG_FILE env vars):

Terminal window
CONFIG_FILE=configs/opentremor-core-local.yaml poetry run python src/server.py

opentremor-core/
├── configs/
│ ├── opentremor-core.yaml This repo's own standalone docker stack (MongoDB)
│ ├── opentremor-core-local.yaml Local dev (in-memory, default)
│ ├── opentremor-core-prod.yaml Operator's cloud SaaS deployment
│ └── opentremor-core-tests.yaml Test suite config
├── src/
│ ├── opentremor_core/ Python package — server framework, no analyzers
│ ├── tests/ Test suite
│ ├── tools/ CLI utilities
│ └── server.py Uvicorn entrypoint
├── pyproject.toml
├── Dockerfile
└── docker-compose.yaml This repo alone (app + MongoDB, no analyzer/dashboard)

Terminal window
# Format
poetry run black src/
# Sort imports
poetry run isort src/
# Both (typical pre-commit)
poetry run black src/ && poetry run isort src/

.github/workflows/ci.yml at the repository root runs on every push and pull request. Every job targets runs-on: self-hosted, so the workflow needs a registered self-hosted runner on the repository; without one the jobs queue instead of failing. The runner has to provide Docker (the compose config job shells out to docker compose) and enough disk for the Python, Node and Go toolchains the setup-* actions install into its tool cache.

One job per module, all in parallel:

JobRuns
python · <module>poetry install + pytest for OpenTremor-platform, OpenTremor-core, the three analyzers, and OpenTremor-task-scheduler. Core installs --with internal so the analyzer-dependent tests run instead of skipping.
platform independenceAsserts opentremor_core is not importable from the platform venv — platform must stay runnable without the product mounted on it.
dashboardnpm ci, npm run lint, npx tsc --noEmit, npm run build.
docsnpm ci + npm run build, which runs the module-docs composition step first.
terraform-providergo build, go vet, go test.
helm charthelm lint, then helm template against each values profile.
compose configdocker compose config over all three compose files.

There is no path filtering — every job runs on every push, because the dependency edges between modules (a platform change must still run core’s suite; an analyzer change must still run core with --with internal) don’t match the directories that changed.


Renovate opens update pull requests every Monday morning (UTC), configured in .github/renovate.json5. It finds every manifest on its own — the seven pyproject.toml/poetry.lock pairs, the dashboard and docs package.json files, the provider’s go.mod (indirect requirements included), every Dockerfile and *.Dockerfile, the docker-compose files, the chart’s values.yaml, core’s mise.toml and the workflow actions.

UpdatePull requestMerged by
Python, npm, Go — minor and patchone per ecosystemRenovate, once every check is green and the version is 3 days old
Container images — minor and patchone for all imagesa person — CI builds no image
Dev tools in mise.toml — minor and patchonea person
Security fix (OSV advisory)one per advisory, any day of the weekas its ecosystem’s group
GitHub Actions — anyone for all actions, ci(deps)a person
Any majornone, until ticked on the Dependency Dashboard issuea person
Lockfile refresh (transitive dependencies)one, weeklya person

Majors wait on the Dependency Dashboard. Renovate keeps one issue listing every pending major; ticking its checkbox opens the pull request. A major that can’t pass yet — eslint 10 before eslint-plugin-react supports it — stays listed there instead of being re-opened every week.

Lockfiles are written with CI’s toolchain — node 24, npm 11.19.0, Poetry 2.4.1, under constraints in the config. Bump them there when NODE_VERSION or POETRY_VERSION changes in .github/workflows/ci.yml; nothing checks that the two agree.

Pinned in the config rather than proposed:

  • mongo stays below 8 — every 8.x refuses to start on Linux 6.19+ (MongoDB SERVER-121912).
  • The python base image’s minor and major wait for approval — it moves with python = ">=3.14,<3.15" in every pyproject.toml and CI’s PYTHON_VERSION, never alone.
  • Go’s go directive waits for approval — it is the language version, and CI’s setup-go reads it from go.mod.
  • Our own images and workspace packages are ignored — ghcr.io/tguisep/opentremor-*, the local opentremor-* compose images and @opentremor/*. release-please stamps them.

Commits use chore(deps) and ci(deps). chore is a hidden section in release-please’s changelog, so a package bump ships in the next release without a changelog line.


Docs live in the sibling OpenTremor-docs directory:

Terminal window
cd ../OpenTremor-docs
npm install
npm run dev # live-reload dev server at http://localhost:4321
npm run build # static site → dist/

Reaching the dev server on a hostname other than localhost

Section titled “Reaching the dev server on a hostname other than localhost”

Astro’s dev server is Vite, and Vite refuses requests whose Host header it doesn’t recognise — a DNS-rebinding protection. Reached through a proxy or on a real domain it answers Blocked request. This host ("…") is not allowed. instead of the site. List the extra hostnames in DOCS_ALLOWED_HOSTS (comma-separated; * disables the check entirely):

Terminal window
DOCS_ALLOWED_HOSTS=docs.example.com npm run dev -- --host

This affects npm run dev only. npm run build output is static files with no dev server involved, so a production deployment never needs the variable — the workspace’s docker-compose.dev.yaml sets it for its docs service, docker-compose.prod.yaml does not.