# revision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 # reachability is measured by qualified name, not by bare word: # import dev.caskeleton.messaging.security.; OR dev.caskeleton.messaging.security. ## A. twelve public types, files referencing them outside the owning leaf DestinationAccessPolicy 7 DestinationAccessValidator 0 MessageSecurityValidator 1 BrokerTlsPolicy 6 BrokerSecurityProfile 8 BrokerCredentialProfile 5 BrokerAclManifest 0 CredentialProvider 4 CredentialRuntime 2 CredentialRuntimeRegistry 6 CredentialRotationPlan 0 CredentialIds 0 ## B. the four with no consumer DestinationAccessValidator NONE BrokerAclManifest NONE CredentialRotationPlan NONE CredentialIds NONE (CredentialIds is package-private: internal by construction, not a finding.) ## C. duplicate 1 — the access check the publisher performs is not the validator --- the validator nobody calls 32: public void requirePublish(DestinationName destination) { 33- if (!policy.mayPublish(destination)) { 34- throw new MessageAuthorizationException( 35- "DESTINATION_PUBLISH_DENIED", 36- "the producer credential may not publish to " + destination.value()); 37- } --- what the publish path actually does 170: if (!access.mayPublish(destination.name())) { 171- // Before encoding: an unauthorized publish must not serialise the payload, because the 172- // encoded bytes are what a claim-check or a log would then be holding. 173- return rejected( 174- "PUBLISH_FORBIDDEN", 175- "this application may not publish to '" + destination.name().value() + '\'', 176- startedAt); ## D. duplicate 2 — the same TLS posture is checked by two classes with different strictness --- MessageSecurityValidator: hostname verification only in production, IllegalArgumentException if (profile.production() && !profile.tlsEnabled()) { throw new IllegalArgumentException( "a production broker connection requires TLS: " + profile.broker()); } if (profile.production() && !profile.hostnameVerification()) { throw new IllegalArgumentException( "a production broker connection requires TLS hostname verification: " + profile.broker()); } --- BrokerTlsPolicy: hostname verification WHENEVER TLS is on, MessagingConfigurationException if (!profile.tlsEnabled()) { if (profile.production() || !allowPlaintextOutsideProduction) { throw new MessagingConfigurationException( "TLS_REQUIRED", "broker %s runs in production and must not use a plaintext connection" .formatted(profile.broker())); } return; } if (!profile.hostnameVerification()) { throw new MessagingConfigurationException( "HOSTNAME_VERIFICATION_REQUIRED", "broker %s enables TLS without hostname verification, which accepts any certificate" .formatted(profile.broker())); } --- both are created as beans 156: public MessageSecurityValidator messageSecurityValidator() { 328: public BrokerTlsPolicy brokerTlsPolicy() { ## E. duplicate 3 — the rotation predicate exists twice, verbatim --- CredentialRotationPlan (no consumer) public boolean isDue(Instant now) { Objects.requireNonNull(now, "now must not be null"); return expiresAt.map(expiry -> !now.isBefore(expiry.minus(rotateBefore))).orElse(false); } /** * Reports whether the credential has already expired. * * @param now the current instant * @return true once expired */ public boolean isExpired(Instant now) { return expiresAt.map(expiry -> !now.isBefore(expiry)).orElse(false); } --- CredentialRuntime (used) public boolean isExpired(Instant now) { Objects.requireNonNull(now, "now must not be null"); return expiresAt.map(expiry -> !now.isBefore(expiry)).orElse(false); } /** * Reports whether rotation should begin. * * @param now the current instant * @return true when the credential is inside its rotation lead or already expired */ public boolean isDueForRotation(Instant now) { Objects.requireNonNull(now, "now must not be null"); return expiresAt.map(expiry -> !now.isBefore(expiry.minus(rotationLead))).orElse(false); } ## F. who does use this leaf --- BrokerTlsPolicy messaging-kafka/main/java/dev/caskeleton/messaging/kafka/KafkaSecurityConfigurer.java messaging-kafka/test/java/dev/caskeleton/messaging/kafka/KafkaSecurityConfigurerTest.java messaging-rabbit/main/java/dev/caskeleton/messaging/rabbit/RabbitSecurityConfigurer.java messaging-spring-boot-starter/main/java/dev/caskeleton/messaging/autoconfigure/KafkaMessagingAutoConfiguration.java messaging-spring-boot-starter/main/java/dev/caskeleton/messaging/autoconfigure/MessagingCoreAutoConfiguration.java messaging-spring-boot-starter/main/java/dev/caskeleton/messaging/autoconfigure/RabbitMessagingAutoConfiguration.java --- CredentialRuntimeRegistry messaging-kafka/main/java/dev/caskeleton/messaging/kafka/KafkaSecurityConfigurer.java messaging-kafka/test/java/dev/caskeleton/messaging/kafka/KafkaSecurityConfigurerTest.java messaging-rabbit/main/java/dev/caskeleton/messaging/rabbit/RabbitSecurityConfigurer.java messaging-spring-boot-starter/main/java/dev/caskeleton/messaging/autoconfigure/KafkaMessagingAutoConfiguration.java messaging-spring-boot-starter/main/java/dev/caskeleton/messaging/autoconfigure/MessagingCoreAutoConfiguration.java messaging-spring-boot-starter/main/java/dev/caskeleton/messaging/autoconfigure/RabbitMessagingAutoConfiguration.java --- CredentialProvider messaging-kafka/test/java/dev/caskeleton/messaging/kafka/KafkaSecurityConfigurerTest.java messaging-spring-boot-starter/main/java/dev/caskeleton/messaging/autoconfigure/MessagingCoreAutoConfiguration.java messaging-spring-boot-starter/main/java/dev/caskeleton/messaging/autoconfigure/MessagingCredentialRequirementValidator.java messaging-spring-boot-starter/test/java/dev/caskeleton/messaging/autoconfigure/MessagingAutoConfigurationTest.java --- DestinationAccessPolicy messaging-kafka/test/java/dev/caskeleton/messaging/kafka/KafkaSecurityConfigurerTest.java messaging-runtime-core/main/java/dev/caskeleton/messaging/runtime/DeclaredDestinationAccess.java messaging-runtime-core/main/java/dev/caskeleton/messaging/runtime/DefaultMessagePublisher.java messaging-runtime-core/test/java/dev/caskeleton/messaging/runtime/DefaultMessagePublisherTest.java messaging-spring-boot-starter/main/java/dev/caskeleton/messaging/autoconfigure/MessagingConfigurationCompiler.java messaging-spring-boot-starter/main/java/dev/caskeleton/messaging/autoconfigure/MessagingCoreAutoConfiguration.java messaging-spring-boot-starter/test/java/dev/caskeleton/messaging/autoconfigure/MessagingAutoConfigurationTest.java