close
Skip to content

Tags: ascoderu/lokole

Tags

0.8.10

Toggle 0.8.10's commit message
fix: Update Docker release and deployment process for improved tagging

Signed-off-by: Mohamad Abuelhagag <mohammed.abuelhagag@gmail.com>

0.8.9

Toggle 0.8.9's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix: Split apache-libcloud versions for Python compatibility (#619)

* fix: Split apache-libcloud versions for Python compatibility

- Server (Python 3.9): apache-libcloud==3.2.0 (stable Cloudflare DNS)
- Client (Python 3.12): apache-libcloud==3.8.0 (Python 3.12 support)

Client Dockerfile installs requirements-webapp.txt after requirements.txt,
so libcloud 3.8.0 overrides 3.2.0 for the client container only.

Fixes Cloudflare DNS issues:
- libcloud 3.6.0: RecordAlreadyExistsError constructor bug
- libcloud 3.8.0: KeyError 'zone_name' in Cloudflare driver
- libcloud 3.2.0: Proven stable with Cloudflare, incompatible with Py3.12

Tested:
- Server: Python 3.9 + libcloud 3.2.0 (all 8 DNS tests pass)
- Client: Python 3.12 + libcloud 3.8.0 (imports work correctly)

* fix: Remove [opwen_email_server] extra from client package install

The client Dockerfile was installing the package with [opwen_email_server] extra,
which pulled in server dependencies (requirements.txt with libcloud 3.2.0).
This conflicted with the client's libcloud 3.8.0.

Client only needs the base package dependencies (requirements-webapp.txt).

* fix: Shorten comments to meet flake8 120 char limit and fix hadolint comment placement

* fix: Make test queue durable for RabbitMQ 4.0+ compatibility

RabbitMQ 4.0+ deprecated transient non-exclusive queues. The integration
test was creating a queue without durable=True, causing CI failures with:
InternalError: Queue.declare: (541) INTERNAL_ERROR - Feature
`transient_nonexcl_queues` is deprecated.

* Revert RabbitMQ fix - was incomplete

* fix: Configure Celery for RabbitMQ 4.0+ compatibility

RabbitMQ 4.0+ deprecated transient non-exclusive queues. This fix:

1. Explicitly defines all task queues as durable using Kombu Queue objects
2. Disables remote control (worker_enable_remote_control=False) to prevent
   creation of non-durable pidbox queues that trigger the deprecation error
3. Updates test queue to be durable

Without these changes, Celery workers fail to start with:
  amqp.exceptions.InternalError: Queue.declare: (541) INTERNAL_ERROR
  Feature `transient_nonexcl_queues` is deprecated.

Tested successfully with RabbitMQ 4.3.1 - all integration tests pass.

* fix: Separate integration test dependencies into requirements-integration.txt

- Created requirements-integration.txt with server dependencies needed by AzureIoc
- Updated Dockerfile to install integration deps in both builder and runtime stages
- Production client (client.env) uses default Ioc without server dependencies
- Integration tests (webapp.env) use AzureIoc with full server dependencies
- Integration tests now pass successfully with BUILD_TARGET=runtime

* fix: RabbitMQ 4.0+ compatibility with explicit durable queues

- Define all 7 task queues explicitly as durable Queue objects
- Disable worker remote control to prevent transient pidbox queues
- Set worker_prefetch_multiplier=1 to avoid deprecated global_qos
- Fixes 'Feature transient_nonexcl_queues is deprecated' errors
- Integration tests pass with RabbitMQ 4.3.1

0.8.8

Toggle 0.8.8's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix: downgrade apache-libcloud to 3.2.0 to fix Cloudflare DNS registr…

…ation (#618)

* fix: downgrade apache-libcloud to 3.2.0 to fix Cloudflare DNS registration

apache-libcloud 3.6.0 introduced incomplete error handling in the
Cloudflare DNS driver. Version 3.6.0 added new error codes (81057, 81058)
with special handling, but when Cloudflare returns errors during record
CREATION (not update), there's no record_id in the context, causing
exception constructors to fail with:
  TypeError: __init__() missing 1 required positional argument: 'record_id'

Version 3.2.0 was the last known working version (used in production
before June 2022 requirements upgrade). It has simpler error handling
where unknown error codes fall back to LibcloudError without requiring
special parameters.

Fixes client registration MX record creation failures.

* fix: update apache-libcloud in requirements-webapp.txt to match server

Both client and server dependencies must use the same libcloud version
to avoid pip resolution conflicts when installing as
opwen_email_client[opwen_email_server].

* fix: upgrade apache-libcloud to 3.9.1 for Python 3.12 support

apache-libcloud 3.2.0 doesn't support Python 3.12 because it tries to
import match_hostname from ssl module, which was removed in Python 3.12.

Python 3.12 support was added in libcloud 3.8.0 (beta) and 3.9.0 (stable).
Upgrading to latest 3.9.1 which should also fix the Cloudflare DNS
parse_error bug that was introduced in 3.6.0.

* fix: use apache-libcloud 3.8.0 for Python 3.9/3.12 compatibility

apache-libcloud 3.9.0+ requires Python 3.10+, but the server uses Python 3.9.
Version 3.8.0 is the last version that supports Python 3.9 while also adding
Python 3.12 (beta) support.

* refactor: improve DNS MX record handling with verification and updates

Changes:
1. Import RecordAlreadyExistsError for type-safe exception handling
2. When MX record already exists, verify it points to correct mail server
3. Automatically update record if it points to wrong server
4. Add comprehensive tests for both scenarios:
   - Record exists with correct value (no update needed)
   - Record exists with wrong value (updates to correct server)

Benefits:
- Prevents silent failures where MX record points to wrong server
- More robust DNS management during client registration
- Type-safe exception handling (no string matching)
- Better logging with before/after values on updates

* style: apply yapf formatting to dns files

0.8.7

Toggle 0.8.7's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fix: Revert server Python to 3.9 for Celery compatibility (#617)

* fix: Revert server Python version to 3.9 for Celery compatibility

Commit c844db6 accidentally upgraded the server (opwen_email_server) from
Python 3.9 to 3.12 along with the client upgrade. This causes Celery
worker to fail with 'RuntimeError: can't start new thread' in production.

The intended architecture (documented in .github/copilot-instructions.md) is:
- Client (opwen_email_client): Python 3.12+ ✓
- Server (opwen_email_server): Python 3.9 (this fix)

Python 3.12 has stricter threading limitations that break Celery's
prefork worker pool. Reverting server to Python 3.9 while maintaining
client at 3.12 restores the documented mixed-version environment.

Changes:
- docker/app/Dockerfile: PYTHON_VERSION 3.12 → 3.9 (server only)
- docker/client/Dockerfile: unchanged (stays at 3.12)

Fixes worker crash loop in production deployment.

* chore: Add production deployment script

Add deploy-production.sh script to simplify production deployments.

Usage:
  ./deploy-production.sh

The script:
- Connects to production VM via SSH
- Pulls latest code and Docker images
- Recreates containers with --force-recreate
- Shows deployment status and next steps

This maintains manual deployment control while simplifying the process
to a single command.

* fix: Remove webapp dependencies from server container

The server container (api/worker) doesn't need client-specific dependencies like mkwvconf (modem configuration). This was causing build failures when mkwvconf wasn't available for Python 3.9.

Only the webapp container needs these dependencies and already installs them via docker/client/Dockerfile.

* fix: Keep webapp deps in builder stage for CI tests

The builder stage needs webapp dependencies for running the full test suite in CI (which includes both client and server tests).

The runtime stage only copies /deps (server wheels) and opwen_email_server, so webapp dependencies don't make it into production containers.

* fix: Separate server and client CI for Python version compatibility

**Problem:**
Server container (Python 3.9) was running ALL tests (client + server) which required webapp dependencies like mkwvconf that need Python 3.12+, causing CI failures.

**Solution:**
1. Split CI into two parallel jobs:
   - test-server: Python 3.9, server code only
   - test-client: Python 3.12, client code only

2. Remove webapp dependencies from server Dockerfile
   - Builder stage: Only server dependencies
   - Runtime stage: Only server code (unchanged)

3. Create separate CI scripts:
   - docker/app/run-ci.sh: Lint/test opwen_email_server only
   - docker/client/run-ci.sh: Lint/test opwen_email_client only

**Result:**
- Server stays at Python 3.9 ✅
- Client stays at Python 3.12 ✅
- No dependency conflicts ✅
- Full test coverage maintained ✅

* fix: Add fasteners to server requirements

opwen_email_server/integration/webapp.py imports opwen_email_client code which transitively needs fasteners. Even though webapp.py is unused in production, it's included in the server package and causes test import failures.

fasteners is needed for test discovery in the server CI.

Tested locally with Python 3.9: 182 tests run successfully with no import errors.

* fix: Set per-job coverage thresholds for split CI

The split CI jobs test server (Python 3.9) and client (Python 3.12)
separately, which reveals lower individual coverage than combined:
- Server tests: 38% of server code
- Client tests: 55% of client code
- Combined: ~80% overall

Set realistic thresholds per job:
- test-server: --fail-under=35 (allows 38%)
- test-client: --fail-under=50 (allows 55%)
- test-local: fail_under=75 (combined, unchanged)

This prevents coverage regressions in each codebase while maintaining
the 75% combined coverage requirement.

* fix: Remove coverage threshold from split CI jobs

Split CI jobs (test-server/test-client) now only validate:
- Code quality (linting, formatting, type checking)
- Test correctness (all tests must pass)
- Python version compatibility (3.9 server, 3.12 client)

Coverage tracking:
- Split jobs generate coverage.xml for Codecov (no threshold)
- test-local job enforces 75% combined coverage (unchanged)

This simplifies CI while maintaining quality standards.

* fix: Override setup.cfg fail_under in split CI jobs

coverage xml was reading fail_under=75 from setup.cfg.
Added --fail-under=0 flag to explicitly disable threshold
for test-server and test-client jobs.

0.8.6

Toggle 0.8.6's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix: Update SendGrid webhook when client_id changes (#616)

When a domain is re-registered or configuration changes generate a new
client_id, SetupSendgridMailbox now updates the existing SendGrid inbound
parse webhook URL instead of silently skipping it. This prevents inbound
emails from being rejected with 'unregistered_client' errors.

Previously, if a mailbox already existed in SendGrid, the code would exit
early without checking if the webhook URL matched the current client_id.
This caused production domains to lose inbound mail after re-registration.

Changes:
- Added http_patch import to sendgrid.py
- Modified SetupSendgridMailbox._run() to compare existing webhook URL
  with expected URL
- When URLs mismatch, PATCH the webhook to update with correct client_id
- Preserves existing spam_check and send_raw settings during update
- Updated test_skips_request_when_domain_already_exists to mock JSON response
- Added test_updates_webhook_when_url_mismatches to verify PATCH behavior

Fixes inbound email loss bug reported for production domains.

0.8.5

Toggle 0.8.5's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix: convert RestartAppComponent to use systemctl instead of supervis…

…orctl (#614)

This fixes the broken service restart mechanism on systemd-only systems.
The RestartAppComponent was trying to call supervisorctl commands which don't
exist on IIAB PR #4398's new systemd-based architecture.

Changes:
- Replace supervisorctl calls with systemctl equivalents
- Map signal types: HUP -> systemctl reload, empty -> systemctl restart
- Convert component names from supervisor format (lokole_gunicorn) to
  systemd format (lokole-gunicorn)

This allows the registration flow to properly restart services after
writing new credentials to settings.env, fixing the issue where
OPWEN_CLIENT_ID remained None in running processes.

0.8.4

Toggle 0.8.4's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix: Add missing @login_required to register view and fix HTTPError h…

…andling (#613)

* fix: Add missing @login_required to register view and fix HTTPError handling

- Register view was checking is_admin on AnonymousUser, causing AttributeError
- Error handler tried to call non-existent .read() method on HTTPError from requests library
- Now uses ex.response.text instead (proper requests HTTPError attribute)

Tested on Python 3.12.12 and 3.13.3 - all imports successful

* fix: Fix continuation line indentation in cli.py

* fix: Fix image type detection URL parsing in email_parser.py

Extract filename from URL before passing to mimetypes.guess_type() since
it only accepts filenames, not full URLs. This was causing images without
Content-Type headers to fail base64 encoding, breaking offline functionality.

Handles query strings correctly: http://example.com/image.png?size=large -> image.png

* chore: Add hadolint ignore directives for unpinned pip install

Ignore DL3013 warning for 'pip install --upgrade pip' since pinning pip version
can cause issues with package installation. This is a known exception to the rule.

0.8.3

Toggle 0.8.3's commit message
fix: update Python version to 3.12 and upgrade pip in Dockerfiles

Signed-off-by: Mohamad Abuelhagag <mohammed.abuelhagag@gmail.com>

0.8.2

Toggle 0.8.2's commit message
Upgrade Python dependencies #593

0.8.0

Toggle 0.8.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
prompt user to provide a sync schedule (#553)

* prompt user to provide a sync schedule after registration

* remove trailing whitespace