The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.
Follows the import procedure in README.md.
source/ the originating repository verbatim — 78 documents, 28 SVGs,
8 manifests, plus .source-revision recording the commit
final/ the SSOT
document.md 729 lines written from the 29 experiment documents, not
concatenated: what was predicted, what was measured, and
where the measurement itself was wrong
evidence/raw 125 outputs, flattened to <experiment>__<file> because
the originals collided (01-baseline.txt appeared three
times) and the audit only globs the top level
evidence/meta one per raw file; command and exitCode are null and the
README says why rather than inventing them
evidence/browser 22 captures
assets/ three diagrams through techviz
.techviz/ their VizSpecs
A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.
Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.
verify-pipeline.py passes. audit-records.py reports no issues.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
468 lines
45 KiB
Plaintext
468 lines
45 KiB
Plaintext
Sub-scope 09 (mongo) security + failure + observation + client - manifest and probes
|
|
revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5
|
|
generatedAt=2026-08-30T00:22:02+00:00
|
|
cwd=/shared/codebase/clean-architecture-backend-template/src
|
|
|
|
=== OWNED FILES ===
|
|
70bb70e58ac29b6c1401715556b3bc999ecdde08 main/java/dev/caskeleton/adapter/outbound/mongo/client/MongoClientSettingsFactory.java 122
|
|
bd752d8017c85a8a179ec33f6bcac31a191938d2 main/java/dev/caskeleton/adapter/outbound/mongo/failure/DefaultMongoFailureClassifier.java 165
|
|
078eb6624daee4e12077317fe7f0f40c1484583f main/java/dev/caskeleton/adapter/outbound/mongo/failure/DefaultMongoFailureTranslator.java 136
|
|
42607f5e5692a704b40fb16f8e8deef7bc4eca8d main/java/dev/caskeleton/adapter/outbound/mongo/failure/MongoDriverFailureView.java 96
|
|
305db8f20852d5d4a5b31e6bd9e5a563113f0a4e main/java/dev/caskeleton/adapter/outbound/mongo/failure/MongoFailureClassification.java 84
|
|
fa7ee1fdb4d8b87db62636665e163d6efa54ade3 main/java/dev/caskeleton/adapter/outbound/mongo/failure/MongoFailureClassifier.java 30
|
|
c97bee6755b406ce235b0db2f1ddafd5b43a8ad7 main/java/dev/caskeleton/adapter/outbound/mongo/failure/MongoFailureExtractor.java 63
|
|
68f7019d768d09bab77c4062d58011f9a3072517 main/java/dev/caskeleton/adapter/outbound/mongo/failure/MongoFailurePhase.java 41
|
|
247affc2e97d358eec04ebe39096e749afc74e62 main/java/dev/caskeleton/adapter/outbound/mongo/failure/MongoFailureTranslator.java 32
|
|
cb66127e79ac161b23cbf8397da1fb23eaf1f2cc main/java/dev/caskeleton/adapter/outbound/mongo/observation/MicrometerMongoOperationObserver.java 104
|
|
d58c2b1109ea4c6d3b37a84048c1baded4c0e23f main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoCommandObservationListener.java 72
|
|
6833f38c54a5a82ab91515c7f1706d9436771525 main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoDriverObservabilityConfiguration.java 43
|
|
95d47f6c83dfba0486a290c12061062e10e4139a main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoObservationConvention.java 76
|
|
b31b95daae98c9d222b03def13571c20b567fe3b main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoObservationRedactor.java 48
|
|
862d03f5a8c6df8a6edf80b61dc19cab616e7004 main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoPoolObservationListener.java 79
|
|
da98d619400a5428052ebffb23918ed829b7eedb main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoSdamObservationListener.java 76
|
|
1eefc12534906eb0a5fe89f5f3679e5b0154073a main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoCredentialReference.java 74
|
|
c2630cf7b6e8e81348ab1e38337b9ad2d743ad5e main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoCredentialResolver.java 43
|
|
07772c4569a6e77a17f172a688c2c9ae385d3ade main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoCredentialRotationPolicy.java 50
|
|
97e58d6d456edf916972c8cdc6f96f65ad74f605 main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoPrincipalRole.java 63
|
|
ff75d970bf3da211faa9ca538dd11ae8834ac76c main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfile.java 54
|
|
5966a708bf8282bc8a1d1734978e16caaddf5ee1 main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfileValidator.java 69
|
|
7e3139a9e13624b6640938d0cf316819f464386c main/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminApproval.java 57
|
|
416ae3c05c952d61268619061f066000964c6ec6 main/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminAuditPhase.java 21
|
|
4ce978358da0817f3f4c89392e3ba2c1f348c717 main/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminAuditRecord.java 103
|
|
365d9d2a76e8da168df5e4b6c3ae5b444315fc2f main/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminAuthorization.java 58
|
|
b0e6c2311cd23484f1694797e6dca247440d245d main/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminCommand.java 103
|
|
3f7a8e9e0ea5e0921c87ef9d5cd10863acbac1dd main/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminGateway.java 155
|
|
bb4c1d808aac7a9db42f3faf73fbb848ad4462bc main/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminOperation.java 69
|
|
2ea0b6961acfdaffa37d6f2c4ed1ae41b407efb1 main/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminRuntimeGuard.java 58
|
|
c669128d19905192760fa6461e382e803b171466 test/java/dev/caskeleton/adapter/outbound/mongo/client/MongoClientSettingsFactoryTest.java 155
|
|
8cade411549e57554ef2af67d8c4a75d0edc7b8e test/java/dev/caskeleton/adapter/outbound/mongo/failure/DefaultMongoFailureClassifierTest.java 85
|
|
31cfe2e045e67d31200371cb577c1027756872e8 test/java/dev/caskeleton/adapter/outbound/mongo/failure/MongoFailureExtractorTest.java 85
|
|
c3c0bedd5f340edde465bdae5531be9550b9f16e test/java/dev/caskeleton/adapter/outbound/mongo/failure/MongoFailurePhaseClassificationTest.java 114
|
|
9cd42c63fc963e16f864877619d7bda9f2dbdb71 test/java/dev/caskeleton/adapter/outbound/mongo/failure/MongoNetworkFaultLaneTest.java 206
|
|
8fd453d853874984528c4ddfea935bd63c481ed3 test/java/dev/caskeleton/adapter/outbound/mongo/failure/TranslatorCarriesOperationContextTest.java 70
|
|
ec8897a4907ed8bfd3209d83beb030d1c5446ce4 test/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoObservationConventionTest.java 67
|
|
355d56a96e8c76c519b6239bcd39e67f30ccf867 test/java/dev/caskeleton/adapter/outbound/mongo/security/MongoCredentialIdentityTest.java 108
|
|
64f8ff90b050f7347dd58bf2e7d21e672d5d41a2 test/java/dev/caskeleton/adapter/outbound/mongo/security/MongoProductionSecurityContractTest.java 176
|
|
48ddb5c88db513fed1666dea0b712cf6d11615d7 test/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityIntegrationLaneTest.java 173
|
|
bd76cc9d30bd033639a5911c9f965838c7784ecb test/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfileValidatorTest.java 115
|
|
3ca3a9db79b2f5ff033b25d659da79850d39c4b2 test/java/dev/caskeleton/adapter/outbound/mongo/security/MongoTlsLaneTest.java 164
|
|
9ab88fab1970f5bbdcc009269b0de14188701e21 test/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminAuditStateMachineTest.java 250
|
|
e080d8c0e10b9ee0999c0170fdd0e2a4457d80cf test/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminRuntimeGuardTest.java 117
|
|
|
|
production: 30
|
|
test: 14
|
|
production LOC: 2244 total
|
|
|
|
=== 8.1 reachability: what the auto-configuration builds from these four packages ===
|
|
$ grep -n 'ClientSettings\|CredentialResolver\|SecurityProfile\|FailureTranslator\|FailureClassifier\|Observ\|Redactor\|AdminGateway' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformAutoConfiguration.java
|
|
5:import dev.caskeleton.adapter.outbound.mongo.api.observation.MongoOperationObserver;
|
|
6:import dev.caskeleton.adapter.outbound.mongo.failure.DefaultMongoFailureClassifier;
|
|
7:import dev.caskeleton.adapter.outbound.mongo.failure.DefaultMongoFailureTranslator;
|
|
8:import dev.caskeleton.adapter.outbound.mongo.failure.MongoFailureClassifier;
|
|
9:import dev.caskeleton.adapter.outbound.mongo.failure.MongoFailureTranslator;
|
|
14:import dev.caskeleton.adapter.outbound.mongo.observation.MicrometerMongoOperationObserver;
|
|
85: public MongoFailureClassifier mongoFailureClassifier() {
|
|
86: return new DefaultMongoFailureClassifier();
|
|
92: public MongoFailureTranslator mongoFailureTranslator(MongoFailureClassifier classifier) {
|
|
93: return new DefaultMongoFailureTranslator(classifier);
|
|
104: public MongoOperationObserver mongoOperationObserver(ObjectProvider<MeterRegistry> registries) {
|
|
107: ? MongoOperationObserver.none()
|
|
108: : new MicrometerMongoOperationObserver(registry, "default");
|
|
117: MongoFailureTranslator translator,
|
|
118: MongoOperationObserver observer) {
|
|
298: MongoFailureTranslator translator,
|
|
299: MongoOperationObserver observer) {
|
|
335: ObjectProvider<dev.caskeleton.adapter.outbound.mongo.security.MongoSecurityProfile>
|
|
exit=0
|
|
|
|
=== 8.1b does the platform actually build the driver client from its own factory? ===
|
|
$ git grep -n 'MongoClientSettingsFactory' -- 'adapter/outbound/persistence-mongo/src'
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/client/MongoClientSettingsFactory.java:38:public final class MongoClientSettingsFactory {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/client/MongoClientSettingsFactory.java:51: public MongoClientSettingsFactory(
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/client/MongoClientSettingsFactoryTest.java:28:class MongoClientSettingsFactoryTest {
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/client/MongoClientSettingsFactoryTest.java:38: new MongoClientSettingsFactory(
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/client/MongoClientSettingsFactoryTest.java:60: new MongoClientSettingsFactory(
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/client/MongoClientSettingsFactoryTest.java:74: new MongoClientSettingsFactory(
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/client/MongoClientSettingsFactoryTest.java:95: new MongoClientSettingsFactory(settings, ACTIVE, resolver(resolved)).create();
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/client/MongoClientSettingsFactoryTest.java:110: new MongoClientSettingsFactory(
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/client/MongoClientSettingsFactoryTest.java:120: new MongoClientSettingsFactory(
|
|
exit=0
|
|
|
|
$ git grep -n 'MongoClientSettings\|MongoClient\b\|MongoClients' -- 'adapter/outbound/persistence-mongo/src/main' | grep -v '/client/MongoClientSettingsFactory.java'
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoDriverObservabilityAutoConfiguration.java:8:import org.springframework.boot.mongodb.autoconfigure.MongoClientSettingsBuilderCustomizer;
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoDriverObservabilityAutoConfiguration.java:15: * settings builder, and nothing ever called it. Boot builds the {@code MongoClient} from its own
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoDriverObservabilityAutoConfiguration.java:38: public MongoClientSettingsBuilderCustomizer mongoDriverObservabilityCustomizer(
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/nativecap/MongoNativeCapabilityGateway.java:6: * <p>There is no {@code MongoClient}, {@code MongoDatabase} or {@code MongoCollection<Document>}
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoDriverObservabilityConfiguration.java:3:import com.mongodb.MongoClientSettings;
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoDriverObservabilityConfiguration.java:26: public MongoClientSettings.Builder apply(MongoClientSettings.Builder builder) {
|
|
exit=0
|
|
|
|
$ git grep -rn 'MongoClientSettingsFactory\|MongoCredentialResolver' -- '../app-bootstrap' '../adapter' 2>/dev/null | grep -v persistence-mongo | head
|
|
exit=0
|
|
|
|
=== 8.1c are the driver observability listeners ever installed? ===
|
|
$ git grep -n 'MongoDriverObservabilityConfiguration' -- 'adapter/outbound/persistence-mongo/src'
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoDriverObservabilityAutoConfiguration.java:3:import dev.caskeleton.adapter.outbound.mongo.observation.MongoDriverObservabilityConfiguration;
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoDriverObservabilityAutoConfiguration.java:14: * <p>{@link MongoDriverObservabilityConfiguration} could add command, SDAM and pool listeners to a
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoDriverObservabilityAutoConfiguration.java:45: MongoDriverObservabilityConfiguration observability =
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoDriverObservabilityAutoConfiguration.java:46: new MongoDriverObservabilityConfiguration(registry, profile);
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoDriverObservabilityConfiguration.java:14:public final class MongoDriverObservabilityConfiguration {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoDriverObservabilityConfiguration.java:20: public MongoDriverObservabilityConfiguration(MeterRegistry registry, String mongoProfile) {
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoDriverObservabilityWiringTest.java:19: * <p>{@code MongoDriverObservabilityConfiguration} could attach command, SDAM and pool listeners to
|
|
exit=0
|
|
|
|
$ git grep -n 'MongoCommandObservationListener\|MongoSdamObservationListener\|MongoPoolObservationListener' -- 'adapter/outbound/persistence-mongo/src/main' | grep -v '/observation/'
|
|
exit=1
|
|
|
|
$ git grep -n 'addCommandListener\|addClusterListener\|addConnectionPoolListener' -- 'adapter/outbound/persistence-mongo/src'
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoDriverObservabilityConfiguration.java:28: builder.addCommandListener(new MongoCommandObservationListener(registry, mongoProfile));
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoDriverObservabilityConfiguration.java:31: cluster.addClusterListener(new MongoSdamObservationListener(registry, mongoProfile)));
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoDriverObservabilityConfiguration.java:34: pool.addConnectionPoolListener(
|
|
exit=0
|
|
|
|
=== 8.1d is the security profile validator called at startup? ===
|
|
$ git grep -n 'MongoSecurityProfileValidator\|MongoSecurityProfile\b\|requireDistinctCredentials' -- 'adapter/outbound/persistence-mongo/src/main'
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformAutoConfiguration.java:335: ObjectProvider<dev.caskeleton.adapter.outbound.mongo.security.MongoSecurityProfile>
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoStartupValidator.java:9:import dev.caskeleton.adapter.outbound.mongo.security.MongoSecurityProfile;
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoStartupValidator.java:10:import dev.caskeleton.adapter.outbound.mongo.security.MongoSecurityProfileValidator;
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoStartupValidator.java:28: private final MongoSecurityProfile runtimeSecurity;
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoStartupValidator.java:41: MongoSecurityProfile runtimeSecurity,
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoStartupValidator.java:62: new MongoSecurityProfileValidator().validate(runtimeSecurity);
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoStartupValidator.java:117: new MongoSecurityProfileValidator()
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoStartupValidator.java:118: .requireDistinctCredentials(runtimeSecurity.credential(), admin));
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoCredentialReference.java:46: * MongoSecurityProfileValidator#requireDistinctCredentials}, is always called with a runtime role
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfile.java:13:public record MongoSecurityProfile(
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfile.java:20: public MongoSecurityProfile {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfile.java:27: public static MongoSecurityProfile production(
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfile.java:29: return new MongoSecurityProfile(
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfile.java:38: public static MongoSecurityProfile production(
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfile.java:40: return new MongoSecurityProfile(true, true, true, credential, grantedPrivileges);
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfile.java:44: public static MongoSecurityProfile local(MongoCredentialReference credential) {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfile.java:45: return new MongoSecurityProfile(false, false, false, credential, Set.of());
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfileValidator.java:14:public final class MongoSecurityProfileValidator {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfileValidator.java:21: public void validate(MongoSecurityProfile profile) {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfileValidator.java:57: public void requireDistinctCredentials(
|
|
exit=0
|
|
|
|
$ git grep -n 'MongoCredentialRotationPolicy\|validateRotation' -- 'adapter/outbound/persistence-mongo/src'
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoClientGenerationRegistry.java:5:import dev.caskeleton.adapter.outbound.mongo.security.MongoCredentialRotationPolicy;
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoClientGenerationRegistry.java:31: private final MongoCredentialRotationPolicy rotationPolicy;
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoClientGenerationRegistry.java:35: public MongoClientGenerationRegistry(MongoCredentialRotationPolicy rotationPolicy, Clock clock) {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoClientGenerationRegistry.java:68: rotationPolicy.validateRotation(existing.credential(), replacement);
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformAutoConfiguration.java:417: dev.caskeleton.adapter.outbound.mongo.security.MongoCredentialRotationPolicy.class)
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformAutoConfiguration.java:419: dev.caskeleton.adapter.outbound.mongo.security.MongoCredentialRotationPolicy rotationPolicy,
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoCredentialReference.java:51: * MongoCredentialRotationPolicy} always knew that: it compares roles on its own line, right after
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoCredentialRotationPolicy.java:14:public record MongoCredentialRotationPolicy(Duration drainTimeout, boolean failClosedOnOverlap) {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoCredentialRotationPolicy.java:16: public MongoCredentialRotationPolicy {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoCredentialRotationPolicy.java:24: public static MongoCredentialRotationPolicy standard() {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoCredentialRotationPolicy.java:25: return new MongoCredentialRotationPolicy(Duration.ofSeconds(30), true);
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoCredentialRotationPolicy.java:34: public void validateRotation(
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoClientGenerationConcurrencyTest.java:8:import dev.caskeleton.adapter.outbound.mongo.security.MongoCredentialRotationPolicy;
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoClientGenerationConcurrencyTest.java:43: new MongoClientGenerationRegistry(MongoCredentialRotationPolicy.standard(), FIXED);
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformPropertiesTest.java:13:import dev.caskeleton.adapter.outbound.mongo.security.MongoCredentialRotationPolicy;
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformPropertiesTest.java:136: MongoCredentialRotationPolicy.standard(),
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformPropertiesTest.java:156: MongoCredentialRotationPolicy.standard(),
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/RotationOrderingTest.java:8:import dev.caskeleton.adapter.outbound.mongo.security.MongoCredentialRotationPolicy;
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/RotationOrderingTest.java:41: new MongoClientGenerationRegistry(MongoCredentialRotationPolicy.standard(), FIXED);
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/security/MongoCredentialIdentityTest.java:21: * <p>{@code MongoCredentialRotationPolicy} is the counter-evidence that the role was never meant to
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/security/MongoCredentialIdentityTest.java:90: new MongoCredentialRotationPolicy(java.time.Duration.ofSeconds(30), true)
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/security/MongoCredentialIdentityTest.java:91: .validateRotation(
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfileValidatorTest.java:101: MongoCredentialRotationPolicy policy = MongoCredentialRotationPolicy.standard();
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfileValidatorTest.java:105: assertThatThrownBy(() -> policy.validateRotation(current, current))
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/security/MongoSecurityProfileValidatorTest.java:109: policy.validateRotation(
|
|
exit=0
|
|
|
|
=== 8.2 the observation allowlist: enforced by code, or only asserted by a test? ===
|
|
$ git grep -n 'requireAllowed\|allowedTagNames\|forbiddenTagNames\|MongoObservationConvention' -- 'adapter/outbound/persistence-mongo/src/main'
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/advanced/search/MongoSearchQuery.java:48: public void requireAllowedPaths(Set<String> allowedPaths) {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/advanced/sharding/ShardAwareQueryValidator.java:59: public MongoRoutingClassification requireAllowedRead(
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/aggregation/MongoAggregationProfile.java:86: public void requireAllowed(MongoAggregationStageDescriptor descriptor) {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/aggregation/PolicyAwareMongoAggregationExecutor.java:49: plan.stages().forEach(profile::requireAllowed);
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoDriverObservabilityConfiguration.java:40: public MongoObservationConvention convention() {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoDriverObservabilityConfiguration.java:41: return MongoObservationConvention.standard();
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoObservationConvention.java:17:public final class MongoObservationConvention {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoObservationConvention.java:44: private MongoObservationConvention() {}
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoObservationConvention.java:47: public static MongoObservationConvention standard() {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoObservationConvention.java:48: return new MongoObservationConvention();
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoObservationConvention.java:52: public Set<String> allowedTagNames() {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoObservationConvention.java:57: public Set<String> forbiddenTagNames() {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoObservationConvention.java:66: public void requireAllowed(String tagName) {
|
|
exit=0
|
|
|
|
$ grep -n 'Tags.of' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/*.java
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MicrometerMongoOperationObserver.java:46: Tags.of(
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MicrometerMongoOperationObserver.java:72: this.outcomeTags = Tags.of("result", "unknown", "failureCategory", "none");
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MicrometerMongoOperationObserver.java:77: outcomeTags = Tags.of("result", outcome.name(), "failureCategory", "none");
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MicrometerMongoOperationObserver.java:83: Tags.of(
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoCommandObservationListener.java:63: Tags.of(
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoPoolObservationListener.java:40: Tags tags = Tags.of("mongoProfile", mongoProfile);
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoPoolObservationListener.java:60: .tags(Tags.of("mongoProfile", mongoProfile, "failureCategory", event.getReason().name()))
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoSdamObservationListener.java:46: .tags(Tags.of("mongoProfile", mongoProfile))
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MongoSdamObservationListener.java:61: .tags(Tags.of("mongoProfile", mongoProfile))
|
|
exit=0
|
|
|
|
$ git grep -n 'redactor.describe\|\.describe(' -- 'adapter/outbound/persistence-mongo/src/main'
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/api/error/MongoPersistenceException.java:24: summary + " [" + Objects.requireNonNull(failureContext, "failureContext").describe() + "]");
|
|
exit=0
|
|
|
|
=== 8.2b the admin gateway's two audit paths ===
|
|
$ grep -n 'private void audit' -A 12 adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminGateway.java
|
|
127: private void audit(MongoAdminAuditRecord record) {
|
|
128- try {
|
|
129- auditSink.accept(record);
|
|
130- } catch (RuntimeException sinkFailed) {
|
|
131- throw MongoOperationRejectedException.of(
|
|
132- "admin.audit",
|
|
133- "the admin audit sink refused the "
|
|
134- + record.phase()
|
|
135- + " record; an administrative operation that cannot be audited does not run");
|
|
136- }
|
|
137- }
|
|
138-
|
|
139- /**
|
|
exit=0
|
|
|
|
$ grep -n 'public void dryRun' -A 8 adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminGateway.java
|
|
145: public void dryRun(MongoAdminOperation operation, String target, String operator, String reason) {
|
|
146- authorization.require(operation);
|
|
147- auditSink.accept(
|
|
148- MongoAdminAuditRecord.dryRun(operation, target, operator, reason, clock.instant()));
|
|
149- }
|
|
150-
|
|
151- /** The guard this gateway was constructed under. */
|
|
152- public MongoAdminRuntimeGuard guard() {
|
|
153- return guard;
|
|
exit=0
|
|
|
|
=== 8.2c traceId ===
|
|
$ grep -rn 'traceId' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/api/observation/MongoOperationObservation.java adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MicrometerMongoOperationObserver.java
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/api/observation/MongoOperationObservation.java:22: String traceId();
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MicrometerMongoOperationObserver.java:91: public String traceId() {
|
|
exit=0
|
|
|
|
$ git grep -n 'traceId()' -- 'adapter/outbound/persistence-mongo/src/main'
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/api/observation/MongoOperationObservation.java:22: String traceId();
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/api/observation/NoOpMongoOperationObserver.java:42: public String traceId() {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/imperative/DefaultMongoImperativeExecutor.java:129: observation.failure(translated.failureContext().withTraceId(observation.traceId()));
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/observation/MicrometerMongoOperationObserver.java:91: public String traceId() {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/reactive/DefaultReactiveMongoExecutor.java:169: observation.failure(translated.failureContext().withTraceId(observation.traceId()));
|
|
exit=0
|
|
|
|
=== 8.3 duplicate / unused mechanisms ===
|
|
$ git grep -n 'unrecognisedServerCode\|MongoFailureClassification.nonRetryable\|classify(failure)' -- 'adapter/outbound/persistence-mongo/src/main'
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/failure/DefaultMongoFailureClassifier.java:139: return MongoFailureClassification.nonRetryable(category);
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/failure/MongoFailureClassification.java:57: public static MongoFailureClassification nonRetryable(MongoFailureCategory category) {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/failure/MongoFailureClassification.java:70: public static MongoFailureClassification unrecognisedServerCode() {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/failure/MongoFailureClassifier.java:28: return classify(failure);
|
|
exit=0
|
|
|
|
$ git grep -n 'MongoAdminAuditRecord.applied\|adminGatewayAllowed\|MongoAdminApproval.of' -- 'adapter/outbound/persistence-mongo/src'
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminApproval.java:31: public static MongoAdminApproval of(
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminAuditRecord.java:98: public static MongoAdminAuditRecord applied(
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminRuntimeGuard.java:55: public boolean adminGatewayAllowed() {
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminAuditStateMachineTest.java:138: MongoAdminApproval.of(rehearsal, "approver", NOW.plus(Duration.ofMinutes(10)));
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminAuditStateMachineTest.java:157: MongoAdminApproval.of(approved, "approver", NOW.plusSeconds(600)),
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminAuditStateMachineTest.java:167: MongoAdminApproval approval = MongoAdminApproval.of(command, "approver", NOW.plusSeconds(600));
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminAuditStateMachineTest.java:187: MongoAdminApproval.of(command, "approver", NOW.minusSeconds(1)),
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminRuntimeGuardTest.java:48: assertThat(guard.adminGatewayAllowed()).isTrue();
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminRuntimeGuardTest.java:101: MongoAdminAuditRecord.applied(
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/security/admin/MongoAdminRuntimeGuardTest.java:106: MongoAdminAuditRecord.applied(
|
|
exit=0
|
|
|
|
$ git grep -n 'MongoFailureExtractor' -- 'adapter/outbound/persistence-mongo/src/main'
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/failure/MongoFailureExtractor.java:21:public final class MongoFailureExtractor {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/failure/MongoFailureExtractor.java:26: private MongoFailureExtractor() {}
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/SpringMongoTransactionSessionFactory.java:22:import dev.caskeleton.adapter.outbound.mongo.failure.MongoFailureExtractor;
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/SpringMongoTransactionSessionFactory.java:225: MongoDriverFailureView view = MongoFailureExtractor.viewOf(failure).orElse(null);
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/SpringReactiveMongoTransactionSessionFactory.java:21:import dev.caskeleton.adapter.outbound.mongo.failure.MongoFailureExtractor;
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/SpringReactiveMongoTransactionSessionFactory.java:176: MongoDriverFailureView view = MongoFailureExtractor.viewOf(failure).orElse(null);
|
|
exit=0
|
|
|
|
$ git grep -n 'DefaultMongoFailureTranslator.standard\|new DefaultMongoFailureTranslator\|new DefaultMongoFailureClassifier' -- 'adapter/outbound/persistence-mongo/src/main'
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformAutoConfiguration.java:86: return new DefaultMongoFailureClassifier();
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformAutoConfiguration.java:93: return new DefaultMongoFailureTranslator(classifier);
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/failure/DefaultMongoFailureTranslator.java:46: public static DefaultMongoFailureTranslator standard() {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/failure/DefaultMongoFailureTranslator.java:47: return new DefaultMongoFailureTranslator(new DefaultMongoFailureClassifier());
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/SpringMongoTransactionSessionFactory.java:52: this(template, consistency, new DefaultMongoFailureClassifier());
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/SpringReactiveMongoTransactionSessionFactory.java:53: this(template, consistency, new DefaultMongoFailureClassifier());
|
|
exit=0
|
|
|
|
=== 8.4 lane / documentation drift ===
|
|
$ grep -n 'lane(' adapter/outbound/persistence-mongo/build.gradle
|
|
107: lane('mongoReplicaSetTest') {
|
|
113: lane('mongoFailoverTest') {
|
|
119: lane('mongoMigrationTest') {
|
|
125: lane('mongoCompatibilityTest') {
|
|
130: lane('mongoSecurityIntegrationTest') {
|
|
139: lane('mongoPerformanceTest') {
|
|
exit=0
|
|
|
|
$ grep -n 'mongodb-security-integration\|mongodb-failover' adapter/outbound/persistence-mongo/build.gradle
|
|
96: 'mongodb-failover',
|
|
99: 'mongodb-security-integration'
|
|
114: tag = 'mongodb-failover'
|
|
131: tag = 'mongodb-security-integration'
|
|
exit=0
|
|
|
|
|
|
=== 8.1e REPO-WIDE: who builds the MongoClient, and is the platform factory reachable? ===
|
|
$ git grep -rn 'MongoClientSettingsFactory' -- . | grep -v 'adapter/outbound/persistence-mongo/src'
|
|
exit=1
|
|
|
|
$ git grep -rln 'MongoCredentialResolver' -- . | grep -v 'adapter/outbound/persistence-mongo/src'
|
|
adapter/outbound/persistence-mongo/CLAUDE.md
|
|
exit=0
|
|
|
|
$ git grep -rn 'spring.data.mongodb.uri\|spring.mongodb.uri' -- . | head -20
|
|
adapter/outbound/persistence-mongo/README.md:37:spring.data.mongodb.uri=mongodb://localhost:27017/portfolio
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/MongoPersistenceSettings.java:10: * own standard {@code spring.mongodb.uri} (owned by Spring Boot's {@code MongoProperties}), which
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/security/MongoCredentialResolver.java:11: * spring.mongodb.uri}, which is an ordinary property — in configuration, in the image and in every
|
|
exit=0
|
|
|
|
$ cat adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoDriverObservabilityAutoConfiguration.java
|
|
package dev.caskeleton.adapter.outbound.mongo.autoconfigure;
|
|
|
|
import dev.caskeleton.adapter.outbound.mongo.observation.MongoDriverObservabilityConfiguration;
|
|
import io.micrometer.core.instrument.MeterRegistry;
|
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
import org.springframework.boot.mongodb.autoconfigure.MongoClientSettingsBuilderCustomizer;
|
|
import org.springframework.context.annotation.Bean;
|
|
|
|
/**
|
|
* Attaches the driver's observation listeners to the client Boot builds.
|
|
*
|
|
* <p>{@link MongoDriverObservabilityConfiguration} could add command, SDAM and pool listeners to a
|
|
* settings builder, and nothing ever called it. Boot builds the {@code MongoClient} from its own
|
|
* customizers, so the listeners were a method with no caller: the pool-checkout, server-selection
|
|
* and primary-change metrics the operations documentation refers to were never emitted.
|
|
*
|
|
* <p>Separate from {@code MongoPlatformAutoConfiguration} because it is conditional on something
|
|
* else — a {@link MeterRegistry}. A listener with nowhere to publish costs work on every command,
|
|
* so a deployment without metrics gets no listeners rather than silent ones.
|
|
*
|
|
* <p>These tag by driver event. The platform's own observation tags by operation. The two measure
|
|
* different things on purpose, and neither is derived from the other, so a command appears once in
|
|
* each rather than twice in one.
|
|
*/
|
|
@org.springframework.context.annotation.Configuration(proxyBeanMethods = false)
|
|
@ConditionalOnProperty(
|
|
prefix = "ca-skeleton.persistence-mongo",
|
|
name = "enabled",
|
|
havingValue = "true")
|
|
public class MongoDriverObservabilityAutoConfiguration {
|
|
|
|
/** The customizer Boot applies when it builds the client. */
|
|
@Bean
|
|
@ConditionalOnBean(MeterRegistry.class)
|
|
@ConditionalOnMissingBean(name = "mongoDriverObservabilityCustomizer")
|
|
public MongoClientSettingsBuilderCustomizer mongoDriverObservabilityCustomizer(
|
|
MeterRegistry registry,
|
|
org.springframework.beans.factory.ObjectProvider<MongoPlatformSettings> properties) {
|
|
String profile =
|
|
properties.getIfAvailable(MongoPlatformSettings::empty).profiles().keySet().stream()
|
|
.findFirst()
|
|
.orElse("default");
|
|
MongoDriverObservabilityConfiguration observability =
|
|
new MongoDriverObservabilityConfiguration(registry, profile);
|
|
return observability::apply;
|
|
}
|
|
}
|
|
exit=0
|
|
|
|
$ sed -n '325,375p' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformAutoConfiguration.java
|
|
* first transaction.
|
|
*
|
|
* <p>Conditional on a {@link MongoTopologyProbe} bean, because the check is about the server this
|
|
* deployment actually talks to, and only a composition root knows how to reach it.
|
|
*/
|
|
@Bean
|
|
@ConditionalOnBean(MongoTopologyProbe.class)
|
|
public InitializingBean mongoPlatformStartupCheck(
|
|
MongoPlatformSettings properties,
|
|
MongoTopologyProbe probe,
|
|
ObjectProvider<dev.caskeleton.adapter.outbound.mongo.security.MongoSecurityProfile>
|
|
runtimeSecurity,
|
|
ObjectProvider<dev.caskeleton.adapter.outbound.mongo.security.MongoCredentialReference>
|
|
adminCredential,
|
|
ObjectProvider<dev.caskeleton.adapter.outbound.mongo.api.schema.MongoSchemaVersionRange>
|
|
schemaVersionRange) {
|
|
return () -> {
|
|
properties.validate();
|
|
var security = runtimeSecurity.getIfAvailable();
|
|
var admin = adminCredential.getIfAvailable();
|
|
var versions = schemaVersionRange.getIfAvailable();
|
|
if (security == null || admin == null || versions == null) {
|
|
// Fail closed rather than validate a subset. A partial startup check reports success for
|
|
// the parts nobody supplied, which is the shape the missing wiring already had.
|
|
throw new IllegalStateException(
|
|
"the Mongo platform is enabled and a topology probe is present, but the security"
|
|
+ " profile, admin credential reference or schema version range is not configured;"
|
|
+ " the startup validator cannot answer with only part of its inputs");
|
|
}
|
|
new MongoStartupValidator(
|
|
properties,
|
|
probe,
|
|
security,
|
|
admin,
|
|
// From settings, not literals. These were `true, true`, which told the validator that
|
|
// transactions and change streams were both wanted whatever the deployment had
|
|
// configured — and then validated the topology against that invented answer.
|
|
properties.transactions(),
|
|
properties.changeStreams(),
|
|
versions)
|
|
.validate();
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Refuses a platform that is on with no way to look at the server it talks to (MNG-INT-003).
|
|
*
|
|
* <p>{@code mongoPlatformStartupCheck} above is conditioned on a {@link MongoTopologyProbe},
|
|
* which is right — the check is about the live server, and only a composition root knows how to
|
|
* reach it. But a condition is also an exit: a deployment that enables the platform and supplies
|
|
* no probe got no validation at all, silently, and not supplying a bean is exactly what an
|
|
exit=0
|
|
|
|
$ sed -n '55,70p;110,125p' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoStartupValidator.java
|
|
/**
|
|
* Runs every startup check.
|
|
*
|
|
* @throws MongoOperationRejectedException naming the first failed condition
|
|
*/
|
|
public void validate() {
|
|
properties.validate();
|
|
new MongoSecurityProfileValidator().validate(runtimeSecurity);
|
|
requireDeclaredTopologyMatchesReality();
|
|
requireCapabilitiesForEnabledFeatures();
|
|
requireDistinctAdminCredential();
|
|
requireSupportedSchemaRange();
|
|
}
|
|
|
|
private void requireDeclaredTopologyMatchesReality() {
|
|
properties
|
|
}
|
|
}
|
|
|
|
private void requireDistinctAdminCredential() {
|
|
Optional.ofNullable(adminCredential)
|
|
.ifPresent(
|
|
admin ->
|
|
new MongoSecurityProfileValidator()
|
|
.requireDistinctCredentials(runtimeSecurity.credential(), admin));
|
|
}
|
|
|
|
private void requireSupportedSchemaRange() {
|
|
if (schemaVersionRange.minimumSupported().compareTo(schemaVersionRange.current()) > 0) {
|
|
throw MongoOperationRejectedException.of(
|
|
"startup.schema", "the configured schema version range is inverted");
|
|
}
|
|
exit=0
|
|
|
|
=== 8.1f the four AutoConfiguration entries this leaf registers ===
|
|
$ cat adapter/outbound/persistence-mongo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
|
|
dev.caskeleton.adapter.outbound.mongo.MongoRootAutoConfiguration
|
|
exit=0
|
|
|