Skip to content

Fix SIP URI scheme handling: follow AOR scheme (sip:/sips:) and raise RegistrationError on failure#22

Merged
codingjoe merged 6 commits intotranscribe-callfrom
copilot/sub-pr-8
Mar 13, 2026
Merged

Fix SIP URI scheme handling: follow AOR scheme (sip:/sips:) and raise RegistrationError on failure#22
codingjoe merged 6 commits intotranscribe-callfrom
copilot/sub-pr-8

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 13, 2026

TLS-registered clients were receiving SIP/2.0 403 Forbidden and other error responses because the code used hardcoded URI schemes in REGISTER requests and Contact headers, ignoring the scheme configured in the AOR. The URI scheme (sip: or sips:) is now taken directly from the configured AOR, and any unexpected REGISTER response raises a descriptive RegistrationError.

Changes

  • RegistrationError — new exception class (exported from __all__) raised when a REGISTER response is unexpected; message includes the server's status code and reason phrase (e.g. "403 Forbidden")
  • registrar_uri — preserves the AOR scheme verbatim: sips:[email protected]REGISTER sips:example.com, sip:[email protected]REGISTER sip:example.com
  • _build_contact(user=None) — helper that builds the Contact URI using the AOR scheme: sips: AOR → <sips:user@host:port>; sip: AOR over TLS → <sip:user@host:port;transport=tls>; used by both register() and _answer()
  • response_received() — raises RegistrationError("{status_code} {reason}") immediately for any unexpected REGISTER response; no silent retries or state mutation
# sips: AOR (carrier requires end-to-end TLS)
REGISTER sips:example.com SIP/2.0
Contact: <sips:[email protected]:5061>

# sip: AOR over TLS
REGISTER sip:example.com SIP/2.0
Contact: <sip:[email protected]:5061;transport=tls>

💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 13, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • stun.cloudflare.com
    • Triggering command: /usr/bin/python3 python3 -m pytest tests/sip/test_protocol.py::TestRegistration -x -q (dns block)
    • Triggering command: /usr/bin/python3 python3 -m pytest tests/sip/test_protocol.py -x -q -k contact (dns block)
    • Triggering command: /usr/bin/python3 python3 -m pytest tests/sip/test_protocol.py -q ACCEPT (dns block)
  • www.rfc-editor.org
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node /home/REDACTED/work/_temp/ghcca-node/node/bin/node --enable-source-maps /home/REDACTED/work/_temp/copilot-developer-action-main/dist/index.js (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title [WIP] Implement call transcription Fix 403 Forbidden on TLS REGISTER: use sip: with transport=tls per RFC 5630 Mar 13, 2026
Copilot AI requested a review from codingjoe March 13, 2026 16:27
@codingjoe
Copy link
Copy Markdown
Owner

@copilot we want to be as secure as possible. Does the RFC have any suggestions for fallback implementations? Can we try the most secure version and fall back?

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 13, 2026

@copilot we want to be as secure as possible. Does the RFC have any suggestions for fallback implementations? Can we try the most secure version and fall back?

RFC 5630 §4 treats sips: as the preferred scheme when TLS is in use but acknowledges that many servers only support sip: with transport=tls — a fact-of-life fallback rather than an explicit RFC procedure.

Implemented in 265152b:

  • First attempt (over TLS): REGISTER sips:example.com with Contact: <sips:alice@host:port> — strongest, mandates end-to-end TLS
  • On 403 Forbidden: logs a warning, sets _sips_downgraded = True, retries with REGISTER sip:example.com and Contact: <sip:alice@host:port;transport=tls> — still encrypted, just without the strict end-to-end guarantee
  • No infinite loop: a second 403 after downgrade raises NotImplementedError

A _build_contact() helper centralises the URI-scheme logic so register() and _answer() stay consistent.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • stun.cloudflare.com
    • Triggering command: /usr/bin/python3 python3 -m pytest tests/sip/test_protocol.py::TestRegistration -x -q (dns block)
    • Triggering command: /usr/bin/python3 python3 -m pytest tests/ -q --ignore=tests/test_audio.py (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title Fix 403 Forbidden on TLS REGISTER: use sip: with transport=tls per RFC 5630 RFC 5630 SIP URI scheme negotiation: try sips: first, fall back to sip:;transport=tls on 403 Mar 13, 2026
@codingjoe
Copy link
Copy Markdown
Owner

pre-commit.ci run

@codingjoe codingjoe marked this pull request as ready for review March 13, 2026 16:54
Copilot AI review requested due to automatic review settings March 13, 2026 16:54
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.68%. Comparing base (4437716) to head (6fdb78f).

Additional details and impacted files
@@                 Coverage Diff                 @@
##           transcribe-call      #22      +/-   ##
===================================================
+ Coverage            94.62%   94.68%   +0.05%     
===================================================
  Files                   16       16              
  Lines                 1303     1317      +14     
===================================================
+ Hits                  1233     1247      +14     
  Misses                  70       70              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates SIP registration behavior to follow RFC 5630 scheme negotiation: try sips: first over TLS, and automatically fall back to sip: (with transport=tls in Contact) when servers reject sips: with 403 Forbidden, improving interoperability with carriers.

Changes:

  • Add _sips_downgraded state and implement 403-driven one-time retry with downgraded URI scheme in response_received().
  • Centralize Contact header construction via _build_contact() and use it for both REGISTER and INVITE answers.
  • Change CLI default AOR scheme from sips: to sip: and update related tests/docs.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
voip/sip/protocol.py Implements sips:sip: downgrade logic, adds _build_contact(), and adjusts registrar URI selection based on TLS + downgrade state.
voip/__main__.py Defaults CLI-generated AOR to sip: instead of sips:.
tests/test_main.py Updates CLI tests to match the new default AOR scheme.
tests/sip/test_protocol.py Adds/updates tests for registrar URI selection, Contact formatting under downgrade, and 403 retry behavior.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +419 to +426
logger.warning(
"REGISTER rejected with 403 Forbidden while using sips: URIs; "
"server may not support sips: — retrying with sip:;transport=tls "
"(RFC 5630 §4 fallback)"
)
self._sips_downgraded = True
asyncio.create_task(self.register())
return
Copy link
Copy Markdown
Owner

@codingjoe codingjoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot I changed my mind and merged some upstream changes. Follow the protocol (sip/sips) supplied by the AON. No more fallback behavior. Fail the registration with a helpful exception message (the reponse message).

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 13, 2026

@copilot I changed my mind and merged some upstream changes. Follow the protocol (sip/sips) supplied by the AON. No more fallback behavior. Fail the registration with a helpful exception message (the ...

Done in 5415777. The fallback is removed; the code now follows the scheme (sip: or sips:) directly from the configured AOR:

  • registrar_uri preserves the AOR scheme (e.g. sips:[email protected]REGISTER sips:example.com)
  • _build_contact() uses the AOR scheme: sips: AOR → <sips:user@host:port> Contact; sip: AOR over TLS → <sip:user@host:port;transport=tls> Contact
  • Any unexpected REGISTER response (including 403) now raises RegistrationError("{status_code} {reason}") immediately — no retry, no state mutation

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • stun.cloudflare.com
    • Triggering command: /usr/bin/python3 python3 -m pytest tests/ -q --ignore=tests/test_audio.py (dns block)
    • Triggering command: /usr/bin/python3 python3 -m pytest tests/ -q --ignore=tests/test_audio.py ame t[bot] (dns block)
    • Triggering command: /usr/bin/python3 python3 -m pytest tests/ -q --ignore=tests/test_audio.py rev-parse ux_amd64/compile-o --quiet ase,codename,all-W (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title RFC 5630 SIP URI scheme negotiation: try sips: first, fall back to sip:;transport=tls on 403 Fix SIP URI scheme handling: follow AOR scheme (sip:/sips:) and raise RegistrationError on failure Mar 13, 2026
Copilot AI requested a review from codingjoe March 13, 2026 18:32
@codingjoe codingjoe merged commit ab098a7 into transcribe-call Mar 13, 2026
1 check failed
@codingjoe codingjoe deleted the copilot/sub-pr-8 branch March 13, 2026 18:44
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.

3 participants