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>
82 lines
3.4 KiB
Plaintext
82 lines
3.4 KiB
Plaintext
# evidence 260 — messaging-admin-plane-assembly
|
|
# revision: a24ece9cf797f7ea647e33bf846b115208ed1ba5
|
|
# cwd: /shared/codebase/clean-architecture-backend-template/src/messaging
|
|
# command: grep -vE "^import " messaging-spring-boot-starter/src/main/java/dev/caskeleton/messaging/autoconfigure/MessagingAdminAutoConfiguration.java
|
|
# ---- raw output ----
|
|
package dev.caskeleton.messaging.autoconfigure;
|
|
|
|
|
|
/**
|
|
* Wires the admin plane, and only when a deployment has explicitly asked for it.
|
|
*
|
|
* <p>Off unless {@code app.messaging.admin.enabled=true}. An application that acquires the admin
|
|
* plane by adding a starter to its classpath is exactly the situation the plane's guards exist to
|
|
* prevent — the guards would still refuse an unapproved operation, but the beans would be reachable
|
|
* from any code in the process.
|
|
*
|
|
* <p>{@link dev.caskeleton.messaging.admin.runtime.DestructiveMessagingAdmin} is deliberately
|
|
* absent from this class. No bean for it is ever auto-configured: an operator tool that needs purge
|
|
* or delete registers one itself, with an admin credential this runtime does not hold.
|
|
*/
|
|
@Configuration(proxyBeanMethods = false)
|
|
@ConditionalOnProperty(prefix = "app.messaging.admin", name = "enabled", havingValue = "true")
|
|
public class MessagingAdminAutoConfiguration {
|
|
|
|
/**
|
|
* Returns the guard that authorises non-destructive admin operations.
|
|
*
|
|
* @return the guard
|
|
*/
|
|
@Bean
|
|
@ConditionalOnMissingBean
|
|
public DestructiveOperationGuard destructiveOperationGuard() {
|
|
// false: an application runtime never holds an admin credential, so the guard refuses the
|
|
// operations that would need one. An operator tool overrides this bean with true.
|
|
return new DestructiveOperationGuard(false);
|
|
}
|
|
|
|
/**
|
|
* Returns a single-process journal so a development runtime starts without extra wiring.
|
|
*
|
|
* <p>It declares itself non-durable, and {@link MessagingAdminDurabilityValidator} refuses to let
|
|
* a production profile start on it. That pairing is deliberate: the convenient default stays
|
|
* convenient for local work and becomes a startup failure — naming what to supply — the moment
|
|
* the deployment claims to be production. The previous default was an indistinguishable {@code
|
|
* ConcurrentHashMap} that silently let two replicas execute the same approval.
|
|
*
|
|
* @return the in-memory journal
|
|
*/
|
|
@Bean
|
|
@ConditionalOnMissingBean
|
|
public AdminOperationJournal adminOperationJournal() {
|
|
return new InMemoryAdminOperationJournal();
|
|
}
|
|
|
|
/**
|
|
* Returns the validator that refuses a production profile on a non-durable journal.
|
|
*
|
|
* @param journal the journal in use
|
|
* @param environment the Spring environment
|
|
* @return the validator
|
|
*/
|
|
@Bean
|
|
@ConditionalOnMissingBean
|
|
public MessagingAdminDurabilityValidator messagingAdminDurabilityValidator(
|
|
AdminOperationJournal journal, org.springframework.core.env.Environment environment) {
|
|
return new MessagingAdminDurabilityValidator(journal, environment);
|
|
}
|
|
|
|
/**
|
|
* Returns the topology validator, when the application supplied a broker inspector.
|
|
*
|
|
* @param inspector reads the broker's current topology
|
|
* @return the composite validator
|
|
*/
|
|
@Bean
|
|
@ConditionalOnBean(BrokerTopologyInspector.class)
|
|
@ConditionalOnMissingBean
|
|
public CompositeTopologyValidator compositeTopologyValidator(BrokerTopologyInspector inspector) {
|
|
return new CompositeTopologyValidator(inspector);
|
|
}
|
|
}
|