@@ -250,9 +250,75 @@ pub fn build(
250250mod tests {
251251 use super :: * ;
252252 use crate :: controller:: build:: properties:: test_support:: {
253- MINIMAL_TRINO_YAML , validated_cluster_from_yaml,
253+ MINIMAL_TRINO_YAML , file_auth_class, validated_cluster_from_yaml,
254+ validated_cluster_from_yaml_with_auth,
254255 } ;
255256
257+ const SERVER_TLS_ONLY_YAML : & str = r#"
258+ apiVersion: trino.stackable.tech/v1alpha1
259+ kind: TrinoCluster
260+ metadata:
261+ name: simple-trino
262+ namespace: default
263+ uid: "e6ac237d-a6d4-43a1-8135-f36506110912"
264+ spec:
265+ image:
266+ productVersion: "479"
267+ clusterConfig:
268+ catalogLabelSelector: {}
269+ tls:
270+ internalSecretClass: null
271+ coordinators:
272+ roleGroups:
273+ default:
274+ replicas: 1
275+ workers:
276+ roleGroups:
277+ default:
278+ replicas: 1
279+ "# ;
280+
281+ const INTERNAL_TLS_ONLY_YAML : & str = r#"
282+ apiVersion: trino.stackable.tech/v1alpha1
283+ kind: TrinoCluster
284+ metadata:
285+ name: simple-trino
286+ namespace: default
287+ uid: "e6ac237d-a6d4-43a1-8135-f36506110912"
288+ spec:
289+ image:
290+ productVersion: "479"
291+ clusterConfig:
292+ catalogLabelSelector: {}
293+ tls:
294+ serverSecretClass: null
295+ coordinators:
296+ roleGroups:
297+ default:
298+ replicas: 1
299+ workers:
300+ roleGroups:
301+ default:
302+ replicas: 1
303+ "# ;
304+
305+ fn cluster_info ( ) -> stackable_operator:: utils:: cluster_info:: KubernetesClusterInfo {
306+ stackable_operator:: utils:: cluster_info:: KubernetesClusterInfo {
307+ cluster_domain : stackable_operator:: commons:: networking:: DomainName :: try_from (
308+ "cluster.local" ,
309+ )
310+ . unwrap ( ) ,
311+ }
312+ }
313+
314+ fn rg ( cluster : & ValidatedCluster , role : & TrinoRole ) -> TrinoRoleGroupConfig {
315+ cluster. role_group_configs [ role]
316+ . values ( )
317+ . next ( )
318+ . expect ( "the fixture defines a role group" )
319+ . clone ( )
320+ }
321+
256322 #[ test]
257323 fn default_renders_includes_coordinator_default_and_query_max_memory_default ( ) {
258324 let cluster = validated_cluster_from_yaml ( MINIMAL_TRINO_YAML ) ;
@@ -280,4 +346,125 @@ mod tests {
280346 Some ( "50GB" )
281347 ) ;
282348 }
349+
350+ #[ test]
351+ fn server_tls_only_uses_server_keystore_dir_and_http_discovery ( ) {
352+ let cluster = validated_cluster_from_yaml ( SERVER_TLS_ONLY_YAML ) ;
353+ let props = build (
354+ & cluster,
355+ TrinoRole :: Coordinator ,
356+ & rg ( & cluster, & TrinoRole :: Coordinator ) ,
357+ & cluster_info ( ) ,
358+ )
359+ . unwrap ( ) ;
360+
361+ assert_eq ! (
362+ props. get( "http-server.https.enabled" ) . map( String :: as_str) ,
363+ Some ( "true" )
364+ ) ;
365+ assert_eq ! (
366+ props. get( "http-server.https.port" ) . map( String :: as_str) ,
367+ Some ( "8443" )
368+ ) ;
369+ assert_eq ! (
370+ props
371+ . get( "http-server.https.keystore.path" )
372+ . map( String :: as_str) ,
373+ Some ( "/stackable/server_tls/keystore.p12" ) ,
374+ ) ;
375+ // Server TLS is on, so insecure HTTP access must not be allowed.
376+ assert_eq ! (
377+ props. get( "http-server.authentication.allow-insecure-over-http" ) ,
378+ None
379+ ) ;
380+ // Internal TLS is off: no internal-communication keystore or FQDN address source.
381+ assert_eq ! (
382+ props. get( "internal-communication.https.keystore.path" ) ,
383+ None
384+ ) ;
385+ assert_eq ! ( props. get( "node.internal-address-source" ) , None ) ;
386+ // Discovery uses http when internal TLS is disabled.
387+ assert ! ( props. get( "discovery.uri" ) . unwrap( ) . starts_with( "http://" ) ) ;
388+ }
389+
390+ #[ test]
391+ fn internal_tls_only_allows_insecure_http_and_uses_internal_keystore_dir ( ) {
392+ let cluster = validated_cluster_from_yaml ( INTERNAL_TLS_ONLY_YAML ) ;
393+ let props = build (
394+ & cluster,
395+ TrinoRole :: Coordinator ,
396+ & rg ( & cluster, & TrinoRole :: Coordinator ) ,
397+ & cluster_info ( ) ,
398+ )
399+ . unwrap ( ) ;
400+
401+ assert_eq ! (
402+ props. get( "http-server.https.enabled" ) . map( String :: as_str) ,
403+ Some ( "true" )
404+ ) ;
405+ assert_eq ! (
406+ props
407+ . get( "http-server.authentication.allow-insecure-over-http" )
408+ . map( String :: as_str) ,
409+ Some ( "true" ) ,
410+ ) ;
411+ assert_eq ! (
412+ props. get( "http-server.http.port" ) . map( String :: as_str) ,
413+ Some ( "8080" )
414+ ) ;
415+ assert_eq ! (
416+ props
417+ . get( "http-server.https.keystore.path" )
418+ . map( String :: as_str) ,
419+ Some ( "/stackable/internal_tls/keystore.p12" ) ,
420+ ) ;
421+ // Internal TLS block is present.
422+ assert_eq ! (
423+ props
424+ . get( "internal-communication.https.keystore.path" )
425+ . map( String :: as_str) ,
426+ Some ( "/stackable/internal_tls/keystore.p12" ) ,
427+ ) ;
428+ assert_eq ! (
429+ props
430+ . get( "node.internal-address-source" )
431+ . map( String :: as_str) ,
432+ Some ( "FQDN" )
433+ ) ;
434+ // Discovery uses https when internal TLS is enabled.
435+ assert ! ( props. get( "discovery.uri" ) . unwrap( ) . starts_with( "https://" ) ) ;
436+ }
437+
438+ #[ test]
439+ fn worker_omits_include_coordinator ( ) {
440+ let cluster = validated_cluster_from_yaml ( MINIMAL_TRINO_YAML ) ;
441+ let props = build (
442+ & cluster,
443+ TrinoRole :: Worker ,
444+ & rg ( & cluster, & TrinoRole :: Worker ) ,
445+ & cluster_info ( ) ,
446+ )
447+ . unwrap ( ) ;
448+
449+ assert_eq ! ( props. get( "coordinator" ) . map( String :: as_str) , Some ( "false" ) ) ;
450+ assert_eq ! ( props. get( "node-scheduler.include-coordinator" ) , None ) ;
451+ }
452+
453+ #[ test]
454+ fn authentication_without_server_tls_errors ( ) {
455+ // Server TLS off (only internal) plus an enabled authenticator must be rejected.
456+ let cluster = validated_cluster_from_yaml_with_auth (
457+ INTERNAL_TLS_ONLY_YAML ,
458+ vec ! [ file_auth_class( "file-auth" ) ] ,
459+ ) ;
460+ let err = build (
461+ & cluster,
462+ TrinoRole :: Coordinator ,
463+ & rg ( & cluster, & TrinoRole :: Coordinator ) ,
464+ & cluster_info ( ) ,
465+ )
466+ . unwrap_err ( ) ;
467+
468+ assert ! ( matches!( err, Error :: AuthenticationRequiresTls ) ) ;
469+ }
283470}
0 commit comments