feat: add Python packaging metadata and a Nix flake
Build and publish container / build (pull_request) Successful in 7m8s

Package the proxy properly so it can be consumed outside a container, and
without downstream users vendoring a package definition into their own
configuration.

- pyproject.toml: setuptools metadata with a `legacy-email-proxy` console
  script. Runtime dependencies are read dynamically from requirements.txt, so
  the Docker build and the package cannot drift apart.
- proxy_server.run(): a synchronous entry point for the console script, since
  `main` is a coroutine and cannot be referenced by one directly. The
  `__main__` path is unchanged in behaviour.
- package.nix / flake.nix: the package, an overlay, and a dev shell. The test
  suite runs as part of the build, so `nix flake check` covers it.
- module.nix: a NixOS module exposing `services.legacy-email-proxy` with
  freeform `settings` (environment variables) and a separate `environmentFile`
  for credentials, so secrets stay out of the Nix store. Runs under
  DynamicUser with CAP_NET_BIND_SERVICE only while a listener needs a
  privileged port, and opens no firewall ports.

The Dockerfile and its CI workflow are deliberately untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Emma Thorpe
2026-08-21 13:05:34 +01:00
co-authored by Claude Opus 5
parent 4bde4f884d
commit fe540e1831
8 changed files with 353 additions and 1 deletions
+61
View File
@@ -53,6 +53,67 @@ docker run --rm -p 110:110 -p 25:25 \
legacy-email-proxy
```
The project is also a standard Python package (`pyproject.toml`), so it
installs without Docker. This puts a `legacy-email-proxy` command on `PATH`:
```bash
pip install .
legacy-email-proxy
```
`requirements.txt` remains the single source of runtime dependencies;
`pyproject.toml` reads it, so the Docker build and the package cannot drift.
## Nix
The repository is a flake. It exposes the package, an overlay, and a NixOS
module.
```bash
nix run .#legacy-email-proxy # run it
nix build .#legacy-email-proxy # build it; the test suite runs as part of the build
nix develop # dev shell with pytest
```
As a NixOS service, with the proxy's own flake as an input:
```nix
{
inputs.legacy-email-proxy.url = "git+https://code.emmathe.dev/lyrathorpe/legacy-email-proxy";
# optionally: inputs.legacy-email-proxy.inputs.nixpkgs.follows = "nixpkgs";
}
```
```nix
{
imports = [ inputs.legacy-email-proxy.nixosModules.default ];
services.legacy-email-proxy = {
enable = true;
settings = {
POP3_BIND_ADDR = "10.0.0.1";
SMTP_BIND_ADDR = "10.0.0.1";
BACKEND_IMAP_HOST = "imap.example.com";
BACKEND_IMAP_USER = "someone@example.com";
BACKEND_SMTP_HOST = "smtp.example.com";
BACKEND_SMTP_USER = "someone@example.com";
};
# Credentials belong here, not in `settings` -- anything in `settings`
# lands in the world-readable Nix store.
environmentFile = "/var/lib/legacy-email-proxy/backend.env";
};
}
```
`settings` accepts any of the environment variables listed above; booleans and
integers are converted for you. The service runs under `DynamicUser`, with
`CAP_NET_BIND_SERVICE` granted only while a listener is on a privileged port.
It opens no firewall ports — see "Security".
Prefer to manage the package yourself? `overlays.default` provides
`pkgs.legacy-email-proxy`, and `nixosModules.legacy-email-proxy` is the same
module without the package default wired to this flake.
## Tests
Install development dependencies and run the test suite: