Skip to content

Commit 44e2fcb

Browse files
committed
apply patch to use TlsClientDetailsWithSecureDefaults with default fo webPki
1 parent b390044 commit 44e2fcb

3 files changed

Lines changed: 92 additions & 4 deletions

File tree

crates/stackable-operator/crds/DummyCluster.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,12 @@ spec:
143143
format: uri
144144
type: string
145145
tls:
146-
description: Use a TLS connection. If not specified no TLS will be used.
146+
default:
147+
verification:
148+
server:
149+
caCert:
150+
webPki: {}
151+
description: Configure a TLS connection. If not specified it will default to webPki validation.
147152
nullable: true
148153
properties:
149154
verification:

crates/stackable-operator/src/commons/tls_verification.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub enum TlsClientDetailsError {
2626
},
2727
}
2828

29+
#[repr(transparent)]
2930
#[derive(
3031
Clone, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize,
3132
)]
@@ -35,6 +36,40 @@ pub struct TlsClientDetails {
3536
pub tls: Option<Tls>,
3637
}
3738

39+
#[repr(transparent)]
40+
#[derive(
41+
Clone, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize,
42+
)]
43+
#[serde(rename_all = "camelCase")]
44+
pub struct TlsClientDetailsWithSecureDefaults {
45+
/// Configure a TLS connection. If not specified it will default to webPki validation.
46+
#[serde(default = "default_web_pki_tls")]
47+
pub tls: Option<Tls>,
48+
}
49+
50+
impl std::ops::Deref for TlsClientDetailsWithSecureDefaults {
51+
type Target = TlsClientDetails;
52+
53+
fn deref(&self) -> &TlsClientDetails {
54+
// SAFETY: both types are `#[repr(transparent)]` over `Option<Tls>`, so they share
55+
// the same memory layout and this cast is sound.
56+
//
57+
// This cannot silently break due to struct changes: `#[repr(transparent)]` requires
58+
// exactly one non-zero-sized field, so adding a second real field to either struct
59+
// is a compile error. The only scenario that would NOT be caught at compile time is
60+
// deliberately removing `#[repr(transparent)]` from one of the two structs.
61+
unsafe { &*(self as *const Self as *const TlsClientDetails) }
62+
}
63+
}
64+
65+
fn default_web_pki_tls() -> Option<Tls> {
66+
Some(Tls {
67+
verification: TlsVerification::Server(TlsServerVerification {
68+
ca_cert: CaCert::WebPki {},
69+
}),
70+
})
71+
}
72+
3873
impl TlsClientDetails {
3974
/// This functions adds
4075
///
@@ -165,3 +200,51 @@ pub enum CaCert {
165200
/// so if you got provided with a CA cert but don't have access to the key you can still use this method.
166201
SecretClass(String),
167202
}
203+
204+
#[cfg(test)]
205+
mod tests {
206+
use super::*;
207+
use crate::utils::yaml_from_str_singleton_map;
208+
209+
#[test]
210+
fn tls_client_details_with_secure_defaults_deserialization() {
211+
// No tls key at all → WebPki default kicks in
212+
let parsed: TlsClientDetailsWithSecureDefaults =
213+
yaml_from_str_singleton_map("{}").expect("failed to deserialize empty input");
214+
assert_eq!(parsed.tls, default_web_pki_tls());
215+
216+
// Explicit null → opt out of TLS entirely
217+
let parsed: TlsClientDetailsWithSecureDefaults =
218+
yaml_from_str_singleton_map("tls: null").expect("failed to deserialize tls: null");
219+
assert_eq!(parsed.tls, None);
220+
221+
// Explicit SecretClass value is preserved as-is
222+
let parsed: TlsClientDetailsWithSecureDefaults = yaml_from_str_singleton_map(
223+
"tls:
224+
verification:
225+
server:
226+
caCert:
227+
secretClass: my-ca",
228+
)
229+
.expect("failed to deserialize secretClass");
230+
assert_eq!(
231+
parsed.tls,
232+
Some(Tls {
233+
verification: TlsVerification::Server(TlsServerVerification {
234+
ca_cert: CaCert::SecretClass("my-ca".to_owned()),
235+
}),
236+
})
237+
);
238+
}
239+
240+
#[test]
241+
#[allow(clippy::explicit_auto_deref)]
242+
fn tls_client_details_with_secure_defaults_deref() {
243+
let secure: TlsClientDetailsWithSecureDefaults =
244+
yaml_from_str_singleton_map("{}").expect("failed to deserialize");
245+
246+
// Deref must not panic and must expose the same tls value
247+
let tls_client_details: &TlsClientDetails = &*secure;
248+
assert_eq!(tls_client_details.tls, secure.tls);
249+
}
250+
}

crates/stackable-operator/src/crd/git_sync/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use stackable_shared::time::Duration;
88
use url::Url;
99

1010
use crate::{
11-
commons::tls_verification::TlsClientDetails, crd::git_sync::v1alpha2::Credentials,
12-
versioned::versioned,
11+
commons::tls_verification::TlsClientDetailsWithSecureDefaults,
12+
crd::git_sync::v1alpha2::Credentials, versioned::versioned,
1313
};
1414

1515
mod v1alpha1_impl;
@@ -77,7 +77,7 @@ pub mod versioned {
7777
/// If `http.sslCAInfo` is also set via `gitSyncConf` (the `--git-config` option) then a warning will be logged.
7878
/// If not specified no TLS will be used, defaulting to github/lab using commonly-recognised certificates.
7979
#[serde(flatten)]
80-
pub tls: TlsClientDetails,
80+
pub tls: TlsClientDetailsWithSecureDefaults,
8181
}
8282

8383
#[derive(strum::Display, Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]

0 commit comments

Comments
 (0)