Commit Graph
14 Commits
Author SHA1 Message Date
Emma ThorpeandClaude Opus 5 23bfa27fd7 fix: keep the packaged version in step with the release tag
Build and publish container / build (pull_request) Successful in 4m8s
The version in pyproject.toml was static, while releases are derived from
conventional commits and tagged by CI. The first release after packaging was
cut as v0.4.0 while the file still declared 0.3.0, so the Python package and
the Nix store path both understated the release.

The version cannot be set by hand in the pull request that causes a release:
it is computed from the commit messages and is only known inside the release
job. So the release job now writes it into pyproject.toml, commits it as
chore(release), and tags that commit.

Neither push re-triggers the workflow -- it listens on main only for the
image-affecting paths, and pyproject.toml is not one of them -- and the
chore(release) subject produces no bump of its own on the next run. The branch
push is ordered before the tag push so a rejected push cannot leave a tag
pointing at a commit that is not on main.

pyproject.toml is bumped to 0.4.0 here to correct the current state; from the
next release onward CI maintains it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 13:47:17 +01:00
lyrathorpeandEmma Thorpe f1e1373fd3 feat: add Python packaging metadata and a Nix flake (#16)
Build and publish container / build (push) Successful in 6m4s
## What

- `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 that console script; `main` is a coroutine and cannot be referenced by one. The `__main__` path behaves as before.
- `flake.nix` / `package.nix` — the package, `overlays.default`, a dev shell, and `checks`. The pytest suite runs as part of the build.
- `module.nix` — a NixOS module: `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`, takes `CAP_NET_BIND_SERVICE` only while a listener is on a privileged port, and opens no firewall ports.
- README: pip install, Nix usage, and a NixOS service example.

## Why

The proxy could only be consumed as a container. Anyone deploying it on NixOS had to vendor a package definition into their own configuration — which is exactly what happened downstream, and is now deleted there in favour of this.

## Not in scope

- The `Dockerfile` and its CI workflow are untouched.
- No Nix job in CI; the runner has no Nix. The build is reproducible locally with `nix flake check`.
- `version` is static and tracks the latest tag (`0.3.0`); bump it with the tag.

## Verification

- `nix flake check` — package builds, 14 tests pass inside the build.
- Consumed from a downstream NixOS host with `--override-input`: the unit's `ExecStart` resolves to the module's own build, and that flake's checks pass too.

---------

Co-authored-by: Emma Thorpe <emma.thorpe@citrix.com>
Reviewed-on: #16
v0.4.0
2026-08-21 13:26:51 +01:00
lyrathorpe 4bde4f884d feat: respect BACKEND_MUTATE to avoid mutating backend mailboxes by default; add tests and docs
Build and publish container / build (push) Successful in 7m8s
v0.3.0
2026-06-17 18:43:22 +01:00
lyrathorpeandEmma Thorpe 9a4bab33e2 feat: ignore client-supplied POP3 credentials (#15)
Build and publish container / build (push) Successful in 12m15s
Accept any POP3 `USER`/`PASS` from the client and discard them. The proxy always authenticates to the IMAP backend with the configured `BACKEND_IMAP_USER` / `BACKEND_IMAP_PASS`.

## Changes

- `handle_user` / `handle_pass`: accept client credentials unconditionally, no validation.
- `authenticate`: always use backend credentials; remove the fallback that connected with client-supplied credentials when backend credentials were unset. Raise a clear configuration error when backend credentials are missing.
- Tests: client credentials are ignored; missing backend credentials are reported.

Closes #14

---------

Co-authored-by: Emma Thorpe <emma.thorpe@citrix.com>
Reviewed-on: #15
v0.2.0
2026-06-17 18:16:37 +01:00
lyrathorpe e51740b8db Document unauthenticated listener exposure (#13)
Adds a Security section: the front-end POP3/SMTP listeners are unauthenticated and must be bound to a trusted internal network only. Closes #9

Reviewed-on: #13
Co-authored-by: Lyra Thorpe <iam@emmathe.dev>
Co-committed-by: Lyra Thorpe <iam@emmathe.dev>
2026-06-17 17:33:51 +01:00
lyrathorpe 4ab12f8ce6 Cache pip before install and fix cache key expansion (#12)
Moves the actions/cache step ahead of the install step and uses the runner.os Actions expression in the cache key. Closes #8

Reviewed-on: #12
Co-authored-by: Lyra Thorpe <iam@emmathe.dev>
Co-committed-by: Lyra Thorpe <iam@emmathe.dev>
2026-06-17 17:33:37 +01:00
lyrathorpe 7930235efd Run container as non-root user (#11)
Build and publish container / build (push) Successful in 5m59s
Adds a dedicated non-root user and switches to it before CMD. Verified the container runs as a non-root uid. Closes #7

Reviewed-on: #11
Co-authored-by: Lyra Thorpe <iam@emmathe.dev>
Co-committed-by: Lyra Thorpe <iam@emmathe.dev>
2026-06-17 17:33:23 +01:00
lyrathorpe bde999185a Fix POP3/SMTP correctness and IMAP robustness (#10)
Build and publish container / build (push) Has been cancelled
POP3/SMTP proxy correctness fixes.

- RETR now returns the message body (reads the FETCH tuple). Closes #1
- Maildrop snapshotted once; DELE marks survive STAT/LIST/UIDL. Closes #2
- RETR/TOP dot-stuff and CRLF-terminate per RFC 1939. Closes #3
- SMTP relays raw bytes, no UTF-8 mangling. Closes #4
- Message sizes batched in one IMAP round-trip off the event loop; IMAP timeout added. Closes #5
- POP3 TOP implemented. Closes #6

pytest: 10 passed.
Reviewed-on: #10
Co-authored-by: Lyra Thorpe <iam@emmathe.dev>
Co-committed-by: Lyra Thorpe <iam@emmathe.dev>
2026-06-17 17:33:09 +01:00
lyrathorpe e05f08995e chore: separate runtime and dev dependencies, add pytest config and CI cache
Build and publish container / build (push) Successful in 8m20s
v0.1.0
2026-06-17 16:40:39 +01:00
lyrathorpe 91d70cf10c test: finalize CI test coverage and fix dependency import path 2026-06-17 16:39:22 +01:00
lyrathorpe aa746b780d test: add pytest coverage and run tests in CI
Build and publish container / build (push) Failing after 1m7s
2026-06-17 16:14:22 +01:00
lyrathorpe 739280f930 fix: correct workflow path filter for proxy_server.py 2026-06-17 16:12:39 +01:00
lyrathorpe e6eca290ba chore: add documented POP3/SMTP proxy scaffold and Renovate config 2026-06-17 16:08:06 +01:00
lyrathorpe a41fbf04da feat(requirements): add a summary of project requirements 2026-06-17 15:53:07 +01:00