Skip to content

Parse and validate chronicle:// connection strings - #33

Open
woksin wants to merge 4 commits into
mainfrom
feature/connection-string-parser
Open

woksin wants to merge 4 commits into
mainfrom
feature/connection-string-parser

Conversation

@woksin

@woksin woksin commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Added

  • parse_connection_string() and ChronicleConnectionOptions.parse() parse a chronicle://[<client-id>:<client-secret>@]<host>[:<port>] connection string into immutable, typed ChronicleConnectionOptions without opening a connection. The port defaults to 35000, credentials are percent-decoded, and TLS is on by default. (Parse and validate Chronicle connection strings #2)
  • A connection string without credentials uses the development credentials, so chronicle://localhost:35000 equals chronicle://chronicle-dev-client:chronicle-dev-secret@localhost:35000, as in the .NET client. The values are exported as DEVELOPMENT_CLIENT_ID and DEVELOPMENT_CLIENT_SECRET. A partial set of credentials is rejected. (Parse and validate Chronicle connection strings #2)
  • skipTlsValidation is parsed into skip_tls_validation, which defaults to True like the .NET client. TLS stays on, and skipTlsValidation=false requires a verifiable certificate. (Parse and validate Chronicle connection strings #2)
  • Typed ConnectionStringError subclasses reject missing hosts, invalid ports, incomplete credentials, credentials combined with a non-empty apiKey, unsupported schemes and unsupported options such as auth=..., a non-empty apiKey without credentials, and other query parameters. An empty apiKey is treated as absent. (Parse and validate Chronicle connection strings #2)
  • str() and repr() of the parsed options never expose the client secret.

@woksin woksin self-assigned this Sep 30, 2026
@woksin woksin added the minor Backward-compatible capability addition label Sep 30, 2026
@woksin

woksin commented Sep 30, 2026

Copy link
Copy Markdown
Collaborator Author

Design decisions for reviewers (the issue left these open):

  • Credentials are required in this first shape. A string with no credentials, or only one of client id and secret, raises IncompleteCredentialsError.
  • "Ambiguous authentication" is client credentials combined with an apiKey or auth query parameter (the selectors in the shared connection-string grammar). Used alone, apiKey and auth=none are rejected as unsupported options for now.
  • Every other query parameter (including skipTlsValidation), multiple hosts, chronicle+srv, a non-root path and a fragment raise UnsupportedOptionError/InvalidHostError/UnsupportedSchemeError. The client guide says the TLS relaxation API is a public API decision for this issue; this PR does not make it, so TLS is always on (tls=True).
  • Local gate: ruff format --check ., ruff check ., mypy src, pytest, python -m build, twine check all pass on Python 3.14.7. Python 3.10-3.13 were not available locally; CI covers them.

@woksin
woksin requested a review from einari September 30, 2026 23:36
@woksin

woksin commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

@einari this needs your code-owner review to merge (branch protection requires a reviewer other than the author). Could you take a look?

The UnicodeDecodeError names the offending byte of the client secret. Raise
InvalidCredentialsEncodingError outside the handler so neither __cause__ nor
__context__ carries it.
@einari

einari commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Independent review (prerequisite for OAuth #3, authenticated append #4, parity #36): no blocking defects. One narrow hardening pushed as ba6e10d: InvalidCredentialsEncodingError no longer chains the decoder UnicodeDecodeError (its message names the offending byte of the secret); a spec asserts __cause__/__context__ are None. Note: the description's line about TLS always on predates the later commit; skip_tls_validation now defaults to True as in the .NET builder. Local: ruff, mypy, 148 pytest, build and twine check pass on 3.10-3.14.

@einari

einari commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Independent review passes after secret-safe exception hardening;148 tests/mypy pass on3.10-3.14 and hosted checks green atba6e10d. Current merge is legitimately protected (code-owner review + last-push approval), so I will not bypass it. @woksin please coordinate the protected review/last-push requirement; runtime#3/#4 is proceeding stacked on this accepted API while review is pending. Source of evidence: event-source-worktrees/logs/python-parser-review.status.md.

@einari einari left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved after independent automated review at ba6e10d:148 specs and strict typing across Python3.10-3.14 plus hosted CI. Secret decoder exceptions hardened; options immutable and credentials redacted. This approval does not bypass code-owner or last-push protections; preserve those gates. Runtime uses production certificate/hostname validation despite parser dev-default skipTlsValidation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minor Backward-compatible capability addition

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants