Skip to content

Strict encryption option #412, hostname_in_certificate option #340, t…#413

Open
olback wants to merge 9 commits intoprisma:mainfrom
olback:tds80
Open

Strict encryption option #412, hostname_in_certificate option #340, t…#413
olback wants to merge 9 commits intoprisma:mainfrom
olback:tds80

Conversation

@olback
Copy link
Copy Markdown

@olback olback commented Apr 8, 2026

Fixes

New

  • Client hostname should be provided in LoginMessage #414 - Provide client hostname in LoginMessage
  • TDS 8.0 and "Strict" encryption option #412 - Add TDS 8.0 and Strict encryption option
    • New default feature flag: tds80, extends the existing feature tds73
    • Added compile-time check to disallow TDS 8.0 without any TLS implementation.
    • Strict option added to EncryptionLevel
      • Connection string parser also updated.
    • Added tds/8.0 ALPN to TLS implementations that support it. ALPN is only requested when EncryptionLevel = Strict. See note below.
    • Client hostname automatically set in login message
      • Added config option to overwrite hostname

New/updated tests

  • Tests
    • Add test cases for encrypt=strict in connection string
    • Add test cases for hostname in certificate in connection string
    • Add test cases for Workstation ID connection string

Qs

  • Should max TLS version be configured when TDS 8.0 is not enabled? Does it matter?
  • Should a user be able to specify min/max TLS versions via the configuration?

NOTE: While not required, ALPN should be set when negotiating TLS. SQL Server will assume tds/8.0 if unset.
image

image

As ffmpeg twitter once said: talk is cheap, send patches

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 8, 2026

Summary by CodeRabbit

  • New Features
    • TDS 8.0 protocol is now the default encryption standard
    • Strict encryption mode with ALPN support for enhanced security
    • Certificate hostname validation configuration option
    • Client/workstation name support in connection strings
    • Improved certificate handling with better file extension recognition

Walkthrough

Adds TDS 8.0 / Strict encryption support and wiring: new tds80 feature, EncryptionLevel::Strict, strict-mode early TLS negotiation and ALPN, hostname-in-certificate and client-name configuration, platform hostname detection for login, CA-path parsing tweaks, TLS verifier updates, and Cargo feature/dependency adjustments.

Changes

Cohort / File(s) Summary
Manifest & feature config
Cargo.toml, src/lib.rs
Added Unix-only libc dep, bumped async-native-tls to 0.5, changed default features to ["tds80","winauth","native-tls"], added tds80 = ["tds73"] feature, and added a compile-time guard requiring a TLS feature when tds80 is enabled.
Encryption enum & wire encoding
src/tds.rs
Added EncryptionLevel::Strict = 4 and as_wire_value() mapping (Strict wire-encodes as 3); unit tests added for as_wire_value.
Client config & ADO.NET parsing
src/client/config.rs, src/client/config/ado_net.rs
Added hostname_in_certificate: Option<String> and client_name: Option<String> to Config; new setters and crate getter; trust_cert_ca now accepts impl Into<PathBuf>; ADO.NET parsing accepts encrypt=strict and new key aliases; tests added.
Connection flow & login code
src/client/connection.rs, src/tds/codec/pre_login.rs
Connection::connect pre-wraps transport with TLS for Strict; login refactored to take Config; tls_handshake reworked to match on EncryptionLevel (explicit Strict path); PreloginMessage uses as_wire_value() and negotiates Strict explicitly.
TLS stream constant & ALPN
src/client/tls_stream.rs
Added pub(crate) const TDS_ALPN_PROTOCOL_NAME: &str = "tds/8.0";.
native-tls adjustments
src/client/tls_stream/native_tls_stream.rs
When encryption == Strict request ALPN for tds/8.0; use case-insensitive CA file-extension checks; use get_hostname_in_certificate() for SNI/verification.
OpenTLS adjustments
src/client/tls_stream/opentls_tls_stream.rs
Log warning that OpenTLS lacks ALPN for Strict (SQL Server will assume TDS 8.0); use get_hostname_in_certificate() for verification hostname.
rustls verifier & TLS1.3 handling
src/client/tls_stream/rustls_tls_stream.rs
Implemented NoCertVerifier::verify_tls13_signature to accept signatures; use get_hostname_in_certificate() for ServerName; case-insensitive CA extension checks; add ALPN when Strict.
Login message hostname detection
src/tds/codec/login.rs
LoginMessage::new() now initializes hostname via new get_hostname() with platform-specific implementations (Windows: GetComputerNameW; Unix: libc::gethostname); added hostname() setter and error logging.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title references three distinct issues (#412, #340, and a truncated reference) and is incomplete, making it vague about the full scope of changes despite being related to the changeset. Complete the title and make it more specific, e.g., 'Add TDS 8.0 strict encryption, hostname in certificate, and client name support' or similar.
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The PR description is comprehensive and directly related to the changeset, covering fixes, new features, test cases, and open questions about the implementation.
Linked Issues check ✅ Passed The PR fully implements the requirement from issue #336 by changing trust_cert_ca to accept impl Into and storing the path directly via path.into().
Out of Scope Changes check ✅ Passed All changes are directly aligned with the stated objectives: TDS 8.0 support, strict encryption, hostname in certificate, client name support, and addressing issue #336.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/client/config.rs (1)

380-390: ⚠️ Potential issue | 🟠 Major

Reject encrypt=strict when tds80 is not compiled in.

This branch is only gated on a TLS backend. A default-features = false build with native-tls or rustls but without tds80 will still accept strict from the connection string and hand an unsupported mode to the connection layer.

🔧 Suggested fix
-                Err(_) if val.eq_ignore_ascii_case("strict") => Ok(EncryptionLevel::Strict),
+                Err(_) if val.eq_ignore_ascii_case("strict") => {
+                    #[cfg(feature = "tds80")]
+                    {
+                        Ok(EncryptionLevel::Strict)
+                    }
+                    #[cfg(not(feature = "tds80"))]
+                    {
+                        Err(crate::Error::Conversion(
+                            "Connection string: `encrypt=strict` requires the `tds80` feature"
+                                .into(),
+                        ))
+                    }
+                }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/config.rs` around lines 380 - 390, The encrypt() parsing currently
accepts "strict" unconditionally; change the branch handling Err(_) if
val.eq_ignore_ascii_case("strict") inside encrypt() so that it only returns
Ok(EncryptionLevel::Strict) when the crate feature "tds80" is enabled (e.g.
using cfg!(feature = "tds80") or #[cfg] gating), and otherwise return an Err
parsed error (reject the value) so non-tds80 builds (default-features = false)
do not accept "strict"; update the match in encrypt() that references
Self::parse_bool and EncryptionLevel to perform this conditional check.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/client/connection.rs`:
- Line 82: Remove the leftover commented-out dead code line that defines a
transport ("// let transport = Framed::new(MaybeTlsStream::Raw(tcp_stream),
PacketCodec);"); it is redundant because transport initialization is handled by
the subsequent match expression—delete that commented line so only the active
match-based transport creation remains (search for the transport variable
initialization and references to MaybeTlsStream and PacketCodec in connection.rs
to locate it).
- Around line 480-485: The code currently matches transport.into_inner() and
uses MaybeTlsStream::Raw(tcp) to call create_tls_stream(...,
TlsPreloginWrapper::new(tcp)).await? with an unreachable!() fallback; replace
that panic-prone fallback with a defensive error return (or at minimum a
debug_assert! plus a clear Err variant) so unexpected variants produce a
Result::Err instead of panicking. Locate the match around transport.into_inner()
in connection.rs and change the unreachable!() arm to return a meaningful error
(or debug_assert! then return a conversion error) so callers of this code
receive a graceful error when MaybeTlsStream is not Raw.

In `@src/client/tls_stream/native_tls_stream.rs`:
- Around line 17-20: The rustls backend currently uses
ClientConfig::builder().with_safe_defaults() without limiting TLS versions,
causing a mismatch with native-tls which caps to TLS 1.2 when the tds80 feature
is disabled; update the rustls client config (the ClientConfig constructed in
rustls_tls_stream.rs) to enforce a maximum of TLS1.2 in the non-tds80 case
(mirror the conditional used in native_tls_stream.rs) by setting the config's
supported protocol versions to only TLS1_2 (e.g., replace or override the
default versions on the created ClientConfig when cfg(not(feature = "tds80"))).

In `@src/tds.rs`:
- Around line 28-29: Prelogin ENCRYPTION currently writes the raw
EncryptionLevel discriminant (used in PreloginMessage::encode) so
EncryptionLevel::Strict ends up as 0x04 on the wire; update prelogin() to remap
Strict into a wire-compatible value (e.g., map EncryptionLevel::Strict to
EncryptionLevel::Required or the 0x01–0x03 equivalent) before
constructing/encoding the PreloginMessage so encode (which does
write_u8(self.encryption as u8)) never emits 0x04; locate the prelogin() method
and apply the mapping there (leave the internal config.encryption unchanged if
needed, only modify the value passed into PreloginMessage).

---

Outside diff comments:
In `@src/client/config.rs`:
- Around line 380-390: The encrypt() parsing currently accepts "strict"
unconditionally; change the branch handling Err(_) if
val.eq_ignore_ascii_case("strict") inside encrypt() so that it only returns
Ok(EncryptionLevel::Strict) when the crate feature "tds80" is enabled (e.g.
using cfg!(feature = "tds80") or #[cfg] gating), and otherwise return an Err
parsed error (reject the value) so non-tds80 builds (default-features = false)
do not accept "strict"; update the match in encrypt() that references
Self::parse_bool and EncryptionLevel to perform this conditional check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b4d3682a-7245-4c64-b7a2-0e566d4ad112

📥 Commits

Reviewing files that changed from the base of the PR and between a6b4fcd and 2634e8c.

📒 Files selected for processing (10)
  • Cargo.toml
  • src/client/config.rs
  • src/client/connection.rs
  • src/client/tls_stream/native_tls_stream.rs
  • src/client/tls_stream/opentls_tls_stream.rs
  • src/client/tls_stream/rustls_tls_stream.rs
  • src/lib.rs
  • src/tds.rs
  • src/tds/codec/login.rs
  • src/tds/codec/pre_login.rs

Comment thread src/client/connection.rs Outdated
Comment thread src/client/connection.rs
Comment thread src/client/tls_stream/native_tls_stream.rs Outdated
Comment thread src/tds.rs
Comment thread src/tds/codec/login.rs Outdated
@olback olback marked this pull request as draft April 9, 2026 11:15
@olback olback marked this pull request as ready for review April 9, 2026 18:19
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
src/tds/codec/login.rs (1)

199-200: 🧹 Nitpick | 🔵 Trivial

Minor: Comment mentions "byte" but buffer is u16 array.

The comment says "1 byte for the null terminator" but the buffer is [0u16; 15 + 1], so it should say "1 element" or "1 WCHAR".

📝 Suggested fix
-            // MAX_COMPUTERNAME_LENGTH is 15 and we need 1 byte for the null terminator
+            // MAX_COMPUTERNAME_LENGTH is 15 and we need 1 WCHAR for the null terminator
             let mut buffer = [0u16; 15 + 1];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/tds/codec/login.rs` around lines 199 - 200, The comment above the buffer
allocation incorrectly says "1 byte for the null terminator" even though the
buffer is a u16 array; update the comment to reflect a 1-element/1 WCHAR null
terminator instead. Locate the comment near the declaration let mut buffer =
[0u16; 15 + 1] (related to MAX_COMPUTERNAME_LENGTH) in src/tds/codec/login.rs
and replace "1 byte" with "1 element" or "1 WCHAR" so the comment accurately
matches the u16 buffer type.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Cargo.toml`:
- Around line 195-196: The default TLS backend was changed in Cargo.toml
(default = ["tds80","winauth","rustls"] and tds80 = ["tds73"]) which is a
breaking change for downstream users relying on native-tls; update the release
notes / CHANGELOG to call out that the default feature set now enables rustls
instead of native-tls, describe the consequences (different TLS behavior and
potential need to compile ring), and add clear migration guidance showing how
consumers can restore the old behavior by explicitly enabling the previous
feature (e.g., selecting native-tls and/or disabling rustls) in their Cargo.toml
or dependency feature list, plus any platform-specific build notes for ring.

In `@src/client/config.rs`:
- Around line 408-410: The parse path silently falls through to parse_bool and
yields a confusing "Not a valid boolean" when the user supplies "strict" but the
crate was compiled without the tds80 feature; update the parsing logic (the
FromStr/parse function that branches to EncryptionLevel::Strict and calls
parse_bool) to explicitly check for val.eq_ignore_ascii_case("strict") when
cfg!(not(feature = "tds80")) and return a clear Err variant/message indicating
that "strict" requires the tds80 feature (or suggest enabling that feature), so
users see a meaningful error instead of the generic parse_bool failure.

In `@src/client/tls_stream/native_tls_stream.rs`:
- Around line 17-19: The async-native-tls dependency is missing the "alpn"
feature required for builder.request_alpns to be available; update the
Cargo.toml dependency entry for async-native-tls to include the "alpn" feature
in its features list (e.g., add "alpn" alongside "runtime-async-std") so calls
like builder.request_alpns(&[super::TDS_ALPN_PROTOCOL_NAME]) compile
successfully.

---

Duplicate comments:
In `@src/tds/codec/login.rs`:
- Around line 199-200: The comment above the buffer allocation incorrectly says
"1 byte for the null terminator" even though the buffer is a u16 array; update
the comment to reflect a 1-element/1 WCHAR null terminator instead. Locate the
comment near the declaration let mut buffer = [0u16; 15 + 1] (related to
MAX_COMPUTERNAME_LENGTH) in src/tds/codec/login.rs and replace "1 byte" with "1
element" or "1 WCHAR" so the comment accurately matches the u16 buffer type.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 501ec9e4-d7c6-4477-b96a-0ec12f4b8299

📥 Commits

Reviewing files that changed from the base of the PR and between 2634e8c and e839e4e.

📒 Files selected for processing (11)
  • Cargo.toml
  • src/client/config.rs
  • src/client/config/ado_net.rs
  • src/client/connection.rs
  • src/client/tls_stream.rs
  • src/client/tls_stream/native_tls_stream.rs
  • src/client/tls_stream/opentls_tls_stream.rs
  • src/client/tls_stream/rustls_tls_stream.rs
  • src/tds.rs
  • src/tds/codec/login.rs
  • src/tds/codec/pre_login.rs

Comment thread Cargo.toml Outdated
Comment thread src/client/config.rs
Comment on lines +408 to +410
Err(_) if val.eq_ignore_ascii_case("strict") && cfg!(feature = "tds80") => {
Ok(EncryptionLevel::Strict)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider improving error message when tds80 feature is disabled.

When encrypt=strict is specified but the tds80 feature is not enabled, the code falls through to return a generic "Not a valid boolean" error from parse_bool. This may confuse users who expect strict to work.

♻️ Proposed improvement for clearer error handling
                 Err(_) if val == "DANGER_PLAINTEXT" => Ok(EncryptionLevel::NotSupported),
-                Err(_) if val.eq_ignore_ascii_case("strict") && cfg!(feature = "tds80") => {
-                    Ok(EncryptionLevel::Strict)
-                }
+                Err(_) if val.eq_ignore_ascii_case("strict") => {
+                    #[cfg(feature = "tds80")]
+                    {
+                        Ok(EncryptionLevel::Strict)
+                    }
+                    #[cfg(not(feature = "tds80"))]
+                    {
+                        Err(crate::Error::Conversion(
+                            "encrypt=strict requires the 'tds80' feature to be enabled".into(),
+                        ))
+                    }
+                }
                 Err(e) => Err(e),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Err(_) if val.eq_ignore_ascii_case("strict") && cfg!(feature = "tds80") => {
Ok(EncryptionLevel::Strict)
}
Err(_) if val.eq_ignore_ascii_case("strict") => {
#[cfg(feature = "tds80")]
{
Ok(EncryptionLevel::Strict)
}
#[cfg(not(feature = "tds80"))]
{
Err(crate::Error::Conversion(
"encrypt=strict requires the 'tds80' feature to be enabled".into(),
))
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/config.rs` around lines 408 - 410, The parse path silently falls
through to parse_bool and yields a confusing "Not a valid boolean" when the user
supplies "strict" but the crate was compiled without the tds80 feature; update
the parsing logic (the FromStr/parse function that branches to
EncryptionLevel::Strict and calls parse_bool) to explicitly check for
val.eq_ignore_ascii_case("strict") when cfg!(not(feature = "tds80")) and return
a clear Err variant/message indicating that "strict" requires the tds80 feature
(or suggest enabling that feature), so users see a meaningful error instead of
the generic parse_bool failure.

Comment on lines +17 to +19
if matches!(config.encryption, crate::EncryptionLevel::Strict) {
builder = builder.request_alpns(&[super::TDS_ALPN_PROTOCOL_NAME]);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

async-native-tls 0.5 request_alpns method TlsConnector

💡 Result:

In async-native-tls 0.5.x, request_alpns is a builder-style method on async_native_tls::TlsConnector that lets you advertise ALPN protocols (e.g. h2, http/1.1) during the TLS handshake:

use async_native_tls::TlsConnector;

let tls = TlsConnector::new()
    .request_alpns(&["h2", "http/1.1"]);

request_alpns ultimately comes from native-tls and is only available when the native-tls crate is built with its alpn feature enabled. In native-tls it’s documented as “Available on crate feature alpn only.” [2] (Reqwest uses the same underlying request_alpns call on a TlsConnector::builder() for ALPN selection.) [3]

Sources: async-native-tls::TlsConnector docs (shows request_alpns(self, protocols: &[&str]) -> Self) [1], native-tls::TlsConnectorBuilder::request_alpns (feature-gated by alpn) [2], reqwest source using tls.request_alpns(...) [3].


🏁 Script executed:

#!/bin/bash
# Check Cargo.toml for async-native-tls dependency and alpn feature
find . -name "Cargo.toml" -type f | head -5 | xargs -I {} sh -c 'echo "=== {} ===" && grep -A 5 "async-native-tls" {}'

Repository: prisma/tiberius

Length of output: 304


🏁 Script executed:

#!/bin/bash
# Find the TDS_ALPN_PROTOCOL_NAME constant definition
rg "TDS_ALPN_PROTOCOL_NAME" -B 2 -A 2

Repository: prisma/tiberius

Length of output: 1053


🏁 Script executed:

#!/bin/bash
# Check if there are any feature flags or default settings that might enable alpn
rg "alpn" -i --type toml

Repository: prisma/tiberius

Length of output: 41


🏁 Script executed:

#!/bin/bash
# Check async-native-tls documentation or source for default features
# Search for any build script or conditional compilation related to alpn
rg "request_alpns" -B 5 -A 5 src/client/tls_stream/native_tls_stream.rs

Repository: prisma/tiberius

Length of output: 429


Add missing alpn feature to async-native-tls dependency.

The code at lines 17-19 calls builder.request_alpns(), which requires the alpn feature on the native-tls crate. However, the async-native-tls dependency in Cargo.toml only enables runtime-async-std:

[dependencies.async-native-tls]
version = "0.5"
features = ["runtime-async-std"]

Update to:

[dependencies.async-native-tls]
version = "0.5"
features = ["runtime-async-std", "alpn"]

Without this feature flag, the request_alpns method will not be available.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/tls_stream/native_tls_stream.rs` around lines 17 - 19, The
async-native-tls dependency is missing the "alpn" feature required for
builder.request_alpns to be available; update the Cargo.toml dependency entry
for async-native-tls to include the "alpn" feature in its features list (e.g.,
add "alpn" alongside "runtime-async-std") so calls like
builder.request_alpns(&[super::TDS_ALPN_PROTOCOL_NAME]) compile successfully.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Cargo.toml`:
- Around line 195-196: The change to the Cargo.toml default features now
enabling tds80 (default = ["tds80", "winauth", "native-tls"]) is a breaking
change for downstream users; update the CHANGELOG/release notes to clearly
document the migration: explain that tds80 is now default, that tds80 includes
tds73 but introduces new behavior (e.g., EncryptionLevel::Strict, ALPN/TLS
handshake differences and TDS 8.0 protocol capabilities), provide the exact
opt-out example using default-features = false and features = ["tds73",
"winauth", "native-tls"], and add a short guidance section listing likely
behavioral differences and how to test/restore previous behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 40a6f707-ca39-4b68-9c7d-35b23def4dd3

📥 Commits

Reviewing files that changed from the base of the PR and between e839e4e and 30f0569.

📒 Files selected for processing (1)
  • Cargo.toml

Comment thread Cargo.toml
Comment on lines +195 to +196
default = ["tds80", "winauth", "native-tls"]
tds80 = ["tds73"]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Document the breaking change in default features.

Changing the default feature set from tds73 to tds80 is a breaking change for downstream users. Users who relied on the previous defaults will now automatically receive TDS 8.0 behavior, including:

  • New EncryptionLevel::Strict support (requires TLS handshake with ALPN)
  • TDS 8.0 protocol capabilities
  • Different connection behavior when using defaults

Users who need the previous behavior must explicitly opt out of default features and select tds73 in their Cargo.toml:

[dependencies]
tiberius = { version = "0.12", default-features = false, features = ["tds73", "winauth", "native-tls"] }

This change should be prominently documented in the CHANGELOG/release notes with migration guidance.

Note: Since tds80 = ["tds73"], the tds80 feature is additive and preserves tds73 behavior while enabling additional functionality. However, the new code paths (Strict encryption, ALPN negotiation) may introduce behavioral differences that users should be aware of.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Cargo.toml` around lines 195 - 196, The change to the Cargo.toml default
features now enabling tds80 (default = ["tds80", "winauth", "native-tls"]) is a
breaking change for downstream users; update the CHANGELOG/release notes to
clearly document the migration: explain that tds80 is now default, that tds80
includes tds73 but introduces new behavior (e.g., EncryptionLevel::Strict,
ALPN/TLS handshake differences and TDS 8.0 protocol capabilities), provide the
exact opt-out example using default-features = false and features = ["tds73",
"winauth", "native-tls"], and add a short guidance section listing likely
behavioral differences and how to test/restore previous behavior.

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