Skip to content

Releases: solarssk/mail-autodiscover

v0.4.1

Choose a tag to compare

@github-actions github-actions released this 30 Sep 07:43
2f6ddc6

🚀 mail-autodiscover v0.4.1

At a glance

✨ What's new

  • Supply-chain security hardened end to end: CI's own dev-tool installs (ruff, mypy, bandit, pytest, and friends) are now hash-pinned the same way runtime dependencies already were, published container images and each platform's SBOM carry a cryptographically verifiable Sigstore signature, and a Docker layer-caching bug that had silently stopped applying Debian security patches for weeks is fixed.
  • OpenSSF Scorecard now runs against this repository and is shown as a README badge — an independent, public check of the controls this repo already claims.
  • Full solarssk/playbook Tier 2 compliance re-verified end to end, including workflow linting (actionlint + zizmor), Dependabot cooldowns, and the standard type: label taxonomy.
  • Docker Hub's tag list no longer accumulates a new sha-<short> tag on every merge to main — only latest and version tags are published there now.

🎯 What this means

  • No change to the deployed service's behavior, configuration, or API — every change in this release is CI/CD, build-pipeline, and documentation.
  • Starting with this release, verify what you're running: gh attestation verify oci://ghcr.io/solarssk/mail-autodiscover@<digest> --repo solarssk/mail-autodiscover.
  • If you'd pinned a Docker Hub sha-<short> tag from a previous build, note those are no longer published there — GHCR still carries them, or pin a version tag/digest instead.

🛠️ Action required

  • No action required.

🔧 Technical details

✨ Added

  • .github/workflows/lint-workflows.yml (replaces actionlint.yml): lints workflows with both actionlint (correctness) and zizmor (safety: template injection, excessive permissions, unpinned actions, missing Dependabot cooldown), which playbook v0.2.0 makes a Tier 2 requirement together. Runs only when .github/workflows/** or dependabot.yml change.
  • .github/workflows/scorecard.yml: OpenSSF Scorecard, report-only, on push to main, branch-protection changes, and weekly — an independent check of controls this repo already claims. Never gates a merge.
  • .github/workflows/docs-impact.yml: the documentation-impact check as its own workflow (see Changed), with tests/test_check_pr_docs_impact.py covering the script that had none.
  • The playbook's standard type: labels (type: bug, type: feature, type: docs, type: chore). The four existing labels that map one-to-one were renamed in the repository settings, keeping every existing association; topic labels (ci/cd, security, testing, dependencies, outlook, thunderbird, mail-server) stay alongside them. Issue templates, Dependabot PRs, and CONTRIBUTING.md follow the new names.
  • OpenSSF Scorecard badge in README's top badge row, added once scorecard.yml published its first real (non-error) result.
  • CI's own dev-tool installs are hash-pinned, the same way requirements.txt already is: requirements-test.txt, requirements-lint.txt, requirements-typecheck.txt, requirements-security.txt, one per extra each CI job installs from, verified against pyproject.toml in the same job that already verifies requirements.txt.

🔄 Changed

  • Pinned solarssk/playbook's verify-tier to v0.2.0 (was v0.1.1, overdue — the "pinned to the latest release" check was itself only added in v0.2.0, so the old pin could not warn that it was stale).
  • The documentation-impact check now runs on edited too. The declaration lives in the PR description, and a plain pull_request trigger only fires on opened / synchronize / reopened, so correcting the checkbox left the old failing result in place until another commit was pushed. It is its own workflow rather than an edited trigger on ci.yml, which would re-run every other job on every description edit. It also now exempts a PR only when its author is dependabot[bot], no longer by branch name (anyone can open a PR from a branch called dependabot/...).
  • Every Dependabot entry has cooldown: default-days: 7 (a version published minutes ago is the most likely to be a compromised release; security updates ignore it) and adds type: chore next to dependencies. github-actions updates are grouped into one PR, and pydantic-core is ignored as a standalone bump: it is a transitive pin that Dependabot raised without checking pydantic's own constraint, which breaks --require-hashes installs.
  • docker-publish.yml has a workflow-level concurrency: group keyed on ref and commit, alongside its per-job groups. It only serializes truly identical runs, so it cannot evict a release commit's build the way a per-ref group could.
  • Docker Hub no longer receives the sha-<short> tag on every merge to main — only latest is copied there now. Nothing in this workflow ever reads that tag back from Docker Hub (the promote job's own polling only ever checks it on GHCR), so it was pure accumulating clutter on the one registry a human is actually likely to browse. GHCR keeps both tags exactly as before.

🐛 Fixed

  • release.yml could not release a version that had no tag yet — i.e. every new release. Its "tag already exists at a different commit?" check read gh api's output, and gh api writes the error body to stdout even on failure, so a nonexistent tag's 422 JSON ended up in the "existing SHA" variable and was mistaken for a conflict. This blocked the real 0.4.0 release, which had to be completed by hand. The check now reads the response itself and only accepts the exact "no such ref" shape (HTTP 422, "No commit found for SHA:"); any other outcome — a transient 5xx, a rate limit, an empty body — fails the job instead of guessing, since gh release create only honors --target for a tag that does not already exist.
  • Releases created by release.yml had no explicit title, so GitHub displayed the merge commit's message ("Merge pull request #58 from ...") instead of the version. They now use the tag (v0.4.0), like every earlier release.
  • requirements.txt regenerated to resolve a pydantic-core conflict that broke --require-hashes installs.

🔒 Security

  • Hardened every workflow against template injection and excessive permissions, findings zizmor reported that neither actionlint nor CodeQL had caught (26 in total): ${{ }} expanded straight into run: scripts now goes through env: (the high-severity one was the gitleaks scan-range step), and docker-publish.yml no longer grants contents/packages/security-events: write to all three of its jobs — deny-all at the top, each job gets only the scopes it uses. zizmor now runs in CI, so this stays fixed.
  • codeql.yml's and release.yml's write permissions moved from workflow level to their (single) job, closing OpenSSF Scorecard's Token-Permissions finding: a workflow-level grant applies to every job the file will ever have, not just the one it has today.
  • CI's dev-tool installs (ruff, mypy, bandit, pytest, pip-audit, deptry, httpx) now install from the new hash-pinned lockfiles instead of a bare pip install ".[extra]", and codeql.yml's Python analysis now installs from the hash-pinned requirements.txt instead of a bare pip install . — closing OpenSSF Scorecard's Pinned-Dependencies gap for CI/build-time tooling (previously only runtime dependencies and third-party Actions were pinned) and making CodeQL analyze the exact versions actually shipped, not whatever currently satisfies pyproject.toml's >= bounds.
  • The Docker image's apt-get upgrade layer was silently served from docker-publish.yml's build cache on every build after the first one off a given base-image digest (confirmed in the build logs: always reported CACHED), so it stopped applying Debian security patches — surfaced as GitHub code-scanning alerts for OpenSSL CVEs that a real apt-get upgrade would have fixed. Moved the layer to run after COPY/pip install (so busting it doesn't also force those, correctly content-keyed, layers to redo) and added a CACHEBUST build arg set to run_id-run_attempt (not the commit SHA, which would stay identical across a workflow_dispatch or re-run on an unchanged commit and let the cache serve the same stale layer again), forcing it to actually execute on every build. Verified: rebuilding with a new CACHEBUST value did upgrade openssl (3.0.20-1~deb12u2 → 3.0.22-1~deb12u1), confirming the previously cached layer really was stale.
  • docker-publish.yml's promote job now signs the promoted container image with a keyless Sigstore attestation (actions/attest, OIDC via Fulcio/Rekor — no static key to manage), published as an OCI referrer on GHCR and uploaded to the GitHub Release as image.sigstore.json, closing OpenSSF Scorecard's Signed-Releases finding. Verifiable with gh attestation verify oci://ghcr.io/solarssk/mail-autodiscover@<digest>.
  • Each platform's CycloneDX SBOM gets its own signed SBOM attestation too (same keyless Sigstore mechanism, a distinct predicate type from the image provenance above), published to GHCR and uploaded to the GitHub Release as sbom-amd64.sigstore.json / sbom-arm64.sigstore.json.
  • scorecard.yml now feeds ossf/scorecard-action a token with read access to classic branch-protection settings, so its Branch-Protection check can actually run instead of erroring — the default GITHUB_TOKEN can't read them at all (Administration isn't a grantable GITHUB_TOKEN permission). Prefers a GitHub App installation token (AUTOMATION_APP_ID/AUTOMATION_APP_PRIVATE_KEY — a dedicated app for this repo only, not shared with any other project, scoped to Administration: Read-only + Contents: Read-only) over a standing SCORECARD_TOKEN fine-grained PAT, over the action's own GITHUB_TOKEN default — each tier is optional and falls through to the next until one is configured. Each minted installation token expires in about an hour, but the App's own private key does not: it is a long-lived credential like any ot...
Read more

v0.4.0

Choose a tag to compare

@solarssk solarssk released this 09 Sep 15:51
8128314

🚀 mail-autodiscover v0.4.0

At a glance

✨ What's new

  • Images are now also published to Docker Hub (docker.io/solarssk/mail-autodiscover), alongside GHCR, always byte-identical.
  • Releases are now fully automated — merging the version-bump PR is the only manual step.
  • The full solarssk Tier 2 engineering standard is now enforced and documented: mechanical playbook compliance checks, a CycloneDX SBOM per release, and a rewritten SECURITY.md that names concrete risks and their mitigations instead of a flat feature list.
  • CI is significantly faster and catches more: SonarCloud no longer blocks required checks, the test suite now also runs on the exact Python version the container ships, and the built Docker image is smoke-tested before it ever reaches a registry.
  • Fixed a rate-limiter correctness bug: under bursty traffic, an already-throttled client could occasionally slip through a request early.

🎯 What this means

  • Pull from Docker Hub instead of GHCR if you prefer — see docker-compose.dockerhub.yml. Both registries always carry the exact same, already-scanned image and digest.
  • A new version tag is promoted directly from the exact image main already built and scanned for that commit — never rebuilt — so a release is guaranteed to be byte-identical to what was already tested and published.
  • Rate limiting under heavy, bursty traffic is now strictly correct; normal traffic is unaffected.

🛠️ Action required

  • No action required. If you want to switch to Docker Hub, see the updated docker-compose.dockerhub.yml — otherwise nothing changes.

🔧 Technical details

✨ Added

  • release.yml now runs on every push to main and automates the whole release: if the push changed pyproject.toml's version and CHANGELOG.md has a matching ## [X.Y.Z] - YYYY-MM-DD heading, it creates the vX.Y.Z tag and GitHub Release, dispatches docker-publish.yml (GITHUB_TOKEN-created tags don't self-trigger other workflows' push: tags: listeners), and closes the matching vX.Y.Z milestone. Merging the release PR is now the only manual step — matches the automation ssf-transmitter already uses, adapted to this repo's own CHANGELOG format and format_release_notes.py.

  • requirements.txt: hash-pinned lockfile for runtime dependencies, generated with pip-compile. The Docker image now installs from this instead of resolving pyproject.toml's >= bounds fresh on every build, so the exact same dependency versions and artifacts ship every time. CI fails if it drifts from pyproject.toml.

  • CODE_OF_CONDUCT.md.

  • .coderabbit.yaml: automatic CodeRabbit review is off; trigger one on demand by commenting @coderabbitai review on a PR. Matches the same setting already used in ssf-transmitter and wp-critical-css.

  • .github/CODEOWNERS.

  • "Repository standard" pointer in AGENTS.md declaring this repo as Tier 2 of the solarssk engineering standard (solarssk/playbook).

  • README table of contents, badge row, and License section.

  • CycloneDX SBOM generated on version tags and attached to the GitHub Release.

  • "Documentation impact" declaration on pull requests, checked in CI against the actual diff.

  • SECURITY.md now has a "Security controls / CI" table and a stated response-time SLA.

  • Regression tests for the documented "no mailbox enumeration" invariant: two different mailboxes in an allowed domain must get the same response shape and status code across Outlook, Thunderbird, and Apple Mail.

  • .github/workflows/verify-standard.yml: calls solarssk/playbook's reusable verify-tier workflow on every push and PR, mechanically checking this repo against its own declared Tier 2 checklist (SHA-pinning, SECURITY.md, issue templates, concurrency: blocks, and more). Same setup already used by ssf-transmitter.

  • Published images are now also mirrored to Docker Hub (docker.io/solarssk/mail-autodiscover) alongside GHCR. docker-publish.yml copies the already-built, already-scanned GHCR manifest into Docker Hub by digest — never a second build — so both registries always carry byte-identical images with identical Trivy results. latest is now enabled only for main pushes (previously also a clean version tag): main pushes are already serialized against each other, but a tag push runs in its own concurrency group fully parallel to any in-flight main push, so both being eligible to write latest in two registries each could interleave and leave GHCR and Docker Hub's latest pointing at different digests. The release process always tags a commit already pushed to main, so main's own run has already published latest for that content by the time the tag exists. sha-<short> is restricted to main for the same reason: a version tag shares its commit's short SHA with an already-published main run, and the apt-get upgrade in the Dockerfile means two independent builds of that same commit aren't guaranteed to produce the same digest, so the same cross-registry interleaving risk applied there too. Added docker-compose.dockerhub.yml as a Docker-Hub equivalent of the existing docker-compose.ghcr.yml, defaulting to latest rather than a pinned version for now, since no version tag has been published to Docker Hub yet. Also dropped the {{major}}.{{minor}} floating tag (e.g. 1.2) entirely: two different patch releases in the same minor series are two different immutable tags with their own concurrency groups, so nothing serializes them against each other, and both would write the same "1.2" name from genuinely different, both-correct digests — the identical cross-registry interleaving risk as above, but with no single already-serialized run to defer to this time. Serializing all version-tag pushes into one group to fix it would reintroduce the silent-eviction failure mode already rejected at the top of this file (a third tag arriving mid-build would drop a queued release's image and SBOM entirely). The precise per-version tag is immune to this by construction, since no two releases ever share one.

  • New "Compatibility tests (Python 3.14)" CI job: the Dockerfile ships Python 3.14, but the test suite only ran on the 3.12 floor used elsewhere in CI until now.

  • ci.yml's Docker build job now smoke-tests the built image (/health, /ready, and the Thunderbird config endpoint) before handing off to Trivy, catching a container that builds and scans clean but never actually starts.

  • timeout-minutes set on every CI job, so a hung external dependency (PyPI, SonarCloud, Docker Hub) fails fast instead of blocking up to GitHub's 360-minute default.

  • .github/workflows/actionlint.yml, path-filtered to .github/workflows/**: catches GitHub-Actions-workflow-specific correctness problems (malformed expressions, misspelled with:/needs: names) that CodeQL's actions language analysis has no queries for.

🔄 Changed

  • CLAUDE.md is now a short @AGENTS.md import plus Claude-Code-specific notes, instead of duplicating AGENTS.md in full.
  • docker-publish.yml now scans the actual image about to be pushed with Trivy (gated on fixable HIGH/CRITICAL) before pushing it, instead of only scanning a separate PR-time build that never reaches the registry.
  • ci.yml's secret scan is now scoped to each run's own commit range instead of the gitleaks GitHub Action's full-history default.
  • All workflows now declare a concurrency: group (cancel-on-supersede for CI checks, never-cancel for release/publish workflows).
  • README badges now sit after the description paragraph instead of before it.
  • app/main.py: create_app()'s Thunderbird/Apple Mail handlers and the Outlook POST body are now plain module-level functions instead of nested closures, and a shared _not_found_response() helper replaces four duplicated 404 responses. Reduces SonarCloud-flagged Cognitive Complexity and unused async findings with no behavior change (verified by the full test suite, including the mailbox-enumeration invariant).
  • app/config.py: _shared_validation_errors() is split into four focused validation methods, and the duplicated "mail.example.com"/"example.com" literals are now single constants. Same validation behavior and error messages, lower Cognitive Complexity.
  • app/security.py: SecurityMiddleware.dispatch()'s access-log branching is extracted into _log_access_event(), and the log-sanitizer regex's character class no longer duplicates \t\n\v\f\r between an explicit range and \s (same matched character set, verified against the full BMP). Lower Cognitive Complexity, same logging output.
  • README.md rewritten to match the house style used across solarssk repos (ssf-transmitter as the closest peer): centered badge row (adds Codecov and SonarCloud Quality Gate badges) and platform badge ahead of the description, a collapsed table of contents, a Mermaid "How it works" diagram, and an emoji-tagged Documentation table. Badges now sit before the description again, reversing the earlier "badges after description" change to match the actually-practiced sibling-repo convention rather than the more literal reading of the playbook doc. All content verified against the current repo (endpoints, env vars, compose files, doc links).
  • SECURITY.md's flat "Built-in mitigations" list is now "Main risks and mitigations": four named risks (XXE/XML bombs, oversized-request-body memory exhaustion, log injection, client-IP spoofing), each paired with the specific function and file that mitigates it, plus an explicit "Domain membership is observable — mailbox existence is not" section correcting an earlier draft that implied domain probing was also defended against (it isn't; only mailbox enumeration within an already-allowed domain is). Also corrects the XXE description (defusedxml blocks entity definitions and external references by default, not DTDs themselves) and drops an inaccurate "slow-drip" mitigation claim from the body-size section, pointing instead at reverse-...
Read more

v0.3.3

Choose a tag to compare

@github-actions github-actions released this 21 Jun 20:30
7b315dc

🚀 mail-autodiscover v0.3.3

At a glance

✨ What's new

  • AI coding-agent context files added; documentation corrections.

🎯 What this means

  • CLAUDE.md and AGENTS.md give AI coding assistants (Claude Code, OpenAI Codex, and others) a concise map of the project: architecture, commands, security invariants, and release process. This avoids agents having to re-derive project conventions from scratch on each session.
  • CHANGELOG version links now point to the correct diff range for each release.
  • CONTRIBUTING.md correctly references the docs/ directory instead of the GitHub Wiki, which was superseded in 0.3.0.
  • pyproject.toml project description now includes Apple Mail, which has been supported since 0.2.0.

🛠️ Action required

  • No action required.

🔧 Technical details

✨ Added

  • CLAUDE.md — project context file for Claude Code.
  • AGENTS.md — project context file for OpenAI Codex and other AI agents (mirrors CLAUDE.md).

🔄 Changed

  • Fixed all CHANGELOG version comparison links — each link now points to compare/vPREV...vVERSION for its own release.
  • Updated CONTRIBUTING.md: replaced the stale reference to the GitHub Wiki with the docs/ directory.
  • Updated pyproject.toml description to include Apple Mail profile support.

🐳 Docker tags

ghcr.io/solarssk/mail-autodiscover:0.3.3
docker.io/solarssk/mail-autodiscover:0.3.3
ghcr.io/solarssk/mail-autodiscover:latest
docker.io/solarssk/mail-autodiscover:latest

Portainer / production: pin the semver tag, not latest.

📚 Useful links

v0.3.2

Choose a tag to compare

@github-actions github-actions released this 20 Jun 13:55
94b97c6

🚀 mail-autodiscover v0.3.2

At a glance

✨ What's new

  • Security hardening for the public autodiscover endpoints and their access logs.
  • Maintenance updates for the Docker base image and GitHub secret-scanning action.

🎯 What this means

  • Plain text access logs are harder to spoof. Request-controlled values such as X-Request-ID and URL paths can no longer inject extra log lines or fake key=value fields like status=200.
  • HTTPS deployments now send stricter browser security headers on normal responses and rate-limited 429 responses.
  • The GHCR Docker image now builds on the Python 3.14 slim Bookworm base image.
  • CI secret scanning now uses gitleaks/gitleaks-action v3, which moves the action runtime to Node 24.

🛠️ Action required

  • No configuration changes are required for existing deployments.
  • If you run multiple uvicorn/Gunicorn workers, keep an external rate limiter in front of the service. The built-in limiter is intentionally in-process and each worker has its own counter.

🔧 Technical details

🔒 Security

  • Sanitized X-Request-ID before storing it on request state, returning it to clients, or writing it to logs. Only token-safe characters are kept.
  • Sanitized logged URL paths so control characters, whitespace, and = cannot create forged fields in text-mode access logs.
  • Added Strict-Transport-Security: max-age=63072000 when PUBLIC_BASE_URL uses HTTPS. The header intentionally does not include includeSubDomains by default, because this app cannot know whether sibling subdomains are HTTPS-ready.
  • Added Content-Security-Policy and Permissions-Policy headers.
  • Applied security headers to rate-limited 429 responses as well as normal responses.
  • Replaced xml.sax.saxutils.escape with html.escape(..., quote=False) for XML response text escaping, removing the Bandit B406 warning without changing output behavior.

🔄 Changed

  • Updated Dockerfile from python:3.12-slim-bookworm to python:3.14-slim-bookworm.
  • Updated CI secret scanning from gitleaks/gitleaks-action v2 to v3.
  • Documented the built-in rate limiter's multi-worker limitation in SECURITY.md.

📌 Tests

  • Added regression coverage for request ID sanitization, URL path log sanitization, exact CSP/Permissions-Policy values, HSTS behavior, and security headers on rate-limited responses.

🐳 Docker tags

ghcr.io/solarssk/mail-autodiscover:0.3.2
docker.io/solarssk/mail-autodiscover:0.3.2
ghcr.io/solarssk/mail-autodiscover:latest
docker.io/solarssk/mail-autodiscover:latest

Portainer / production: pin the semver tag, not latest.

📚 Useful links

v0.3.1

Choose a tag to compare

@solarssk solarssk released this 12 Jun 12:20
249446c

🚀 mail-autodiscover v0.3.1

At a glance

✨ What's new

  • Security hardening for reverse-proxy client IP handling and stricter production validation of TRUSTED_PROXY_IPS.

🛠️ Action required

  • No action required.

🔧 Technical details

🐛 Fixed

  • Prefer X-Real-IP over X-Forwarded-For when the direct peer is a trusted proxy, preventing spoofed leftmost XFF entries from bypassing rate limits or polluting logs.
  • Parse X-Forwarded-For from right to left, skipping trusted proxy hops, when X-Real-IP is missing or invalid.

🔄 Changed

  • In production, every non-empty TRUSTED_PROXY_IPS entry must be a valid IP or CIDR; invalid tokens now fail startup instead of being silently ignored.
  • Nginx reverse-proxy docs now recommend X-Forwarded-For $remote_addr instead of $proxy_add_x_forwarded_for for single-hop deployments.

🐳 Docker tags

ghcr.io/solarssk/mail-autodiscover:0.3.1
docker.io/solarssk/mail-autodiscover:0.3.1
ghcr.io/solarssk/mail-autodiscover:latest
docker.io/solarssk/mail-autodiscover:latest

Portainer / production: pin the semver tag, not latest.

📚 Useful links

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 11 Jun 23:23
ea2045a

🚀 mail-autodiscover v0.3.0

At a glance

✨ What's new

  • Production-complete release before 1.0: multi-domain YAML config, deployment docs, /ready, and optional JSON access logs.

🎯 What this means

  • You can run one container for multiple mail domains via mounted config/config.yaml, or keep the existing single-profile ENV mode.
  • Reverse-proxy, DNS, client, and troubleshooting guides now live in docs/.

🛠️ Action required

  • If you upgrade from 0.2.x, review the updated README and mount ./config:/config:ro when using YAML mode.
  • Set TRUSTED_PROXY_IPS when TRUST_PROXY_HEADERS=true in production (unchanged from 0.2.2).

🔧 Technical details

✨ Added

  • Optional multi-domain YAML config via CONFIG_FILE with per-domain IMAP/SMTP/POP3 settings.
  • GET /ready readiness endpoint for container and reverse-proxy health checks.
  • Optional structured JSON access logs via STRUCTURED_JSON_LOGS=true.
  • In-repo deployment guides under docs/ plus sample multi-domain config in config/config.example.yaml.

🔄 Changed

  • Apple Mail .mobileconfig downloads now use clearer per-domain filenames and mailbox-specific profile labels.
  • Docker Compose examples now mount /config and expose the new config/logging settings.

🐛 Fixed

  • Reject YAML config files that define an empty domains map instead of silently falling back to ENV mode.

🐳 Docker tags

ghcr.io/solarssk/mail-autodiscover:0.3.0
docker.io/solarssk/mail-autodiscover:0.3.0
ghcr.io/solarssk/mail-autodiscover:latest
docker.io/solarssk/mail-autodiscover:latest

Portainer / production: pin the semver tag, not latest.

📚 Useful links

v0.2.3

Choose a tag to compare

@github-actions github-actions released this 11 Jun 22:44
33982d2

🚀 mail-autodiscover v0.2.3

At a glance

✨ What's new

  • This is a small follow-up release that closes a rate-limit configuration gap introduced in 0.2.2.

🎯 What this means

  • Production deployments now reject RATE_LIMIT_MAX_CLIENTS <= 0 instead of accepting a value that would silently weaken throttling behavior.

🛠️ Action required

  • No action required if you already use a positive RATE_LIMIT_MAX_CLIENTS value.
  • If you explicitly set RATE_LIMIT_MAX_CLIENTS=0 or a negative value, replace it with a positive number before upgrading.

🔧 Technical details

🐛 Fixed

  • Reject non-positive RATE_LIMIT_MAX_CLIENTS values when rate limiting is enabled, preventing ineffective throttling caused by immediate client-eviction behavior.

🐳 Docker tags

ghcr.io/solarssk/mail-autodiscover:0.2.3
docker.io/solarssk/mail-autodiscover:0.2.3
ghcr.io/solarssk/mail-autodiscover:latest
docker.io/solarssk/mail-autodiscover:latest

Portainer / production: pin the semver tag, not latest.

📚 Useful links

v0.2.2

Choose a tag to compare

@github-actions github-actions released this 11 Jun 22:28
f03900d

🚀 mail-autodiscover v0.2.2

At a glance

✨ What's new

  • Production deployments now fail fast on unsafe placeholder configuration instead of starting with example.com defaults.
  • Reverse-proxy trust is safer by default: forwarded headers require explicit trusted proxy CIDRs.

🎯 What this means

  • Misconfigured production stacks surface a clear startup error instead of silently serving placeholder mail settings.
  • Rate limiting uses a bounded in-memory store with periodic cleanup, reducing memory growth under abuse.

🛠️ Action required

  • If you run behind a reverse proxy with TRUST_PROXY_HEADERS=true, set TRUSTED_PROXY_IPS to your proxy or Docker bridge CIDRs before upgrading to 0.2.2 in production.
  • Review reverse-proxy access logs: Thunderbird and Apple Mail endpoints pass emailaddress in the query string.

🔧 Technical details

🔒 Security

  • Default TRUST_PROXY_HEADERS changed to false; empty TRUSTED_PROXY_IPS no longer trusts all peers.
  • X-Forwarded-For and X-Real-IP values are validated as real IP addresses before use.
  • Production startup validation for HTTPS PUBLIC_BASE_URL, real domains, and proxy trust settings.

✨ Added

  • RATE_LIMIT_MAX_CLIENTS and RATE_LIMIT_CLEANUP_INTERVAL_SECONDS for bounded rate-limit storage.
  • Stable UUIDv5 identifiers in Apple .mobileconfig profiles (re-download updates the same profile).
  • Healthcheck in docker-compose.ghcr.yml.

🔄 Changed

  • TRUST_PROXY_HEADERS default is now false in application config, .env.example, and GHCR compose.
  • Trivy blocks CRITICAL vulnerabilities on pull requests; main keeps advisory SARIF upload.

🐛 Fixed

  • docker-compose.ghcr.yml port mapping now respects CONTAINER_PORT.
  • Apple .mobileconfig PayloadIdentifier values are account-specific so multiple mailboxes on one domain do not collide.
  • docker-compose.ghcr.yml default IMAGE_TAG matches the release version (0.2.2).

🐳 Docker tags

ghcr.io/solarssk/mail-autodiscover:0.2.2
docker.io/solarssk/mail-autodiscover:0.2.2
ghcr.io/solarssk/mail-autodiscover:latest
docker.io/solarssk/mail-autodiscover:latest

Portainer / production: pin the semver tag, not latest.

📚 Useful links

v0.2.1

Choose a tag to compare

@github-actions github-actions released this 11 Jun 20:31
2a0192b

🚀 mail-autodiscover v0.2.1

At a glance

✨ What's new

  • The project now lives at mail-autodiscover, with GHCR images published only under ghcr.io/solarssk/mail-autodiscover.
  • Documentation moved to the GitHub Wiki, and the public Python API is now documented with module docstrings.

🎯 What this means

  • New installs have one canonical repository and container image name.
  • Admins follow wiki links from the README instead of the removed in-repo wiki/ folder.

🛠️ Action required

  • Pull ghcr.io/solarssk/mail-autodiscover instead of the retired ghcr.io/solarssk/autodiscover package path.
  • Pin IMAGE_TAG=0.2.1 (or newer) in production rather than the old autodiscover image tags.

🔧 Technical details

🔄 Changed

  • GitHub repository renamed to mail-autodiscover; GHCR images publish as ghcr.io/solarssk/mail-autodiscover
  • Documentation now links to the GitHub Wiki instead of the in-repo wiki/ folder
  • Replace flaky GitHub CodeQL default setup with explicit .github/workflows/codeql.yml
  • Add docstrings across the app/ package for public API and security helpers

🐳 Docker tags

ghcr.io/solarssk/mail-autodiscover:0.2.1
docker.io/solarssk/mail-autodiscover:0.2.1
ghcr.io/solarssk/mail-autodiscover:latest
docker.io/solarssk/mail-autodiscover:latest

Portainer / production: pin the semver tag, not latest.

📚 Useful links

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 10 Jun 16:04
1abfbed

🚀 mail-autodiscover v0.2.0

At a glance

✨ What's new

  • This release makes reverse-proxy deployments safer, adds a simple landing page, and introduces Apple Mail profile downloads.

🎯 What this means

  • Admins get clearer logging, better control over forwarded headers, and a cleaner user-facing entry point.
  • End users on iPhone, iPad, and Mac can install a mail profile instead of entering all settings by hand.

🛠️ Action required

  • If you run the service behind a reverse proxy, review and set TRUSTED_PROXY_IPS for your own proxy or Docker network ranges.
  • If you deploy with Portainer or GHCR images, prefer the pinned 0.2.0 tag in production.

🔧 Technical details

✨ Added

  • TRUSTED_PROXY_IPS / FORWARDED_ALLOW_IPS so forwarded client IP headers are trusted only from your configured proxy CIDRs
  • ACCESS_LOG_SKIP_PATHS to reduce noise from health checks and static asset requests
  • Apple Mail .mobileconfig profiles (GET /mail/ios.mobileconfig, /.well-known/apple-mail.mobileconfig)
  • HTML landing page, robots.txt, favicon.ico, apple-touch-icon.png
  • docker-compose.ghcr.yml example for Portainer / GHCR deployments

🔄 Changed

  • Unified access logs now show client_ip, method, endpoint, and status in a single line
  • GET / now returns a small landing page instead of JSON metadata
  • /health is no longer rate limited

🔒 Security

  • Forwarded headers are honored only when the direct peer matches TRUSTED_PROXY_IPS when that setting is present

🐳 Docker tags

ghcr.io/solarssk/mail-autodiscover:0.2.0
docker.io/solarssk/mail-autodiscover:0.2.0
ghcr.io/solarssk/mail-autodiscover:latest
docker.io/solarssk/mail-autodiscover:latest

Portainer / production: pin the semver tag, not latest.

📚 Useful links