{"id":49287728,"url":"https://github.com/chatmail/cmlxc","last_synced_at":"2026-04-25T22:34:39.724Z","repository":{"id":350828804,"uuid":"1208381183","full_name":"chatmail/cmlxc","owner":"chatmail","description":"local chatmail container management and testing","archived":false,"fork":false,"pushed_at":"2026-04-20T13:30:30.000Z","size":190,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-20T13:46:05.054Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chatmail.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"open_collective":"chatmail"}},"created_at":"2026-04-12T07:39:56.000Z","updated_at":"2026-04-17T12:45:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/chatmail/cmlxc","commit_stats":null,"previous_names":["chatmail/cmlxc"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/chatmail/cmlxc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chatmail%2Fcmlxc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chatmail%2Fcmlxc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chatmail%2Fcmlxc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chatmail%2Fcmlxc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chatmail","download_url":"https://codeload.github.com/chatmail/cmlxc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chatmail%2Fcmlxc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32279658,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-25T18:29:39.964Z","status":"ssl_error","status_checked_at":"2026-04-25T18:29:32.149Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-25T22:34:38.998Z","updated_at":"2026-04-25T22:34:39.719Z","avatar_url":"https://github.com/chatmail.png","language":"Python","funding_links":["https://opencollective.com/chatmail"],"categories":[],"sub_categories":[],"readme":"# cmlxc -- local chatmail container management and testing\n\nManage local [Incus](https://linuxcontainers.org/incus/) containers for\nchatmail relay development and testing.\n`cmlxc` spins up lightweight LXC containers,\ndeploys chatmail relay services into them via `cmdeploy` or `madmail`,\nand runs integration tests -- all without touching the host system.\nSee [Architecture](#architecture) for more internal details.\n\n\n## Prerequisites\n\n[Incus](https://linuxcontainers.org/incus/) installed and configured on the host.\nUsually only being part of the \"incus\" group is necessary,\nas containers can run with user privileges.\n\n\u003e [!TIP]\n\u003e On Debian or Ubuntu, it is recommended to use the\n\u003e [Zabbly Incus repository](https://github.com/zabbly/incus)\n\u003e to ensure you have a recent version.\n\nYou can verify your incus installation like this:\n\n    incus launch images:debian/12 local-my-setup\n\nIf this command fails, please check the incus documentation.\nIf you get an error about \"Failed instance creation\", \nyou might be running into https://github.com/lxc/incus/issues/916\nand need to ensure there is no component (mullvad) for example,\nthat messes up container networking. \n\n\n## Installation\n\nWith pip:\n\n    python -m venv venv\n    source venv/bin/activate\n    pip install cmlxc\n\nOr with [uv](https://docs.astral.sh/uv/):\n\n    uv venv venv\n    source venv/bin/activate\n    uv pip install cmlxc\n\n\n## Usage\n\n**Initialize the environment** (base image, DNS container, builder container):\n\n    cmlxc init\n\nRe-initialize from scratch (destroys everything first):\n\n    cmlxc init --reset\n\n\n**Deploy chatmail relays** (creates containers if needed, then deploys).\nThe `--source` argument controls where the code comes from:\n\n    cmlxc deploy-cmdeploy --source @main cm0\n    cmlxc deploy-madmail  --source @main mad1\n    cmlxc deploy-madmail  --source @main --with-webadmin mad1\n    cmlxc deploy-madmail  --source @main --ipv4-only mad1\n\n\n| Form | Meaning |\n|---------|---------|\n| `@ref` | Clone default remote at branch/tag `ref` |\n| `/path` or `./path` | Sync from a local checkout |\n| `URL@ref` | Clone a custom remote at `ref` |\n\nExamples with local checkouts or feature branches:\n\n    cmlxc deploy-cmdeploy --source ../relay cm0\n    cmlxc deploy-madmail  --source @lmtp-rework mad0\n    cmlxc deploy-cmdeploy --source @fix-dovecot cm1\n\nEach `deploy-*` invocation initialises the driver's source in the\nbuilder (wipe-and-reclone).\n\n\n**Run integration tests** inside the builder:\n\n    cmlxc test-mini cm0\n    cmlxc test-mini cm0 cm1          # cross-relay tests (domain-based)\n    cmlxc test-mini cm0 mad1         # cross-relay tests (mixed)\n    cmlxc test-cmdeploy cm0 cm1\n    cmlxc test-madmail mad1\n\n\n**SSH into a deployed relay:**\n\n    ssh -F ~/.config/cmlxc/ssh-config cm0\n\n\n**Lifecycle commands:**\n\n    cmlxc status                # show all containers\n    cmlxc status cm0            # show only cm0\n    cmlxc status cm0 mad1       # show multiple containers\n    cmlxc status --host         # show DNS/SSH setup instructions\n    cmlxc start cm0             # restart a stopped relay\n    cmlxc stop cm0 cm1          # stop relays\n    cmlxc destroy cm0           # stop + delete\n    cmlxc destroy --all         # destroy relays, keep DNS/builder\n\n\n**Increase verbosity** with `-v` or `-vv`:\n\n    cmlxc deploy-cmdeploy --source @main -vv cm1\n\n\n## Shell Completion\n\n`cmlxc` supports Bash tab-completion for subcommands, options, and container names.\n\n\nEnable for the **current session**:\n\n```bash\neval \"$(register-python-argcomplete cmlxc)\"\n```\n\nEnable **permanently**:\n\n```bash\nactivate-global-python-argcomplete --user\n```\n\n\n## Architecture\n\n`cmlxc` manages four kinds of containers, each with a distinct role:\n\n```\n    cmlxc init / deploy-* / test-*\n        |\n        v\n   +-----------------+   +------------------------+   +--------------------+\n   | ns-localchat    |   | builder-localchat      |   | relay containers   |\n   | (PowerDNS)      |   | (repos, venvs, builds) |   | (cm0, mad1, ...)   |\n   +-----------------+   +------------------------+   +--------------------+\n           ^                        |                           ^\n           |      DNS zones         |        SSH / SCP          |\n           +------------------------+---------------------------+\n```\n\n\n**Base image** (`localchat-base`) -- a Debian 12 image with SSH and\nPython pre-installed.\nAll other containers are launched from this image (or from a cached\nrelay image).\n\n\n**DNS container** (`ns-localchat`) -- runs PowerDNS authoritative + recursor.\nProvides `.localchat` DNS resolution so containers can reach each other by name.\n\n\n**Builder container** (`builder-localchat`) -- the central workhorse.\nHolds repository templates and per-relay checkouts,\nPython virtualenvs for `cmdeploy` and mini-tests, and the compiled `maddy` binary.\nAll deployment and test operations are executed *inside* the builder --\nthe host only needs `cmlxc` itself.\n\n\n**Relay containers** (e.g. `cm0-localchat`, `mad1-localchat`) --\nephemeral containers that receive a deployed chatmail service.\nEach relay is locked to a single deployment driver (`cmdeploy` or\n`madmail`); switching requires destroying and re-creating the container.\n\n\n### Deployment drivers\n\nDrivers live in `driver_cmdeploy.py` and `driver_madmail.py`.\nEach driver module exports its CLI subcommand metadata,\nbuilder init, and deploy orchestration.\n`cli.py` generates the `deploy-*` subcommands from a `DRIVER_BY_NAME` mapping.\n\n\n- **cmdeploy** -- runs `cmdeploy run` from the builder container over SSH\n  into the relay.\n  Generates DNS zones, loads them into PowerDNS, and verifies records.\n  After the first successful deploy the relay image is cached as\n  `localchat-cmdeploy` so subsequent containers start pre-populated.\n\n- **madmail** -- builds the `maddy` Go binary inside the builder,\n  pushes it via SCP and runs `madmail install --simple --ip \u003cIP\u003e`.\n  No DNS entries are needed.\n\n\n## Releasing\n\nVersions are derived from git tags via `setuptools-git-versioning`.\nThe changelog is generated with [git-cliff](https://git-cliff.org/)\nusing the `cliff.toml` config in the repo root.\n\n\nTo make a new release, use the provided script:\n\n    ./make_new_release.py\n\nThe script automates the following steps:\n\n1. **Test** the codebase by running a full `tox` suite and functional\n   tests (`pytest tests/fullrun.py`).\n\n2. **Preview** unreleased changes with `git cliff`.\n\n3. **Tag** the release (suggesting automatic, micro, or minor bump).\n\n4. **Generate** the full changelog into `CHANGELOG.md`.\n\n5. **Edit** the changelog manually (opens your `$EDITOR`).\n\n6. **Amend** the tag commit to include the changelog update.\n\n7. **Force-tag** the amended commit.\n\n\nAfter the script finishes, push the changes:\n\n    git push origin main --tags\n\n\nThe `release.yml` GitHub workflow triggers on pushed `v*` tags,\nbuilds the sdist + wheel, and publishes to PyPI via trusted publishing (OIDC).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchatmail%2Fcmlxc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchatmail%2Fcmlxc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchatmail%2Fcmlxc/lists"}