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>
69 lines
4.7 KiB
Plaintext
69 lines
4.7 KiB
Plaintext
# 주제: DestructiveOperationGuard 의 6개 검사 중 2개가 어떤 테스트에도 도달하지 않으며,
|
|
# 클래스 javadoc 은 그 2개를 세지 않는다
|
|
# revision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
|
|
|
# DestructiveOperationGuard.authorize 의 실제 분기 (DestructiveOperationGuard.java:54-93)
|
|
# 1) dryRun -> 무조건 통과 (:54-56)
|
|
# 2) !adminCredentialPresent -> ADMIN_CREDENTIAL_REQUIRED (:57-61)
|
|
# 3) approval 부재 -> APPROVAL_REQUIRED (:62-67)
|
|
# 4) !isValidAt(now) -> APPROVAL_EXPIRED (:68-71)
|
|
# 5) operation 불일치 -> APPROVAL_OPERATION_MISMATCH (:72-83)
|
|
# 6) source 불일치 -> APPROVAL_SOURCE_MISMATCH (:84-93)
|
|
#
|
|
# 클래스 javadoc (:12-15):
|
|
# "Four conditions, all required. The caller must hold the admin credential … The approval must
|
|
# be present and inside its validity window. And a dry run is always permitted …"
|
|
# -> 1~4만 서술한다. 5, 6은 언급되지 않는다.
|
|
# (5번 분기에는 별도 인라인 주석이 있다: "A guard that only checks presence and window
|
|
# lets a verified redrive approval authorise a destination deletion." — 즉 의도된 검사다.)
|
|
|
|
# command: git grep -n "\.authorize(" -- src | grep -i "messaging"
|
|
# exit: 0
|
|
src/messaging/messaging-admin-api/src/test/java/.../DestructiveOperationGuardTest.java:56,67,84,96,107 (테스트 5건)
|
|
src/messaging/messaging-admin-runtime/src/main/java/.../RedriveService.java:97
|
|
src/messaging/messaging-admin-runtime/src/main/java/.../ReplayService.java:59
|
|
# => guard.authorize 를 부르는 테스트는 DestructiveOperationGuardTest 의 5건이 전부다.
|
|
|
|
# 그 5건이 도달하는 분기:
|
|
# anApplicationRuntimeCannotRedrive -> 2 (ADMIN_CREDENTIAL_REQUIRED)
|
|
# anAdminRuntimeStillNeedsAnApproval -> 3 (APPROVAL_REQUIRED)
|
|
# anExpiredApprovalDoesNotAuthorise -> 4 (APPROVAL_EXPIRED)
|
|
# aDryRunIsAlwaysPermitted -> 1
|
|
# anApprovedAdminOperationIsAuthorised -> 통과
|
|
# => 분기 5, 6 에 도달하는 테스트가 없다.
|
|
|
|
# 주목: 유일하게 불일치 조합을 넘기는 테스트가 있으나 앞 분기에서 먼저 걸린다.
|
|
# DestructiveOperationGuardTest.java:52-59 anApplicationRuntimeCannotRedrive
|
|
# guard = new DestructiveOperationGuard(false) <- 자격증명 없음
|
|
# guard.authorize(DestructiveOperation.REDRIVE, ORDERS, Optional.of(VALID), false, NOW)
|
|
# VALID 는 :24-25 에서 DestructiveOperation.REPLAY 로 만들어진 승인이다.
|
|
# -> operation 이 실제로 불일치(REDRIVE vs REPLAY)하지만,
|
|
# 분기 2가 먼저 던지므로 단언은 "admin credential" 이다. 분기 5는 실행되지 않는다.
|
|
|
|
# command: git grep -n "APPROVAL_OPERATION_MISMATCH\|APPROVAL_SOURCE_MISMATCH" -- src | grep -v "messaging-admin-api/src/main"
|
|
# exit: 1 (출력 없음)
|
|
# => 두 에러 코드를 단언하는 테스트가 저장소 전체에 없다.
|
|
# (동명 개념은 ApprovedReplayPlan / ApprovedRedrivePlan 생성자에도 있고 그쪽은
|
|
# messaging-admin-runtime 의 ApprovalForgeryTest 가 행위로 검증한다:
|
|
# anApprovalForAReplayCannotAuthoriseARedrive, aVerifiedApprovalForTheWrongSourceCannotBeAttached.
|
|
# 그러나 그것은 record 생성자이지 guard 의 분기가 아니다 — 서로 다른 코드다.)
|
|
|
|
# ---- 배선 ----
|
|
# command: git grep -nE "new ([a-zA-Z0-9_.]+\.)?DestructiveOperationGuard\s*\(" -- src
|
|
src/messaging/messaging-admin-api/src/test/java/.../DestructiveOperationGuardTest.java:52,64,74,92,103
|
|
src/messaging/messaging-admin-runtime/src/test/java/.../RedriveResumptionTest.java:142 new DestructiveOperationGuard(true)
|
|
src/messaging/messaging-spring-boot-starter/src/main/java/.../MessagingAdminAutoConfiguration.java:40
|
|
return new DestructiveOperationGuard(false);
|
|
# => 프로덕션 생성은 1건이며 adminCredentialPresent=false 로 고정이다. 이는 의도된 설계이고
|
|
# 주석이 명시한다("An operator tool overrides this bean with true.").
|
|
# 결과적으로 부팅된 애플리케이션에서는 분기 2에서 항상 멈추므로 3~6은 도달 불가다.
|
|
|
|
# ---- ApprovalVerifier 배선 ----
|
|
# command: git grep -n "implements ApprovalVerifier" -- src
|
|
src/messaging/messaging-admin-api/.../HmacApprovalVerifier.java:26
|
|
# command: git grep -nE "new ([a-zA-Z0-9_.]+\.)?HmacApprovalVerifier\s*\(" -- src | grep "/src/main/"
|
|
# exit: 1 (출력 없음) — src/main 생성 0건, src/test 생성 5건
|
|
# => 부팅된 애플리케이션에는 ApprovalVerifier 빈이 없다. VerifiedApproval 을 만들 수 있는 주체가
|
|
# 프로덕션 배선에 존재하지 않는다. (스타터 javadoc 이 이 스탠스를 명시한다:
|
|
# "an operator tool that needs purge or delete registers one itself".)
|