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>
61 lines
2.7 KiB
Markdown
61 lines
2.7 KiB
Markdown
---
|
|
kind: PROJECT_DECISION
|
|
slug: unclassified-commands-are-refused
|
|
title: 분류되지 않은 명령은 fail-closed로 거부한다
|
|
topic: redis-command-admission
|
|
project: clean-architecture-backend-template
|
|
status: 게시 전
|
|
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
|
rootTreeNode: decision:unclassified-commands-are-refused
|
|
decisionStatus: ADOPTED
|
|
decidedOn: 2026-08-30
|
|
source:
|
|
- src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/command/RedisCommandCatalog.java
|
|
- src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/command/CommandPolicyGuard.java
|
|
- analysis/10-adapter-outbound-cache-redis.md
|
|
---
|
|
|
|
# 분류되지 않은 명령은 fail-closed로 거부한다
|
|
|
|
## 결정문
|
|
|
|
명령 카탈로그가 분류하지 못하는 명령은 통과시키지 않고 거부한다.
|
|
|
|
## 판단 이유
|
|
|
|
승인 아홉 단계는 명령이 무엇인지 아는 것을 전제한다. 위험 등급도 키 스펙도 슬롯 계산도 카탈로그의 정의에서 나온다.
|
|
|
|
분류되지 않은 명령을 통과시키면 그 단계들이 적용되지 않은 채 실행된다. 위험 등급을 모르므로 허가 요구도 걸 수 없고, 키 스펙을 모르므로 네임스페이스 검사도 슬롯 계산도 할 수 없다.
|
|
|
|
즉 통과는 검사를 건너뛰는 것과 같다. 그리고 그 사실이 호출자에게 보이지 않는다.
|
|
|
|
거부는 시끄럽다. 새 명령을 쓰려면 카탈로그에 먼저 넣어야 한다. 그 마찰이 이 결정의 목적이다.
|
|
|
|
카탈로그의 정의가 서버 메타데이터에서 온다는 것과 함께 보면 구조가 완성된다. 서버가 아는 명령만 카탈로그에 있고, 카탈로그에 있는 명령만 실행된다.
|
|
|
|
## 영향
|
|
|
|
감수하는 것
|
|
|
|
새 Redis 명령을 쓰려면 카탈로그 갱신이 선행되어야 한다. 서버가 지원해도 바로 쓸 수 없다.
|
|
|
|
카탈로그가 뒤처지면 정상적인 명령이 거부된다. 그래서 드리프트 검사가 필요하고, 그 검사가 현재 빌드에 없다.
|
|
|
|
우회 경로가 있으면 이 결정이 그 경로에 적용되지 않는다. 다섯 어댑터가 게이트웨이를 직접 부르는 경로가 그렇다.
|
|
|
|
얻는 것
|
|
|
|
정책이 적용되지 않은 명령이 실행되지 않는다.
|
|
|
|
새 명령의 도입이 명시적 행위가 된다.
|
|
|
|
## 근거
|
|
|
|
- **서버 메타데이터가 명령의 정의이고 정책 파일은 허용 범위다**
|
|
이 결정이 기대는 관계다.
|
|
- **명령 카탈로그와 admission 아홉 단계**
|
|
카탈로그가 없으면 적용될 수 없는 단계들이다.
|
|
- **의미 어댑터 다섯이 gateway를 직접 불러 admission 아홉 단계를 건너뛴다**
|
|
이 결정이 적용되지 않는 경로다.
|
|
|