Skip to content

https://mobileaws.atlassian.net/browse/CLOUD-2712#3

Open
dlopezallcode wants to merge 1 commit intomainfrom
CLOUD-2712
Open

https://mobileaws.atlassian.net/browse/CLOUD-2712#3
dlopezallcode wants to merge 1 commit intomainfrom
CLOUD-2712

Conversation

@dlopezallcode
Copy link
Copy Markdown

Overview

Fixed two critical security/behavior bugs, removed a duplicate class, added typing corrections for Pylance/pyright, and configured the development environment. The SDK passes 39/39 unit tests with zero type errors.


Implemented Changes

1. verify_signature correction — security bug (src/ccai_python/webhook.py) 🔴

Before: the implementation was a placeholder that always returned True, accepting any signature without verification.

return True  # placeholder — always accepts any signature

After: real implementation with HMAC-SHA256:

expected = hmac.new(secret.encode('utf-8'), body.encode('utf-8'), hashlib.sha256).hexdigest()
return hmac.compare_digest(clean_signature, expected)
  • Uses hmac.compare_digest() for constant-time comparison (prevents timing attacks).
  • Support for sha256= prefix in signature.

Security breaking change: Code that relied on verify_signature() always returning True will now receive False for invalid signatures. Communicate as security fix in changelog.


2. Hardcoded URL fix in Email Service (src/ccai_python/email_service.py) 🔴

Before: the service had the email URL hardcoded to the test environment, ignoring client configuration.

After: uses self.ccai.email_base_url dynamically, which already handles test/prod switching correctly from ccai.py.

Intentional breaking change: Users who didn't pass use_test=True now send emails to production (correct behavior).


3. Removal of duplicate Account class (src/ccai_python/ccai.py)

Before: a duplicate Account class existed in ccai.py that duplicated the canonical class in sms/sms.py, causing import confusion.

After: the Account class in ccai.py was removed. It is imported and re-exported from sms/sms.py:

from .sms.sms import SMS, Account

Example scripts (sms_send.py, mms_send.py) updated to import from ccai_python.sms.sms.


4. Typing corrections for Pylance/pyright

All type errors reported by Pylance in basic mode were fixed. No # type: ignore silencers were used — all errors were corrected in the code.

src/ccai_python/ccai.py:

  • data parameter of request() changed to Optional[Union[Dict[str, Any], List[Any]]] to support webhook payload (array [{...}]).
  • Added Union, List to typing imports.

src/ccai_python/sms/sms.py:

  • CCAIProtocol.request() updated to match actual CCAI.request() signature.
  • SMSOptions fixed: added model_config = {"arbitrary_types_allowed": True} and Field(default=None) on all optional fields.
  • on_progress typed as Optional[Callable[[str], None]] (not builtin callable).
  • Default timeout fixed to 30 (avoids int | None).

src/ccai_python/sms/mms.py:

  • CCAIProtocol.request() updated same as sms.py.

src/ccai_python/webhook.py:

  • WebhookResponse made fully optional with extra = "allow" — API doesn't always return all fields.
  • Unpacking **response fixed with explicit dict(response) conversion.
  • create_handler returns correctly typed Callable[[Dict[str, Any]], Dict[str, Any]].

src/ccai_python/email_send.py, sms_send.py, mms_send.py:

  • os.getenv()os.environ['KEY'] for required variables (avoids str | None).

src/ccai_python/test_real.py:

  • Helper _to_dict(obj) -> dict added: converts Pydantic models, dicts, or lists to first element dict.
  • All .get() accesses go through _to_dict() first.
  • Contact response accesses use direct attributes (res.do_not_text, res.phone).

5. Pylance/pyright configuration (pyrightconfig.json)

Created in project root so Pylance resolves src/ layout imports correctly:

{
  "include": ["src", "tests"],
  "extraPaths": ["src"],
  "pythonVersion": "3.10",
  "typeCheckingMode": "basic"
}

Existing Features (Verified)

The following features were implemented before and verified to continue working:

Service Methods
SMS send(), send_single()
MMS send(), send_single(), send_with_image(), get_signed_upload_url(), upload_image_to_signed_url(), check_file_uploaded() (with MD5 cache)
Email send_campaign(), send_single()
Webhook register(), update(), list(), delete(), verify_signature(), create_handler()
Contact set_do_not_text()
Config use_test, base_url, email_base_url, file_base_url with test/prod switching

Compatibility Notes

  • Account is still imported from ccai_python (re-exported) — backwards compatible for public imports.
  • The verify_signature fix intentionally breaks previous behavior (always True). Communicate in changelog.
  • The Email URL fix may redirect test traffic to production — communicate in changelog.

@dlopezallcode dlopezallcode marked this pull request as ready for review April 16, 2026 19:09
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