docs(keycloak-session-store): import the session-storage lab as a new project
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>
This commit is contained in:
co-authored by
Claude Opus 5
parent
43bccd08a8
commit
b2963105a8
+55
@@ -0,0 +1,55 @@
|
||||
---
|
||||
kind: REFERENCE
|
||||
slug: a-publicly-readable-state-must-be-complete-by-constraint
|
||||
title: 공개 읽기 가능한 상태는 완전한 identity를 DB 제약으로 요구한다
|
||||
topic: fileserver-state-and-fencing
|
||||
project: clean-architecture-backend-template
|
||||
status: 게시 전
|
||||
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
||||
rootTreeNode: reference:a-publicly-readable-state-must-be-complete-by-constraint
|
||||
verifiedOn: # 이 기록은 이번 회차에 실행 확인을 하지 않았다
|
||||
---
|
||||
|
||||
# 공개 읽기 가능한 상태는 완전한 identity를 DB 제약으로 요구한다
|
||||
|
||||
## 목적
|
||||
|
||||
공개 상태에 도달한 레코드가 필수 값을 빠뜨린 채 존재해, 그 값을 전제한 코드가 나중에 실패하는 것을 막는다.
|
||||
|
||||
## 규칙
|
||||
|
||||
1. 공개 상태의 요구를 데이터베이스 제약으로 표현한다
|
||||
애플리케이션 검사로 두면 그 검사를 지나지 않는 경로가 언젠가 생긴다.
|
||||
|
||||
2. 상태별로 다른 요구를 조건부 제약으로 쓴다
|
||||
모든 상태에 같은 요구를 걸면 중간 상태를 만들 수 없다.
|
||||
|
||||
3. 상태와 버전을 함께 가드한다
|
||||
상태만 조건에 넣으면 같은 상태에서 출발한 두 전이가 모두 성공한다.
|
||||
|
||||
4. 진실의 출처를 하나로 정한다
|
||||
파일시스템에 바이트가 있다는 것과 공개 가능하다는 것은 다른 사실이다. 어느 쪽이 정본인지 정하고 그것을 문서에 적는다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
외부에 노출되는 상태를 갖는 모든 레코드
|
||||
|
||||
파일이나 객체처럼 저장소와 메타데이터가 따로 있는 자원
|
||||
|
||||
## 예외
|
||||
|
||||
내부 처리 단계의 중간 상태는 완전성을 요구하지 않는다. 그 상태가 외부로 새지 않는 것이 보장되어야 한다.
|
||||
|
||||
## 예시
|
||||
|
||||
파일 메타데이터의 헤더가 관계형 레코드가 공개 가능 여부를 정한다고 명시하고, 모든 상태 전이가 상태와 버전 양쪽으로 가드된다고 적는다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **파일 상태 기계와 READY가 뜻하는 것**
|
||||
이 규칙이 나온 개념이다.
|
||||
- **CAS 튜플을 where 절에 전부 반복하고 update count를 답으로 쓴다**
|
||||
세 번째 규칙의 일반형이다.
|
||||
- **위험한 조합은 정책이 아니라 생성자가 거부하게 만든다**
|
||||
같은 원칙의 값 타입 판이다.
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
---
|
||||
kind: REFERENCE
|
||||
slug: claim-with-a-conditional-update-not-a-read
|
||||
title: 조건부 update로 행을 claim하고 읽은 값으로 판단하지 않는다
|
||||
topic: fileserver-state-and-fencing
|
||||
project: clean-architecture-backend-template
|
||||
status: 게시 전
|
||||
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
||||
rootTreeNode: reference:claim-with-a-conditional-update-not-a-read
|
||||
verifiedOn: # 이 기록은 이번 회차에 실행 확인을 하지 않았다
|
||||
---
|
||||
|
||||
# 조건부 update로 행을 claim하고 읽은 값으로 판단하지 않는다
|
||||
|
||||
## 목적
|
||||
|
||||
읽기와 행동 사이에 상태가 바뀌어, 이미 유효하지 않은 판단으로 되돌릴 수 없는 작업을 수행하는 것을 막는다.
|
||||
|
||||
## 규칙
|
||||
|
||||
1. 읽고 나서 판단하지 않는다
|
||||
조건을 갱신문의 where 절에 넣고 갱신 건수로 판단한다.
|
||||
|
||||
2. 되돌릴 수 없는 작업 앞에서는 특히 그렇다
|
||||
물리 삭제나 외부 호출은 되돌릴 수 없다. 그 앞의 판단은 원자적이어야 한다.
|
||||
|
||||
3. 양쪽이 같은 사실을 본다
|
||||
한쪽은 리스의 부재를 보고 다른 쪽은 만료만 보면, 둘 다 자기 기준으로 옳으면서 서로 어긋난다.
|
||||
|
||||
4. 상태를 명시적으로 만든다
|
||||
끝났다는 사실이 값으로 없으면 각 참여자가 그것을 추론하고, 추론의 근거가 서로 다르다.
|
||||
|
||||
5. 청구하지 못하면 미룬다
|
||||
갱신 건수가 0 이면 다른 참여자가 그 행을 들고 있다는 뜻이다. 강제하지 않고 다음 주기로 넘긴다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
여러 참여자가 같은 자원을 놓고 경합하는 정리 작업과 배치
|
||||
|
||||
물리 삭제나 외부 호출이 뒤따르는 판정
|
||||
|
||||
## 예외
|
||||
|
||||
읽기와 행동이 같은 트랜잭션 안에서 행 잠금과 함께 일어나면 조건부 갱신 없이도 안전하다. 그 잠금이 실제로 걸리는지 확인해야 한다.
|
||||
|
||||
## 예시
|
||||
|
||||
정리가 쓰기 리스를 읽어 없음을 확인하고 스테이징 바이트를 지웠다. 읽기와 삭제 사이에 쓰기 작업자가 그 리스를 얻었고, 지워진 것은 업로드가 이어 쓰고 있던 객체였다.
|
||||
|
||||
수정 후 정리는 조건부 갱신으로 청구하고, 리스가 실제로 걸려 있으면 아무것도 청구하지 않고 미룬다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **cleanup이 읽은 lease와 삭제 사이에 writer가 그 lease를 얻을 수 있었다**
|
||||
이 규칙을 만든 사례다.
|
||||
- **CAS 튜플을 where 절에 전부 반복하고 update count를 답으로 쓴다**
|
||||
같은 규칙의 상태 기계 판이다.
|
||||
- **시간은 DB에서, 그리고 행을 잠근 다음에 읽는다**
|
||||
같은 계열의 짝 규칙이다.
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
---
|
||||
kind: REFERENCE
|
||||
slug: prefix-matching-fits-signatures-not-sniffing
|
||||
title: 접두사 시작 매칭은 시그니처에는 맞고 스니핑 패턴에는 맞지 않는다
|
||||
topic: fileserver-state-and-fencing
|
||||
project: clean-architecture-backend-template
|
||||
status: 게시 전
|
||||
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
||||
rootTreeNode: reference:prefix-matching-fits-signatures-not-sniffing
|
||||
verifiedOn: # 이 기록은 이번 회차에 실행 확인을 하지 않았다
|
||||
---
|
||||
|
||||
# 접두사 시작 매칭은 시그니처에는 맞고 스니핑 패턴에는 맞지 않는다
|
||||
|
||||
## 목적
|
||||
|
||||
파일 형식 시그니처를 찾는 방법으로 브라우저 스니핑 대상을 찾아, 앞에 바이트를 붙이는 것만으로 우회되는 것을 막는다.
|
||||
|
||||
## 규칙
|
||||
|
||||
1. 두 문제를 구별한다
|
||||
형식 시그니처는 정의상 시작 바이트다. 브라우저 스니핑은 관용적 해석이므로 시작이 아니어도 된다.
|
||||
|
||||
2. 스니핑 대상은 포함으로 찾는다
|
||||
앞의 일정 구간 안에 마커가 있으면 탐지한다. 시작이어야 한다는 조건을 걸지 않는다.
|
||||
|
||||
3. 앞에 붙는 것들을 목록으로 갖는다
|
||||
바이트 순서 표시와 널 바이트와 공백과 주석이 흔하다.
|
||||
|
||||
4. 탐지 대상은 소비자의 관용도에 맞춘다
|
||||
무엇을 실행할지 정하는 것은 브라우저다. 우리 파서가 아니다.
|
||||
|
||||
5. 같은 함수를 두 목적에 쓰지 않는다
|
||||
한쪽에 맞추면 다른 쪽이 틀린다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
업로드 콘텐츠 검증
|
||||
|
||||
인라인으로 제공될 수 있는 모든 콘텐츠의 분류
|
||||
|
||||
## 예외
|
||||
|
||||
형식 시그니처를 확인해 파일 타입을 판정하는 목적이면 시작 매칭이 옳다. 그 경우 그 판정이 보안 결정으로 쓰이지 않아야 한다.
|
||||
|
||||
## 예시
|
||||
|
||||
실행 가능 콘텐츠 정책이 앞의 1024 바이트에서 마커를 찾되 시작 매칭을 쓴다. 바이트 순서 표시나 널 바이트나 주석을 앞에 붙이면 탐지되지 않고, 브라우저는 그런 파일도 실행한다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **scriptable 콘텐츠 탐지가 BOM과 NUL과 주석으로 우회된다**
|
||||
이 규칙을 만든 사례다.
|
||||
- **sanitize가 아니라 reject가 기본이다**
|
||||
탐지된 콘텐츠를 어떻게 다룰지 정한 규칙이다.
|
||||
|
||||
Reference in New Issue
Block a user