Skip to content

SDK modernization - #135

Merged
skupriienko merged 46 commits into
masterfrom
feat/sdk-modernization
Aug 16, 2026
Merged

SDK modernization#135
skupriienko merged 46 commits into
masterfrom
feat/sdk-modernization

Conversation

@skupriienko

@skupriienko skupriienko commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Links:

Jira

Actions:

  • Architecture & Developer Experience (DX):

    • Fluent Payload Builders: Introduced MessageBuilder, SendPayloadBuilder, and TemplateContentBuilder to provide a type-safe, fluent interface for constructing complex v3.1 schemas without manual dictionary manipulation.
    • O(1) Static Route Map (routes.py): Replaced heavy, recursive __getattr__ magic methods with a pre-compiled _ROUTE_MAP registry. This drastically improves CPU cold-boot performance and dynamic route resolution.
    • ChunkedStreamer File Attachments: Implemented memory-safe lazy partitioning for file attachments using 512KB chunks, allowing absolute path attachment resolution without loading entire files into RAM.
    • Jitter Retry Engine: Built a custom JitterRetry policy for requests.Session with exponential backoff and randomized full jitter to handle transient 429/5xx errors and prevent the "Thundering Herd" effect on Mailjet's upstream API.
    • Punycode IDN Routing: Added SecurityGuard.normalize_domain() to automatically and safely encode Internationalized Domain Names (IDNs) in email sender/recipient strings (RFC 3490).
  • Security & Guardrails (OWASP):

    • [Something important] Path Traversal & CRLF Mitigation (CWE-22 / CWE-113): Implemented strict path segment sanitization using urllib.parse.quote(safe="") in Endpoint, and centralized validation in SecurityGuard.sanitize_segment to completely neutralize injection attempts across the request stack.
    • Enterprise Runtime Security: Added opt-in PEP 578 Audit Hooks (sys.addaudithook) managed via the enable_security_audit config attribute to monitor runtime network events for SIEM/SecOps compliance.
    • SSRF & MitM Protection (CWE-918 / CWE-319): Hardened URL parsing in Config to strictly require https:// and valid mailjet.com or local CI loopback hostnames. Integrated SecureHTTPAdapter to strictly enforce TLS 1.2+.
    • Resource Exhaustion Guards (CWE-400): Capped HTMLPart and TextPart builder inputs at 5MB, strictly validated floating-point timeouts (blocking NaN/Infinity), and prevented infinite loops in .stream() by enforcing chunk_size > 0.
    • Secret Hygiene (CWE-316): Implemented SecretAuth to obfuscate API keys in memory dumps/tracebacks, and integrated RedactingFilter to recursively scrub secrets from standard logging outputs.
    • Pre-Flight Deliverability Validation (SpamGuard): Built a lightweight HTML static analyzer that preemptively blocks known inline XSS payloads (<script>, onerror=) before network dispatch.
  • Bug Fixes:

    • Generator Infinite Loop: Fixed a critical bug in Endpoint.stream() where negative/zero chunk sizes or None offsets would cause infinite API pagination loops.
    • Builder Immutability Leak: Added .copy() to TemplateContentBuilder.build() to prevent downstream scripts from accidentally mutating internal builder state.
    • Legacy Serialization Fallback: Fixed the ensure_ascii fallback in Endpoint to properly intercept and serialize list batch payloads instead of just dict objects.
  • Testing, CI/CD & Documentation:

    • Automated Fuzzing: Integrated the Atheris (libFuzzer) code coverage suite into development workflows, exposing a unified orchestration entry point (manage.sh fuzz_all) to continuously prove memory safety. Integrated ClusterFuzzLite via GitHub Actions.
    • Stateful Property Testing: Introduced Hypothesis for mathematically rigorous, rule-based state machine testing against API payloads, configurations, and URL routing logic.
    • Consolidated Tooling: Migrated completely to Ruff as the single source of truth for formatting and linting, purging legacy tools from the pipeline.
    • Supply Chain Security: Hardened the GitHub Actions validation pipeline by implementing scorecard.yml (OpenSSF), Google's osv-scanner, and independent pip-audit security jobs.

Verification & Testing:

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

1. Run the Unit & Integration Test Suite:
Validates core routing, HTTP mappings, builder schemas, and runs live CRUD integration checks.

pytest tests/ -v

2. Run the Stateful Property Suite (Hypothesis):
Executes thousands of dynamic boundary checks against routing interpolation, pagination math, exception hierarchies, and string sanitization.

pytest tests/property/ -v

3. Run the Advanced Fuzzing Suite (Atheris):
Executes mutation coverage across core handlers, parsers, HTML filters, and differential serializers.

bash manage.sh fuzz_all 3600

4. Execute the Interactive Examples:
Runs the unified documentation scripts demonstrating fluent builders, attachment chunking, and pagination streaming.

bash manage.sh test_samples

…drails

- Delegate authentication validation and coercion from Client to SecurityGuard (CWE-113, CWE-316).
- Implement strict ingress checks to block empty strings, CRLF/control characters, and invalid Unicode whitespace in credentials.
- Expand property-based test examples ('@example') and add a dedicated unit test suite for auth validation.
- Append discovered token to the fuzzer dictionary.
@skupriienko skupriienko self-assigned this Aug 7, 2026
Comment thread tests/property/test_routing_properties.py Fixed
@skupriienko skupriienko changed the title Feat/sdk modernization SDK modernization Aug 7, 2026
Comment thread tests/unit/test_client.py Dismissed
Comment thread tests/fuzz/fuzz_client.py Dismissed
Comment thread tests/fuzz/fuzz_client.py Fixed
Comment thread tests/fuzz/fuzz_idempotency_fingerprint.py Fixed
Comment thread tests/fuzz/fuzz_router.py Dismissed
Comment thread tests/fuzz/fuzz_structure_aware.py Dismissed
Comment thread samples/smoke_readme_runner.py Fixed
Comment thread tests/integration/test_client.py Fixed
Comment thread tests/property/test_client_properties.py Fixed
skupriienko and others added 14 commits August 7, 2026 23:41
…ring sanitization'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
…ypes

This commit addresses the remaining linter warnings, structural complexities, and missing static typing annotations.

Specific changes:
- style: Replaced custom '# ruff: ignore' pragmas with standard '# noqa' codes (A004, C901, ARG001, BLE001, RUF027) across all core files.
- refactor(endpoint): Extracted registry and dynamic routing logic from '_build_url' into separate '_resolve_registry_route' and '_resolve_dynamic_route' methods to eliminate C901/PLR0915 complexity errors.
- docs: Restored comprehensive 'Args:' and 'Returns:' docstring blocks for Client and Endpoint methods to satisfy DOC201.
- typing: Restored 'PayloadType' and 'TimeoutType' type hints in endpoint method signatures.
- fix(client): Wrapped '__dir__' return in 'sorted(set(...))' to ensure uniqueness and stable ordering of dynamically exposed attributes.
- test(fuzz): Appended newly discovered optimal token to the Atheris fuzzer dictionary.
…rage

- Safely unpack and validate both bounds of tuple timeouts through SecurityGuard (CWE-400 mitigation).
- Add exhaustive live integration tests covering MessageBuilder, TemplateContentBuilder, endpoint streaming pagination, and custom configuration parameters.
- Pin all mutable Action tags ('v7', 'v4', etc.) to 40-character cryptographic SHAs to prevent supply-chain hijacking (fixes Semgrep/Zizmor warnings).
- Add OpenSSF Scorecard workflow ('scorecard.yml') for continuous repository security analysis.
- Integrate 'zizmor' into commit checks to continuously validate GitHub Actions configuration security.
- Add 'osv-scanner' job to the security workflow for lockfile vulnerability analysis.
- Optimize test execution in 'commit_checks.yaml' using '[test]' extras and Codecov integration.
- Add ClusterFuzzLite workflows.
- Fix CWE-113: Prevent HTTP Request Smuggling by sanitizing headers in client.api_call
- Fix CWE-1333: Eliminate catastrophic backtracking (ReDoS) in secret extraction regex
- Fix CWE-316: Block index and iteration credential extraction on SecretAuth class
- Fix CWE-843: Safely cast timeout to float in validate_timeout to prevent TypeErrors
- Fix fuzzer dictionary syntax: URL encode control chars and hardcode multiplication strings
- ci: Explicitly test package imports and install testing dependencies in commit checks
Comment thread tests/fuzz/fuzz_core.py Fixed
Comment thread tests/integration/test_client.py Fixed
- Removed redundant # type: ignore comments in endpoint.py and guardrails.py to pass mypy strict checks.
- Fixed ruff linter configuration in pyproject.toml by replacing the unknown 'unused-import' rule selector with the correct 'F401' rule code.
- Cleaned up security.yml workflow parameters.
Comment thread tests/property/test_client_properties.py Fixed
Comment thread tests/property/test_routing_properties.py Fixed
Comment thread tests/property/test_security_properties.py Fixed
Comment thread tests/property/test_schemas.py Fixed
This commit finalizes the release candidate with the following polishes:

* Security (CWE-22): Explicitly sanitize 'action_id' in legacy dynamic routing fallbacks to prevent unescaped path traversals.
* Reliability: Prevent 'TypeError' in 'stream()' pagination by safely evaluating 'None' offsets.
* Cleanup: Remove dead '_validate_part_size' code from content builders.
* Testing: Remove orphaned 'Config.__getitem__' unit tests and constrain Hypothesis property generation bounds to align with new strict security validation rules.
Comment thread tests/unit/test_client.py Dismissed
Comment thread tests/property/test_routing_properties.py Fixed
…oute map

This commit addresses the final CI static analysis requirements for v1.8.0:

* Builders: Remove obsolete 'type: ignore' on 'TemplateContentBuilder.build()'.
* Fuzzing: Remove deprecated dictionary routing checks in 'fuzz_config.py'.
* Routing: Sync '_ROUTE_MAP' comprehensively with Mailjet documentation, natively supporting all analytics, newsletter, and list verification endpoints. Neutralize auto-formatter injection in 'Endpoint._build_url()' to repair downstream integration tests.
* Linting: Restore strict 'ruff' pragmas overriding rogue auto-formatters.
Comment thread tests/property/test_routing_properties.py Fixed
@skupriienko
skupriienko marked this pull request as ready for review August 15, 2026 20:31
This commit fortifies the test and fuzzing infrastructure using patterns proven in the Mailgun SDK:

* Profiling: Isolates 'test_boot.py' using a sterile subprocess to bypass pytest's module cache, revealing true cold-boot speeds.
* Performance: Adds 'tracemalloc' to verify zero memory leaks across 5,000 route resolutions (validating '__slots__').
* Concurrency: Validates the 100-connection HTTPAdapter pool using 'ThreadPoolExecutor' throughput testing.
Comment thread tests/test_perf.py Dismissed
…ation

This commit resolves a structural validation bypass identified by Hypothesis state-machine testing.

If a recipient injection attempt failed (e.g. throwing a ValueError during IDN Punycode normalization), an empty dictionary key '[]' was left behind in the builder payload. Because the 'build()' method historically checked for key existence ('if "To" not in self._payload') rather than checking for truthy content, the empty array successfully bypassed local validation, allowing malformed schemas to hit the network.

* Builders: Upgraded recipient validation to strictly verify array contents ('if not self._payload.get(...)').
* Tests: Hardened the RuleBasedStateMachine to safely trap and discard expected IDN ValueErrors generated by chaotic Hypothesis 'st.emails()' strings.
Comment thread tests/property/test_builder_state.py Dismissed
Comment thread tests/property/test_builder_state.py Fixed
…est runners

This commit finalizes the sample suite modernization:
* Core: Improved exception DX to surface detailed Mailjet API error messages, whitelisted multipart 'files' in security guardrails, and corrected v1 Content API route mapping.
* Samples: Replaced static placeholders with dynamic resource lookups, implemented idempotent 'upsert' logic for singleton webhooks and parse routes, fixed CSV import payload keys, and ensured safe future-dated campaign scheduling.
Comment thread samples/contacts_sample.py Dismissed
Comment thread samples/statistic_sample.py Fixed
Comment thread tests/property/test_builder_state.py Fixed
Comment thread tests/property/test_builder_state.py Fixed
Comment thread samples/statistic_sample.py Dismissed
Comment thread samples/smoke_readme_runner.py Dismissed
@skupriienko
skupriienko merged commit 77f6abe into master Aug 16, 2026
27 checks passed
@skupriienko
skupriienko deleted the feat/sdk-modernization branch August 16, 2026 10: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