Skip to content

feat: complete SipConfiguration attributes for API 2026-04-16#39

Merged
Fivell merged 6 commits into
mainfrom
feat/incoming-auth-credentials
May 5, 2026
Merged

feat: complete SipConfiguration attributes for API 2026-04-16#39
Fivell merged 6 commits into
mainfrom
feat/incoming-auth-credentials

Conversation

@Fivell
Copy link
Copy Markdown
Member

@Fivell Fivell commented Apr 30, 2026

Summary

Completes the API 2026-04-16 SipConfiguration attribute set. Mirrors the Ruby reference PR #80.

5 writable attributes (missed during the original 2026-04-16 rollout)

These attributes the server accepts under API 2026-04-16 and are listed in the public 2026-04-16 changelog, but were absent from both this SDK and the public Postman collection. Server is authoritative — added all five:

Python attribute Wire Type
enabled_sip_registration enabled_sip_registration bool
use_did_in_ruri use_did_in_ruri bool
network_protocol_priority network_protocol_priority NetworkProtocolPriority enum
diversion_inject_mode diversion_inject_mode DiversionInjectMode enum
cnam_lookup cnam_lookup bool

Two new string-backed enums in didww.enums:

  • DiversionInjectModenone, did_number
  • NetworkProtocolPriorityforce_ipv4, force_ipv6, any, prefer_ipv4, prefer_ipv6

2 read-only attributes

Server-generated, returned only when enabled_sip_registration is True:

  • incoming_auth_username
  • incoming_auth_password

The API rejects writes (400 Param not allowed). Read-only semantics are implemented via:

  1. A new _read_only_attrs frozenset declared on TrunkConfiguration (overridable by subclasses) listing keys to strip.
  2. TrunkConfiguration.to_jsonapi() filters these out before producing the JSON:API attributes object.
  3. SipConfiguration declares _read_only_attrs = frozenset({"incoming_auth_username", "incoming_auth_password"}) and exposes the two fields as read-only property (no setter).

This means a caller who loads a configuration from the server (with incoming_auth_* populated) and submits it back through update() will not accidentally echo the credentials and trigger a 400.

Updated fixture

tests/fixtures/voice_in_trunks/list.yaml SIP configuration response was extended with the 2026-04-16 keys (no-registration shape: incoming_auth_*: null) and re-serialized as compact JSON for diff readability.

Misc

  • Bumped to 3.1.0 in pyproject.toml.

Test plan

  • pytest — 294 tests passing
  • New tests cover reader access, enum casting, serialization of writable attrs, and read-only-strip regression
  • CI green (Python 3.9 – 3.13 matrix)

@Fivell Fivell changed the title feat: complete V3.5 SipConfiguration attributes for API 2026-04-16 feat: complete SipConfiguration attributes for API 2026-04-16 May 4, 2026
@Fivell Fivell force-pushed the feat/incoming-auth-credentials branch from 1813c14 to 64a53a4 Compare May 4, 2026 15:01
Fivell added 2 commits May 4, 2026 17:35
Adds the 5 writable + 2 read-only SIP registration attributes
introduced in API 2026-04-16: enabled_sip_registration,
use_did_in_ruri, cnam_lookup, network_protocol_priority,
diversion_inject_mode plus server-generated incoming_auth_username
and incoming_auth_password (returned only when sip_registration is
enabled, stripped from POST/PATCH bodies because the API rejects
writes with 400 Param not allowed).

Includes wire-format coverage of the create / read / disable PATCH
flows, fixture alignment with real sandbox responses, and the
SDK-specific changes needed to land the feature cleanly (typing /
nullability fixes, read-only enforcement at the type level,
constructor / builder ergonomics).
Override the SDK's idiomatic debug/log surface to replace credential
field values with [FILTERED] before they reach default print(),
logger output, debugger inspection, or unhandled exception traces.
The wire payload is unaffected — serializers continue to emit the
real values (or strip read-only ones via the existing read-only
mechanism).

Marks SIP auth_password and the server-generated incoming_auth_*
on SipConfiguration, plus username and password on the
credentials_and_ip authentication method, as sensitive.
@Fivell Fivell force-pushed the feat/incoming-auth-credentials branch 2 times, most recently from 2ff7b95 to ead6eb7 Compare May 4, 2026 16:38
Fivell added 3 commits May 4, 2026 23:57
The server enforces multi-field invariants on the sip_registration
toggle (host / port must be absent when enabled, use_did_in_ruri
must be false when disabled). The SDK applies those cascades
automatically on attribute assignment so caller code never has to
enumerate the rule set:

  - enabled_sip_registration = True  -> host = None, port = None
                                         (always — needed for
                                          PATCH-against-existing-trunk)
  - enabled_sip_registration = False -> use_did_in_ruri = False
  - host = <non-None>                -> enabled_sip_registration = False,
                                         use_did_in_ruri = False

The cascade fires only on application-driven property assignments;
SipConfiguration(attributes={...}) bypasses the setters via
_attributes, so deserialized server responses are unaffected.

Includes regression coverage for the fresh-config case (the cascade
must emit host=None / port=None even when the local _attributes dict
starts empty — a PATCH against a trunk that already has host
persisted on the server side requires explicit nullification on the
wire), plus an end-to-end sandbox example
(examples/voice_in_trunk_sip_registration.py).
Add a SIP registration usage section to the README that explains
the cascade rules and shows the enable / disable examples. The
disable example is a single setHost() / config.host = '...' call —
the cascade flips the dependent fields automatically.
The same __repr__ override that masks credential attributes lived on
two unrelated base classes — TrunkConfiguration and
AuthenticationMethod, each in its own resource hierarchy. Extract the
shared logic plus the _sensitive_attrs frozenset into a
didww.mixins.RedactsSensitiveAttributes mixin; both base classes now
inherit from it and the duplicate is gone.

Behaviour is unchanged — the mixin's __repr__ body is line-for-line
identical to the previous inline methods, and the existing redaction
tests on both base classes continue to pass.
@Fivell Fivell force-pushed the feat/incoming-auth-credentials branch from 31af6db to b8635d1 Compare May 4, 2026 21:58
…README

The example file was created in the cascade commit but the index table
in examples/README.md was not updated alongside it.
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 5, 2026

@Fivell Fivell merged commit b3bdfc2 into main May 5, 2026
13 checks passed
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.

1 participant