PySSLCertificate#6219
Conversation
WalkthroughAdds a new ssl_cert submodule exposing a Certificate PyO3 type and helpers, integrates it into the main _ssl module, replaces DER-byte returns with Certificate objects for peer/chain APIs, introduces encoding constants, and extends OpenSSL error mapping to include EOF/SSLEOFError. Changes
Sequence Diagram(s)sequenceDiagram
participant Py as Python
participant SSL as _ssl (ssl.rs)
participant Cert as ssl_cert (cert.rs)
participant OpenSSL as OpenSSL
Py->>SSL: getpeercert / get_verified_chain / get_unverified_chain
SSL->>Cert: cert_to_certificate(vm, x509)
Cert->>OpenSSL: inspect/encode X509
OpenSSL-->>Cert: X509 data / bytes
Cert->>Cert: cert_to_dict() or build PySSLCertificate
Cert-->>SSL: PySSLCertificate object(s)
SSL-->>Py: return Certificate object(s)
alt request raw bytes via public_bytes
Py->>Cert: PySSLCertificate.public_bytes(format)
Cert->>OpenSSL: encode (DER/PEM)
OpenSSL-->>Cert: encoded bytes
Cert-->>Py: bytes
end
alt OpenSSL error occurs
OpenSSL-->>SSL: ErrorStack / error
SSL->>SSL: convert_openssl_error(vm, err) (maps EOF→SSLEOFError when applicable)
SSL-->>Py: raise mapped exception
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (4)
stdlib/src/ssl.rs (2)
75-82: Unused import of PySSLCertificate in _sslThis re-import is not needed for exposure; ssl_cert already registers the class via #[pyclass]. Keeping it requires allow(unused_imports). Remove for cleanliness.
- // Re-export PySSLCertificate to make it available in the _ssl module - // It will be automatically exposed to Python via #[pyclass] - #[allow(unused_imports)] - use super::cert::PySSLCertificate; + // PySSLCertificate is registered by cert::ssl_cert; no import needed here.
188-195: Expose and support ENCODING_PEM_AUX consistentlyENCODING_PEM_AUX exists here but is private and unused. To match CPython’s accepted encodings and to let Certificate.public_bytes() accept PEM_AUX, make it pub(crate) and handle it in cert.rs as an alias of PEM.
- #[pyattr] - const ENCODING_PEM_AUX: i32 = sys::X509_FILETYPE_PEM + 0x100; + #[pyattr] + pub(crate) const ENCODING_PEM_AUX: i32 = sys::X509_FILETYPE_PEM + 0x100;Follow-up diff for cert.rs is included in that file’s comment.
stdlib/src/ssl/cert.rs (2)
24-24: Import ENCODING_PEM_AUX and accept it in public_bytes()You added ENCODING_PEM_AUX in _ssl; mirror CPython by treating it like PEM. Also make the constant pub(crate) in ssl.rs.
- use crate::ssl::_ssl::{ENCODING_DER, ENCODING_PEM, convert_openssl_error}; + use crate::ssl::_ssl::{ENCODING_DER, ENCODING_PEM, ENCODING_PEM_AUX, convert_openssl_error};And in public_bytes:
- match format { + match format { x if x == ENCODING_DER => { // DER encoding let der = self .cert .to_der() .map_err(|e| convert_openssl_error(vm, e))?; Ok(vm.ctx.new_bytes(der).into()) } - x if x == ENCODING_PEM => { + x if x == ENCODING_PEM || x == ENCODING_PEM_AUX => { // PEM encoding let pem = self .cert .to_pem() .map_err(|e| convert_openssl_error(vm, e))?; Ok(vm.ctx.new_bytes(pem).into()) } _ => Err(vm.new_value_error("Unsupported format".to_owned())), }
157-187: Prefer std::net for SAN IP formattingManual IPv6 formatting is non‑canonical (uppercase, no compression). Use Ipv4Addr/Ipv6Addr for correct presentation.
- } else if let Some(ip) = gen_name.ipaddress() { - // Parse IP address properly (IPv4 or IPv6) - let ip_str = if ip.len() == 4 { - // IPv4 - format!("{}.{}.{}.{}", ip[0], ip[1], ip[2], ip[3]) - } else if ip.len() == 16 { - // IPv6 - format like: "X:X:X:X:X:X:X:X" (not compressed) - format!( - "{:X}:{:X}:{:X}:{:X}:{:X}:{:X}:{:X}:{:X}", - (ip[0] as u16) << 8 | ip[1] as u16, - (ip[2] as u16) << 8 | ip[3] as u16, - (ip[4] as u16) << 8 | ip[5] as u16, - (ip[6] as u16) << 8 | ip[7] as u16, - (ip[8] as u16) << 8 | ip[9] as u16, - (ip[10] as u16) << 8 | ip[11] as u16, - (ip[12] as u16) << 8 | ip[13] as u16, - (ip[14] as u16) << 8 | ip[15] as u16 - ) - } else { - // Fallback for unexpected length - String::from_utf8_lossy(ip).into_owned() - }; - vm.new_tuple((ascii!("IP Address"), ip_str)).into() + } else if let Some(ip) = gen_name.ipaddress() { + use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + let ip_str = match ip.len() { + 4 => IpAddr::V4(Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3])).to_string(), + 16 => { + let mut seg = [0u16; 8]; + for i in 0..8 { seg[i] = u16::from_be_bytes([ip[2*i], ip[2*i+1]]); } + IpAddr::V6(Ipv6Addr::from(seg)).to_string() + } + _ => String::from_utf8_lossy(ip).into_owned(), + }; + vm.new_tuple((ascii!("IP Address"), ip_str)).into()
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
Lib/test/test_urllib2_localnet.pyis excluded by!Lib/**
📒 Files selected for processing (2)
stdlib/src/ssl.rs(11 hunks)stdlib/src/ssl/cert.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.rs: Format Rust code with the default rustfmt style (runcargo fmt)
Run clippy and fix any warnings or lints introduced by your changes
Follow Rust best practices for error handling and memory management
Files:
stdlib/src/ssl.rsstdlib/src/ssl/cert.rs
{vm,stdlib}/**/*.rs
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use RustPython macros (
pyclass,pymodule,pyfunction, etc.) when implementing Python functionality in Rust
Files:
stdlib/src/ssl.rsstdlib/src/ssl/cert.rs
🧬 Code graph analysis (2)
stdlib/src/ssl.rs (3)
derive-impl/src/util.rs (1)
with(305-317)stdlib/src/ssl/cert.rs (3)
cert_to_certificate(243-245)cert_to_py(248-255)obj2txt(26-51)vm/src/vm/mod.rs (1)
class(568-577)
stdlib/src/ssl/cert.rs (1)
stdlib/src/ssl.rs (1)
convert_openssl_error(1986-2040)
🔇 Additional comments (4)
stdlib/src/ssl.rs (1)
379-384: Good: centralize OID text conversionSwitching to cert::obj2txt avoids duplication and keeps ASN.1 OID formatting consistent across the module.
stdlib/src/ssl/cert.rs (3)
26-51: OBJ_obj2txt wrapper looks good and safeLength probing, allocation, and set_len are in the correct order. UTF‑8 fallback is robust.
66-95: public_bytes(): default and error mapping look goodDefaulting to PEM matches CPython. Error conversion is consistent.
242-255: cert_to_certificate/cert_to_py: API surface looks goodReturning PySSLCertificate for owned X509 and bytes/dict for getpeercert(binary=…) matches expectations. Error conversion via convert_openssl_error is consistent.
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
stdlib/src/ssl.rs (2)
1220-1231: Propagate certificate conversion errors instead of silently dropping certificates.The code still swallows errors with
.ok(), which can mask VM failures and yield incomplete chains. This matches the unresolved past review comment.Apply this diff to propagate errors:
- fn get_unverified_chain(&self, vm: &VirtualMachine) -> Option<PyObjectRef> { + fn get_unverified_chain(&self, vm: &VirtualMachine) -> PyResult<Option<PyObjectRef>> { let stream = self.stream.read(); let chain = stream.ssl().peer_cert_chain()?; - // Return Certificate objects - let certs: Vec<PyObjectRef> = chain - .iter() - .filter_map(|cert| { - // Clone the X509 certificate to create an owned copy - unsafe { - sys::X509_up_ref(cert.as_ptr()); - let owned_cert = X509::from_ptr(cert.as_ptr()); - cert_to_certificate(vm, owned_cert).ok() - } - }) - .collect(); - - Some(vm.ctx.new_list(certs).into()) + let certs: Vec<PyObjectRef> = chain + .iter() + .map(|cert| unsafe { + sys::X509_up_ref(cert.as_ptr()); + let owned_cert = X509::from_ptr(cert.as_ptr()); + cert_to_certificate(vm, owned_cert) + }) + .collect::<PyResult<_>>()?; + Ok(Some(vm.ctx.new_list(certs).into())) }
1248-1259: Propagate certificate conversion errors in verified chain construction.The code still swallows errors with
if let Ok(), which can silently drop certificates. This matches the unresolved past review comment.Apply this diff to propagate errors:
- fn get_verified_chain(&self, vm: &VirtualMachine) -> Option<PyListRef> { + fn get_verified_chain(&self, vm: &VirtualMachine) -> PyResult<Option<PyListRef>> { let stream = self.stream.read(); unsafe { let chain = sys::SSL_get0_verified_chain(stream.ssl().as_ptr()); if chain.is_null() { - return None; + return Ok(None); } let num_certs = sys::OPENSSL_sk_num(chain as *const _); - let mut certs = Vec::new(); + let mut certs: Vec<PyObjectRef> = Vec::with_capacity(num_certs as usize); - // Return Certificate objects for i in 0..num_certs { let cert_ptr = sys::OPENSSL_sk_value(chain as *const _, i) as *mut sys::X509; if cert_ptr.is_null() { continue; } - // Clone the X509 certificate to create an owned copy sys::X509_up_ref(cert_ptr); let owned_cert = X509::from_ptr(cert_ptr); - if let Ok(cert_obj) = cert_to_certificate(vm, owned_cert) { - certs.push(cert_obj); - } + let cert_obj = cert_to_certificate(vm, owned_cert)?; + certs.push(cert_obj); } if certs.is_empty() { - None + Ok(None) } else { - Some(vm.ctx.new_list(certs)) + Ok(Some(vm.ctx.new_list(certs))) } } }
🧹 Nitpick comments (3)
stdlib/src/ssl.rs (1)
2073-2102: Replace magic numbers with named constants and use consistent exception class access.The code uses magic numbers
20and294for OpenSSL error codes, and inconsistently retrieves the SSLEOFError class viavm.class("_ssl", "SSLEOFError")instead ofPySslEOFError::class(&vm.ctx).Define constants for the error codes and use the consistent exception class pattern:
+ // OpenSSL 3.0 error codes + const ERR_LIB_SSL: u32 = 20; + const SSL_R_UNEXPECTED_EOF_WHILE_READING: u32 = 294; + #[track_caller] fn convert_ssl_error( vm: &VirtualMachine, e: impl std::borrow::Borrow<ssl::Error>, ) -> PyBaseExceptionRef { let e = e.borrow(); let (cls, msg) = match e.code() { // ... existing code ... ssl::ErrorCode::SSL => { - // Check for OpenSSL 3.0 SSL_R_UNEXPECTED_EOF_WHILE_READING if let Some(ssl_err) = e.ssl_error() { - // SSL_R_UNEXPECTED_EOF_WHILE_READING = 294 (0x126) - // In OpenSSL 3.0+, unexpected EOF is reported as SSL_ERROR_SSL - // with this specific reason code instead of SSL_ERROR_SYSCALL unsafe { let err_code = sys::ERR_peek_last_error(); let reason = sys::ERR_GET_REASON(err_code); let lib = sys::ERR_GET_LIB(err_code); - // ERR_LIB_SSL = 20, SSL_R_UNEXPECTED_EOF_WHILE_READING = 294 - if lib == 20 && reason == 294 { + if lib == ERR_LIB_SSL && reason == SSL_R_UNEXPECTED_EOF_WHILE_READING { return vm.new_exception( - vm.class("_ssl", "SSLEOFError"), + PySslEOFError::class(&vm.ctx).to_owned(), vec![ vm.ctx.new_int(SSL_ERROR_EOF).into(), vm.ctx .new_str("EOF occurred in violation of protocol") .into(), ], ); } } return convert_openssl_error(vm, ssl_err.clone()); }stdlib/src/ssl/cert.rs (2)
68-95: Consider handling ENCODING_PEM_AUX or documenting why it's unsupported.The parent module exposes
ENCODING_PEM_AUXas a constant, but this method doesn't handle it. Either implement PEM_AUX encoding support or document the limitation.If PEM_AUX support is intended:
x if x == ENCODING_PEM => { // PEM encoding let pem = self .cert .to_pem() .map_err(|e| convert_openssl_error(vm, e))?; Ok(vm.ctx.new_bytes(pem).into()) } + x if x == super::_ssl::ENCODING_PEM_AUX => { + // PEM encoding with auxiliary info + // Note: X509::to_pem() doesn't support AUX format + // Would need to use d2i_X509_AUX_bio or similar + Err(vm.new_not_implemented_error( + "ENCODING_PEM_AUX is not yet supported".to_owned() + )) + } _ => Err(vm.new_value_error("Unsupported format".to_owned())),
167-186: Consider using std::net::Ipv6Addr for simpler IPv6 formatting.The manual bit-shifting works but is verbose. Using the standard library could improve readability.
let ip_str = if ip.len() == 4 { // IPv4 format!("{}.{}.{}.{}", ip[0], ip[1], ip[2], ip[3]) } else if ip.len() == 16 { - // IPv6 - format like: "X:X:X:X:X:X:X:X" (not compressed) - format!( - "{:X}:{:X}:{:X}:{:X}:{:X}:{:X}:{:X}:{:X}", - (ip[0] as u16) << 8 | ip[1] as u16, - (ip[2] as u16) << 8 | ip[3] as u16, - (ip[4] as u16) << 8 | ip[5] as u16, - (ip[6] as u16) << 8 | ip[7] as u16, - (ip[8] as u16) << 8 | ip[9] as u16, - (ip[10] as u16) << 8 | ip[11] as u16, - (ip[12] as u16) << 8 | ip[13] as u16, - (ip[14] as u16) << 8 | ip[15] as u16 - ) + // IPv6 + let octets: [u8; 16] = ip.try_into().expect("length checked"); + std::net::Ipv6Addr::from(octets).to_string() } else { // Fallback for unexpected length String::from_utf8_lossy(ip).into_owned() };Note: If CPython compatibility requires uppercase hex without compression, keep the current implementation.
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
stdlib/src/ssl.rs(11 hunks)stdlib/src/ssl/cert.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.rs: Format Rust code with the default rustfmt style (runcargo fmt)
Run clippy and fix any warnings or lints introduced by your changes
Follow Rust best practices for error handling and memory management
Files:
stdlib/src/ssl.rsstdlib/src/ssl/cert.rs
{vm,stdlib}/**/*.rs
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use RustPython macros (
pyclass,pymodule,pyfunction, etc.) when implementing Python functionality in Rust
Files:
stdlib/src/ssl.rsstdlib/src/ssl/cert.rs
🧬 Code graph analysis (2)
stdlib/src/ssl.rs (3)
derive-impl/src/util.rs (1)
with(305-317)stdlib/src/ssl/cert.rs (3)
cert_to_certificate(243-245)cert_to_py(248-255)obj2txt(26-51)vm/src/vm/mod.rs (1)
class(568-577)
stdlib/src/ssl/cert.rs (1)
stdlib/src/ssl.rs (1)
convert_openssl_error(1986-2040)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: Run snippets and cpython tests (windows-latest)
- GitHub Check: Run snippets and cpython tests on wasm-wasi
- GitHub Check: Check Rust code with rustfmt and clippy
- GitHub Check: Run rust tests (macos-latest)
- GitHub Check: Ensure compilation on various targets
- GitHub Check: Run snippets and cpython tests (ubuntu-latest)
- GitHub Check: Check the WASM package and demo
- GitHub Check: Run rust tests (ubuntu-latest)
- GitHub Check: Run snippets and cpython tests (macos-latest)
- GitHub Check: Run tests under miri
- GitHub Check: Run rust tests (windows-latest)
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
stdlib/src/ssl/cert.rs (1)
107-128: Extract duplicate name_to_py closure to reduce code duplication.The
name_to_pyclosure is defined identically at lines 107-128 and 195-218, violating DRY principles.Also applies to: 195-218
stdlib/src/ssl.rs (1)
1220-1234: Propagate errors instead of swallowing them with.ok().Errors from
cert_to_certificateare silently dropped with.ok(), which can mask allocation or VM failures and yield truncated chains. This was flagged in a previous review but not yet addressed.Change the function signature to return
PyResult<Option<PyObjectRef>>and propagate errors:- fn get_unverified_chain(&self, vm: &VirtualMachine) -> Option<PyObjectRef> { + fn get_unverified_chain(&self, vm: &VirtualMachine) -> PyResult<Option<PyObjectRef>> { let stream = self.stream.read(); let chain = stream.ssl().peer_cert_chain()?; - // Return Certificate objects - let certs: Vec<PyObjectRef> = chain - .iter() - .filter_map(|cert| { - // Clone the X509 certificate to create an owned copy - unsafe { - sys::X509_up_ref(cert.as_ptr()); - let owned_cert = X509::from_ptr(cert.as_ptr()); - cert_to_certificate(vm, owned_cert).ok() - } - }) - .collect(); - - Some(vm.ctx.new_list(certs).into()) + let certs: Vec<PyObjectRef> = chain + .iter() + .map(|cert| unsafe { + sys::X509_up_ref(cert.as_ptr()); + let owned = X509::from_ptr(cert.as_ptr()); + cert_to_certificate(vm, owned) + }) + .collect::<PyResult<_>>()?; + Ok(Some(vm.ctx.new_list(certs).into())) }
🧹 Nitpick comments (1)
stdlib/src/ssl.rs (1)
2072-2101: Consider defining constants for OpenSSL error codes.The magic numbers
20(ERR_LIB_SSL) and294(SSL_R_UNEXPECTED_EOF_WHILE_READING) are hardcoded but well-documented in comments. For better maintainability, consider defining them as constants.Example:
const ERR_LIB_SSL: u32 = 20; const SSL_R_UNEXPECTED_EOF_WHILE_READING: u32 = 294; // Then use in the condition: if lib == ERR_LIB_SSL && reason == SSL_R_UNEXPECTED_EOF_WHILE_READING { // ... }
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
stdlib/src/ssl.rs(10 hunks)stdlib/src/ssl/cert.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.rs: Format Rust code with the default rustfmt style (runcargo fmt)
Run clippy and fix any warnings or lints introduced by your changes
Follow Rust best practices for error handling and memory management
Files:
stdlib/src/ssl/cert.rsstdlib/src/ssl.rs
{vm,stdlib}/**/*.rs
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use RustPython macros (
pyclass,pymodule,pyfunction, etc.) when implementing Python functionality in Rust
Files:
stdlib/src/ssl/cert.rsstdlib/src/ssl.rs
🧬 Code graph analysis (2)
stdlib/src/ssl/cert.rs (1)
stdlib/src/ssl.rs (1)
convert_openssl_error(1985-2039)
stdlib/src/ssl.rs (3)
derive-impl/src/util.rs (1)
with(305-317)stdlib/src/ssl/cert.rs (3)
cert_to_certificate(243-245)cert_to_py(248-255)obj2txt(26-51)vm/src/vm/mod.rs (1)
class(568-577)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: Run snippets and cpython tests on wasm-wasi
- GitHub Check: Check the WASM package and demo
- GitHub Check: Run snippets and cpython tests (macos-latest)
- GitHub Check: Run tests under miri
- GitHub Check: Run snippets and cpython tests (ubuntu-latest)
- GitHub Check: Run snippets and cpython tests (windows-latest)
- GitHub Check: Run rust tests (windows-latest)
- GitHub Check: Run rust tests (macos-latest)
- GitHub Check: Ensure compilation on various targets
- GitHub Check: Run rust tests (ubuntu-latest)
- GitHub Check: Check Rust code with rustfmt and clippy
Sorry, something went wrong.
0c957e7 to
8153d55
Compare
October 27, 2025 12:13
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
stdlib/src/ssl/cert.rs (1)
26-51: Consider defensive error handling over assertions.The function uses
assert!for OpenSSL error conditions (lines 31, 43). While OpenSSL should not return errors for these calls in normal operation, replacing assertions with proper error returns would be more defensive and prevent potential panics.Consider returning
Result<String, ErrorStack>and propagating errors:pub(crate) fn obj2txt(obj: &Asn1ObjectRef, no_name: bool) -> Result<String, ErrorStack> { let no_name = i32::from(no_name); let ptr = obj.as_ptr(); let b = unsafe { let buflen = sys::OBJ_obj2txt(std::ptr::null_mut(), 0, ptr, no_name); if buflen <= 0 { return Err(ErrorStack::get()); } // ... rest of implementation }; // ... }
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
Lib/test/test_urllib2_localnet.pyis excluded by!Lib/**
📒 Files selected for processing (2)
stdlib/src/ssl.rs(10 hunks)stdlib/src/ssl/cert.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.rs: Format Rust code with the default rustfmt style (runcargo fmt)
Run clippy and fix any warnings or lints introduced by your changes
Follow Rust best practices for error handling and memory management
Files:
stdlib/src/ssl/cert.rsstdlib/src/ssl.rs
{vm,stdlib}/**/*.rs
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use RustPython macros (
pyclass,pymodule,pyfunction, etc.) when implementing Python functionality in Rust
Files:
stdlib/src/ssl/cert.rsstdlib/src/ssl.rs
🧬 Code graph analysis (2)
stdlib/src/ssl/cert.rs (1)
stdlib/src/ssl.rs (1)
convert_openssl_error(1987-2041)
stdlib/src/ssl.rs (2)
stdlib/src/ssl/cert.rs (3)
cert_to_certificate(213-215)cert_to_py(218-225)obj2txt(26-51)vm/src/vm/mod.rs (1)
class(568-577)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: Run snippets and cpython tests (windows-latest)
- GitHub Check: Run rust tests (macos-latest)
- GitHub Check: Run snippets and cpython tests (ubuntu-latest)
- GitHub Check: Run snippets and cpython tests (macos-latest)
- GitHub Check: Run tests under miri
- GitHub Check: Check the WASM package and demo
- GitHub Check: Check Rust code with rustfmt and clippy
- GitHub Check: Run rust tests (windows-latest)
- GitHub Check: Ensure compilation on various targets
- GitHub Check: Run snippets and cpython tests on wasm-wasi
- GitHub Check: Run rust tests (ubuntu-latest)
🔇 Additional comments (10)
stdlib/src/ssl.rs (6)
3-4: LGTM: Clean module declaration.The
mod cert;declaration properly introduces the new certificate handling submodule.
31-31: LGTM: Proper module integration.The cert::ssl_cert submodule is correctly wired into the _ssl module, and the imports/re-exports properly expose PySSLCertificate to Python. The past submodule annotation issue has been addressed.
Also applies to: 75-81
383-388: LGTM: Clean delegation to cert module.The refactoring properly delegates OID-to-text conversion to
cert::obj2txt, avoiding code duplication.
1220-1236: LGTM: Proper error propagation and Certificate object construction.The updated
get_unverified_chaincorrectly:
- Propagates errors instead of silently dropping failed conversions (past issue resolved)
- Returns Certificate objects via
cert_to_certificate- Safely manages X509 reference counting with
X509_up_ref
1239-1268: LGTM: Proper error propagation in verified chain construction.The
get_verified_chainnow correctly propagates conversion errors instead of silently dropping certificates. Thecontinueon line 1254 for null pointers is appropriate since it doesn't mask conversion failures.
1987-1990: LGTM: Appropriate visibility change.Making
convert_openssl_errorpub(crate) allows the cert module to properly convert OpenSSL errors while maintaining encapsulation.stdlib/src/ssl/cert.rs (4)
1-6: LGTM: Proper submodule structure.The module exports and
#[pymodule(sub)]annotation correctly define this as a submodule of _ssl, addressing the past review concern.
103-120: LGTM: Clean extraction addresses past duplication.The
name_to_pyfunction properly eliminates the duplicate code identified in previous reviews, with appropriate UTF-8 handling.
227-233: Clarify purpose of _test_decode_cert.The
_test_decode_certfunction is exposed as a Python function but lacks documentation. The leading underscore suggests internal use, but it's unclear if this is meant for:
- Internal testing only
- Public API for certificate debugging
- Temporary scaffolding to be removed
Consider either:
- Adding a docstring explaining its purpose and usage
- Removing it if it was only for development
- Moving it behind a test-only feature flag if it's for testing
/// Test helper to decode a certificate file and return its dictionary representation. /// For internal testing only - not part of the stable API. #[pyfunction] pub(crate) fn _test_decode_cert(path: FsPath, vm: &VirtualMachine) -> PyResult {
68-95: Review comment is incorrect — ENCODING_PEM_AUX is not exposed to Python.ENCODING_PEM_AUX is defined as a private const (not pub and without #[pyattr]), so it is not accessible to Python users. The
public_bytesmethod correctly handles only the exposed formats:ENCODING_DERandENCODING_PEM. Additionally, CPython's ssl.Certificate.public_bytes does not support PEM_AUX, so there is no requirement to implement this format.Likely an incorrect or invalid review comment.
Sorry, something went wrong.
9a2792a
into
RustPython:main
Oct 27, 2025
Summary by CodeRabbit
New Features
Bug Fixes