Skip to content

Refactor client#125

Open
skupriienko wants to merge 29 commits intomasterfrom
refactor-client
Open

Refactor client#125
skupriienko wants to merge 29 commits intomasterfrom
refactor-client

Conversation

@skupriienko
Copy link
Copy Markdown
Collaborator

@skupriienko skupriienko commented Mar 31, 2026

Links:

Jira

Actions:

  • Core SDK & Client:

    • Refactor Client to utilize requests.Session for connection pooling, drastically improving performance for sequential requests.
    • Refactor Config into a @dataclass for cleaner configuration state management.
  • Decompose Endpoint._build_url and Client.api_call to resolve cyclomatic complexity (C901), extracting _check_dx_guardrails, _build_csv_url, and telemetry extraction into pure @staticmethods.

    • Define explicit public module interfaces using __all__ in __init__.py to prevent namespace pollution.
    • Centralize HTTP status logging within api_call using standard Python logging, and deprecating legacy custom logging handlers.
  • Implement Graceful Degradation for legacy kwargs (ensure_ascii, data_encoding) and utility functions (parse_response), wrapping them in standard DeprecationWarnings instead of breaking the API.

  • Upgrade the timeout parameter to accept tuple[float, float] and float, increasing the default to 60s to better handle heavy API operations.

  • Security & Developer Experience (DX):

    • Mitigate Path Traversal (CWE-22) by strictly applying urllib.parse.quote to dynamically injected id and action_id path parameters.
    • Mitigate Cleartext Transmission (CWE-319) by validating the https scheme and requiring a valid hostname during Config initialization.
    • Prevent HTTP Header/CRLF Injection by explicitly scanning the Bearer token for newline characters before applying it to the session.
    • Add DX Guardrails to emit logger.warning events when detecting ambiguous routing (e.g., using singular /template in Content API v1 or routing Send API outside of v3/v3.1).
  • Implement Graceful Degradation for legacy HTTP exceptions (AuthorizationError, ActionDeniedError, etc.), restoring them to preserve 100% backward compatibility for existing try/except blocks.

  • Integrate Smart Telemetry to automatically extract Mailjet Trace IDs (CustomID, Campaign, TemplateID) from payloads and inject them into debug logs.

  • Unit & Integration Tests:

    • Delete the monolithic test.py and segregate tests into tests/unit/ (offline mocked tests) and tests/integration/ (live network tests).
    • Migrate legacy unittest classes to modern pytest fixtures, refactoring assertions into the AAA (Arrange, Act, Assert) pattern.
    • Implement comprehensive offline mock tests for internal routing, CSV endpoints, and DX guardrail branches.
    • Implement full Template lifecycle integration tests for both Email API (v3) and Content API (v1), ensuring clean teardown via try/finally.
    • Verify real multipart upload behavior for Content API images.
    • Add comprehensive unit tests for legacy deprecations (test_legacy_deprecations.py) and context manager lifecycle.
  • CI/CD, Linting & Repository Management:

  • Consolidate tooling by migrating completely to Ruff as the single source of truth for formatting and linting, purging legacy tools (Black, Flake8, Pylint, Pydocstyle) from pyproject.toml and environments.

  • Update GitHub Actions to utilize pip caching, verify compiled .whl artifacts using twine check, and expand the testing matrix to include Python 3.14.

    • Update .github/dependabot.yml to group minor/patch updates and scan GitHub Actions.
    • Add explicit test-unit and test-integration targets to the Makefile.
    • Align environment-dev.yaml strictly with pyproject.toml and add typing-extensions for robust cross-version type hinting (<3.11).
  • Documentation & Samples:

    • Update SECURITY.md to reflect exclusive support for the active branch and forbid reporting CVEs via public issues.
    • Update README.md with new Logging & Debugging guides, updated Python compatibility (3.10-3.14), and modern Content API multipart upload examples.
    • Refresh all files in samples/ to safely fetch credentials using os.environ.get().
    • Update CHANGELOG.md
    • Consolidate legacy smoke tests into an executable samples/smoke_readme_runner.py to dynamically test all README examples.

@skupriienko skupriienko self-assigned this Mar 31, 2026
@skupriienko skupriienko changed the title Refactor client (WIP): Refactor client Mar 31, 2026
Added unit and integration tests to ensure that 'TemplateLanguage' (bool)
and 'Variables' (dict) are correctly serialized into JSON and successfully
accepted by the Mailjet Send API v3.1.
- client: add secret redaction (__repr__/__str__), strict timeout validation, and urllib3 Retry adapter for 5xx errors.
- tests: fix TypeError in integration tests by sourcing credentials directly from os.environ.
- tests: add unit tests for OWASP mitigations and adapter mounting.
…radation

This commit introduces significant Developer Experience (DX) improvements while preserving 100% backward compatibility for a seamless 1.x upgrade path.

Key additions & changes:

- Resource Management: Implemented Context Managers (with Client(...)) for automatic TCP connection pooling and socket cleanup.
- Smart Telemetry: Automatically extract Mailjet Trace IDs (CustomID, Campaign, TemplateID) and inject them into debug logs.
- Advanced Timeouts: Upgraded the timeout parameter to accept tuple[float, float] and float, increasing the default to 60s to better handle heavy API operations (e.g., CSV imports, Content API).
- Graceful Degradation: Llegacy exceptions (AuthorizationError, etc.), kwargs (ensure_ascii, data_encoding), and utility functions (parse_response), wrapping them in standard DeprecationWarnings.
- Poka-Yoke Guardrails: Decoupled Magic Method Trap prevention into a pure utility function (validate_attribute_access).
- Executable Documentation: Consolidated legacy smoke tests into smoke_readme_runner.py to dynamically test all README examples.
- Documentation: Refactored README.md to follow DRY principles and highlight modern DX configurations.
- CI/CD: Updated Dependabot groups and aligned GH Actions with master.
- Testing: Added comprehensive unit tests for deprecations and context managers.

Refs: #125
This commit finalizes the migration to Ruff by completely removing legacy
linters and formatters (Black, Flake8, Pylint, Pydocstyle) from the
development environments and project configurations. It also expands
the testing matrix to ensure forward compatibility.

Key changes:

Tooling Consolidation: Removed obsolete dependencies from environment-dev.yaml
and pyproject.toml, establishing Ruff as the single source of truth.

Config Cleanup: Purged dead configuration sections (tool.black, tool.flake8,
tool.autopep8, tool.pydocstyle) from pyproject.toml.

Ruff Alignment: Updated the Ruff ignore list to strictly preserve architectural
constraints and prevent formatter conflicts (e.g., ISC001, COM812).

Forward Compatibility: Added Python 3.14 to the GitHub Actions matrix and
PyPI classifiers.

Runtime Dependencies: Added typing-extensions to environment.yaml and
environment-dev.yaml for robust cross-version type hinting support.

Code Quality: Formatted code, removed unused imports (suppress), and stripped
legacy migration comments from the smoke_readme_runner.py script.

Refs: #125
@skupriienko skupriienko marked this pull request as ready for review April 9, 2026 22:35
@skupriienko skupriienko changed the title (WIP): Refactor client Refactor client Apr 9, 2026
@skupriienko skupriienko requested a review from erz9engel April 9, 2026 22:39
…ience

Major restructuring of the SDK to implement Zero-Trust principles and mitigate several CWE-class vulnerabilities.

Core Architectural Changes:

Decoupled validation and routing logic into a dedicated mailjet_rest.utils.guardrails module (System Decomposition).

Extracted payload preparation (_prepare_payload) and centralized logging (_log_response) from api_call to ensure Single Responsibility.

Updated Smart Telemetry to include automatic log sanitization.

Security Mitigations (Shift-Left):

CWE-113 (CRLF Injection): Strict header validation to block HTTP Request Smuggling.

CWE-117 (Log Forging): Mandatory telemetry sanitization via sanitize_log_trace.

CWE-918 (SSRF): Hostname allow-listing in Config initialization to prevent credential exfiltration.

CWE-601 (Open Redirect): Hard-disabled automatic redirects for all API calls.

CWE-316 (Secret Leakage): Enhanced redaction in repr and str to prevent sensitive data in traces.

Testing and Resilience:

Modernized test suite to use pytest.warns for auditing security warnings instead of brittle log interception.

Upgraded smoke_readme_runner with a safe_cleanup pattern to handle environmental 401 (permissions) and 404 (eventual consistency) errors.

Fixed path traversal assertions to align with standard urllib.parse.quote behavior.

Updated CHANGELOG.md with explicit CWE mapping for security auditing.
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