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>
15 lines
5.2 KiB
JSON
15 lines
5.2 KiB
JSON
{
|
|
"assetKey": "a-validator-that-demands-tls-and-an-assembly-that-omits-it",
|
|
"kind": "terminal",
|
|
"command": "set -e\nset -o pipefail\nK=src/messaging/messaging-kafka/src/main/java/dev/caskeleton/messaging/kafka\nA=src/messaging/messaging-spring-boot-starter/src/main/java/dev/caskeleton/messaging/autoconfigure\nB=src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/messaging\nstrip() { sed -E 's#^src/[^:]*/src/(main|test|testFixtures)/[^:]*/([^:/]+):([0-9]+):# \\1 · \\2:\\3 #'; }\ncut_range() { awk -v f=\"$2\" -v a=\"$3\" -v b=\"$4\" 'NR>=a && NR<=b {printf \" %s:%d %s\\n\", f, NR, $0}' \"$1\"; }\n\necho \"# 운영 프로파일에 KafkaProfileValidator 가 거는 두 요구\"\ncut_range $K/KafkaProfileValidator.java KafkaProfileValidator.java 51 58\n\necho\necho \"# 그 검증기가 기동에서 도는 경로와, 그 거부를 지키는 테스트\"\ngit grep -n 'kafkaProfileStartupValidation' -- 'src/**/*.java' | strip\ngit grep -n 'implements InitializingBean\\|afterPropertiesSet' -- '**/StartupProfileValidation.java' | strip\ngit grep -n 'aProductionKafkaBrokerWithoutTransportSecurityFailsStartup' -- 'src/**/*.java' | strip\n\necho\necho \"# 두 조립부를 켜는 프로퍼티\"\ngit grep -n 'name = \"enabled\", havingValue = \"true\"' -- 'src/**/*.java' | grep -iE 'messaging' | strip\ngit grep -n '\"kafka\", KafkaMessagingAutoConfiguration.class' -- 'src/**/*.java' | strip\ngrep -n '^@ConditionalOnProperty' $B/KafkaSenderConfig.java | sed -E 's#^([0-9]+):# main · KafkaSenderConfig.java:\\1 #'\necho -n \" 출하 기본값 : \"\ngrep -n 'APP_MESSAGING_ENABLED' src/app-bootstrap/src/main/resources/application.yml | head -1 | sed 's#^#application.yml:#'\n\necho\necho \"# 프로덕션에서 KafkaProducer 를 만드는 두 자리 — 설정 맵 원문 그대로\"\ngrep -n '@Bean\\|@ConditionalOnMissingBean' $A/KafkaMessagingAutoConfiguration.java \\\n | awk -F: '$1>=126 && $1<=130' | sed -E 's#^([0-9]+): *# KafkaMessagingAutoConfiguration.java:\\1 #'\ncut_range $A/KafkaMessagingAutoConfiguration.java KafkaMessagingAutoConfiguration.java 139 153\necho\ngrep -n '@Bean(name = \"kafkaSeamProducer\"\\|@ConditionalOnMissingBean(name' $B/KafkaSenderConfig.java \\\n | sed -E 's#^([0-9]+): *# KafkaSenderConfig.java:\\1 #'\ncut_range $B/KafkaSenderConfig.java KafkaSenderConfig.java 64 81 | grep -v '^ KafkaSenderConfig.java:7[0-6]'\n\necho\necho \"# security.protocol 을 넣는 프로덕션 코드 — 상수명과 리터럴 양쪽으로\"\ngit grep -n 'SECURITY_PROTOCOL\\|\"security\\.protocol\"\\|SslConfigs\\|SaslConfigs\\|CommonClientConfigs' -- 'src/**/*.java' \\\n | grep '/main/' | strip\n\necho\necho \"# KafkaSecurityConfigurer.configure 가 자격 종류마다 하는 일\"\nawk 'NR>=88 && NR<=115 && (/properties.put\\(/ || /case BrokerCredentialProfile/ || /throw new/) {printf \" KafkaSecurityConfigurer.java:%d %s\\n\", NR, $0}' \\\n $K/KafkaSecurityConfigurer.java\n\necho\necho \"# 그 클래스가 빈이 되기까지의 조건 사슬\"\nawk 'NR>=105 && NR<=112 {printf \" KafkaMessagingAutoConfiguration.java:%d %s\\n\", NR, $0}' $A/KafkaMessagingAutoConfiguration.java\ngit grep -n 'ConditionalOnBean(CredentialProvider.class)\\|CredentialRuntimeRegistry credentialRuntimeRegistry' -- 'src/**/*.java' | strip\nn=$(git grep -ln 'implements CredentialProvider' -- 'src/**/*.java' | grep -c '/main/' || true)\necho \" CredentialProvider 를 구현하는 main 클래스 : $n 건\"\necho \" 그 인터페이스를 구현하는 자리 전부 :\"\ngit grep -n 'implements CredentialProvider' -- 'src/**/*.java' | strip\n\necho\necho \"# 그 빈을 파라미터나 필드로 받는 코드 (빈을 만드는 팩토리 자신은 뺀다)\"\nhits=$(git grep -n 'KafkaSecurityConfigurer' -- 'src/**/*.java' \\\n | grep -v '/KafkaSecurityConfigurer.java:' \\\n | grep -v 'public KafkaSecurityConfigurer kafkaSecurityConfigurer' \\\n | grep -v 'return new KafkaSecurityConfigurer' | grep -v 'import ' | grep '/main/' || true)\nif [ -z \"$hits\" ]; then echo \" main 에서 0 건\"; else echo \"$hits\" | strip; fi\necho \" getBean · ObjectProvider · 빈 이름 문자열로 가져가는 자리 :\"\ng=$(git grep -n 'getBean(KafkaSecurityConfigurer\\|ObjectProvider<KafkaSecurityConfigurer>\\|\"kafkaSecurityConfigurer\"' -- 'src/**/*.java' || true)\nif [ -z \"$g\" ]; then echo \" 0 건\"; else echo \"$g\" | strip; fi\n\necho\necho \"# 조립을 확인하는 테스트가 단언하는 것과, 실 브로커 시험이 붙는 컨테이너\"\ngit grep -n 'void selectingKafkaAssemblesOnlyKafka\\|void aSelectedTransportAssemblesAPublisher' -- 'src/**/*.java' | strip\ngit grep -n 'hasSingleBean\\|doesNotHaveBean' -- '**/MessagingStarterOffContractTest.java' | strip\ngit grep -n 'new KafkaContainer(' -- 'src/**/MessagingLiveRoundTripQualificationTest.java' | strip\n",
|
|
"cwd": "/shared/codebase/clean-architecture-backend-template",
|
|
"exitCode": 0,
|
|
"executedAt": "2026-09-03T12:25:08+00:00",
|
|
"sourceRevision": "21234e38cdb9a926cbc92bb97a2aee2e4a7d2916",
|
|
"raw": "evidence/raw/a-validator-that-demands-tls-and-an-assembly-that-omits-it.txt",
|
|
"svg": "evidence/rendered/a-validator-that-demands-tls-and-an-assembly-that-omits-it.svg",
|
|
"rawSha256": "72b47b4d66f485e84de208664844697d0ad0c23e4e43b0a18df95a18d75d9ef0",
|
|
"lines": 102,
|
|
"redaction": "코드베이스 측정으로 교체"
|
|
}
|