Skip to content

Refactor SDK architecture and harden security guardrails#44

Open
skupriienko-mailgun wants to merge 36 commits into
mainfrom
refactor-sdk-architecture
Open

Refactor SDK architecture and harden security guardrails#44
skupriienko-mailgun wants to merge 36 commits into
mainfrom
refactor-sdk-architecture

Conversation

@skupriienko-mailgun

@skupriienko-mailgun skupriienko-mailgun commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Links:

Jira

Actions:

  • Architecture & Developer Experience (DX):

  • Completely decoupled the monolithic client.py into highly cohesive, single-responsibility modules (builders.py, config.py, endpoints.py, security.py, types.py, etc.).

  • Introduced MailgunMessageBuilder and MailgunTemplateBuilder to provide a fluent, autocomplete-friendly way to construct complex payloads (handling v:, h:, and o: prefixes automatically).

  • Fixed Context Managers (__enter__/__exit__ and __aenter__/__aexit__) for Client and AsyncClient to guarantee underlying TCP connection pools are gracefully closed.

  • Added a .stream() generator to Endpoint and AsyncEndpoint for automatic, memory-safe traversal of cursor-based pagination URLs.

  • Added dry_run=True Zero-Leak Sandbox Mode to safely intercept and mock network requests during local development and CI pipelines.

  • Added TypedDict contracts (e.g., SendMessagePayload) to enable IDE autocomplete and compile-time validation via mypy.

  • Completely refactored the mailgun/examples/ directory to cleanly group synchronous and asynchronous equivalents side-by-side using strict context manager patterns.

  • Deleted legacy mailgun/handlers/utils.py, strictly centralizing path sanitization in the new SecurityGuard class.

  • Security & Guardrails:

  • CWE-319 (Protocol Downgrade): Enforced a strict minimum TLS 1.2+ protocol context via SecureHTTPAdapter and ssl_context configurations to prevent MITM downgrade attacks.

  • CWE-316 (Cleartext Storage): Integrated a centralized RedactingFilter to automatically scrub Mailgun API credentials and webhook secrets from all standard log outputs.

  • CWE-316 (Memory Purging): Explicitly zeroed-out the auth tuples and HTTP headers in memory upon Client.close() and AsyncClient.aclose() teardown.

  • CWE-22 & CWE-400 (Path Traversal & Resource Exhaustion): Implemented strict local attachment guardrails (SecurityGuard.validate_attachment_path and check_file_size) to block LFI attempts and fail-fast on files exceeding Mailgun's 25MB boundary.

  • CWE-400 (Uncontrolled Resource Consumption): Hardened sanitize_timeout to strictly enforce finite, positive integer/float boundaries against malicious timeout injection.

  • Enterprise Security Audit Hooks: Implemented native Python PEP 578 sys.audit events (e.g., mailgun.api.request) for Zero-Trust enterprise observability.

  • Path Segment Sanitization: Hardened SecurityGuard.sanitize_path_segment() to strictly canonicalize and URL-encode inputs, neutralizing edge-case Path Traversal and Injection attacks during dynamic route building.

  • Bug Fixes:

  • Fixed internal request data formatting and dynamic routing resolution across various API handlers.

  • Resolved outstanding strict-mode MyPy errors and Ruff linting violations (e.g., F401, PLC0415) across the core package and test suites.

  • Testing, CI/CD & Supply Chain:

  • Vastly expanded SDK test coverage by introducing rigorous unit, integration, regression, Hypothesis (property-based), and Atheris fuzzing tests.

  • Integrated osv-scanner, CodeQL, pip-audit, Bandit, and Semgrep into GitHub Actions to automatically block insecure transitive dependencies and validate code security.

Verification & Testing:

To verify these changes locally, ensure your environment variables (APIKEY and DOMAIN, and others) are set, then run the following commands:

1. Run the Unit Test Suite (Fast):
Validates the core routing logic, data structures, and mock handlers.

pytest tests/unit/ -v

2. Run the Live Routing Meta-Test (No state mutation):
Proves the SDK correctly constructs URLs for all supported endpoints by hitting live Mailgun servers (expects 200, 400, 401, or 403 responses; tests fail if the Python SDK crashes or generates a 404 bad route).

pytest tests/integration/test_routing_meta_live.py -v -s

3. Run the Full Integration Suite (State mutation):
Executes end-to-end flows against your Sandbox domain (creates/deletes real resources).

pytest tests/integration/tests.py -v

4. Execute the Interactive Smoke Test:
Runs the executable documentation script demonstrating cross-version routing and payload serialization.

python mailgun/examples/smoke_test.py

5. Run the Performance & Cold-Boot Benchmarks:
Validates the new O(1) routing dispatch and __slots__ memory optimizations using our unified DX script.

./manage.sh perf_profile
./manage.sh perf_bench

@skupriienko-mailgun skupriienko-mailgun self-assigned this Jun 23, 2026
Comment thread .github/workflows/security.yml Fixed
Comment thread .github/workflows/security.yml Fixed
Comment thread mailgun/examples/templates_examples.py Fixed
Comment thread tests/fuzz/fuzz_async_client.py Fixed
Comment thread tests/fuzz/fuzz_async_evil_server.py Fixed
Comment thread tests/fuzz/fuzz_async_evil_server.py Fixed
Comment thread tests/fuzz/fuzz_builders.py Fixed
Comment thread tests/fuzz/fuzz_builders.py Fixed
Comment thread tests/fuzz/fuzz_builders.py Fixed
Comment thread tests/fuzz/fuzz_client.py Fixed
Comment thread tests/fuzz/fuzz_config_router.py Fixed
Comment thread tests/fuzz/fuzz_endpoint_lifecycle.py Fixed
@skupriienko-mailgun skupriienko-mailgun changed the title Refactor SDK architecture Refactor SDK architecture and harden security guardrails Jun 23, 2026
skupriienko-mailgun and others added 9 commits June 23, 2026 11:47
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Comment thread tests/fuzz/fuzz_evil_server.py Fixed
Comment thread tests/fuzz/fuzz_evil_server.py Fixed
Comment thread tests/fuzz/fuzz_headers.py Fixed
Comment thread tests/fuzz/fuzz_log_redaction.py Fixed
Comment thread tests/fuzz/fuzz_logger.py Fixed
Comment thread mailgun/examples/templates_examples.py Fixed
Comment thread mailgun/examples/templates_examples.py Fixed
Comment thread tests/integration/test_integration_coverage.py Fixed
Comment thread tests/integration/test_integration_async.py Fixed
Comment thread mailgun/examples/mailing_lists_examples.py Fixed
Comment thread mailgun/examples/messages_examples.py Fixed
Comment thread mailgun/examples/routes_examples.py Fixed
Comment thread mailgun/examples/templates_examples.py Fixed
Comment thread mailgun/examples/templates_examples.py Fixed
Comment thread tests/integration/test_integration_coverage.py Fixed
Comment thread mailgun/examples/webhooks_examples.py Fixed
Comment thread tests/integration/test_integration_coverage.py Fixed
Comment thread tests/integration/test_integration_async.py Fixed
Comment thread mailgun/client.py Fixed
@mailgun mailgun deleted a comment from github-advanced-security AI Jun 24, 2026
Comment thread mailgun/examples/ip_pools_examples.py Dismissed
Comment thread mailgun/examples/ip_pools_examples.py Dismissed
Comment thread mailgun/examples/ip_pools_examples.py Dismissed
Comment thread mailgun/examples/ips_examples.py Dismissed
Comment thread mailgun/examples/mailing_lists_examples.py Dismissed
Comment thread mailgun/examples/mailing_lists_examples.py Dismissed
Comment thread mailgun/examples/mailing_lists_examples.py Dismissed
Comment thread mailgun/examples/routes_examples.py Dismissed
Comment thread mailgun/examples/routes_examples.py Dismissed
Comment thread mailgun/examples/tags_examples.py Fixed
Comment thread mailgun/examples/suppressions_examples.py Fixed
Comment thread mailgun/examples/tags_examples.py Fixed
Comment thread mailgun/types.py Fixed
Comment thread mailgun/types.py Dismissed
@skupriienko-mailgun skupriienko-mailgun marked this pull request as ready for review June 25, 2026 11:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants