Files
document-haness/reviews/2026-09-20-keycloak-session-store-post-remediation-verification.md
T

15 KiB
Raw Blame History

keycloak-session-store 후속 검증 리뷰

  • 검토일: 2026-09-20
  • 대상: 이전 리뷰 reviews/2026-09-20-keycloak-session-store-seven-stage-review.md 반영 결과
  • 판정: 아직 더 봐야댐

1. 결론

이전 리뷰의 문서 내용 자체는 대부분 제대로 반영됐다.

특히 다음은 확실히 닫혔다.

  • command analyzer가 bash label="...", sh label="..."을 읽도록 수정됨
  • TechLog Record의 shell block 992개 / 33 Record를 analyzer가 실제로 인식함
  • label의 [lab host], [워크스테이션], [탐침 파드] 같은 실행 위치를 execution context로 인식함
  • 관련 회귀 테스트가 추가됨
  • Tree의 미처분 SSOT 절이 KEEP_IN_SSOT / CONFIRMED로 처분됨
  • 이 기준이 선 근거.이 기준의 근거다.로 수정됨
  • prose/voice는 현재도 61/61 PASS
  • TechViz가 직접 근거로 삼는 current_section31/31 최신 SSOT와 일치
  • Figure Text / Overlap / Provenance 모두 PASS
  • 전체 pipeline은 exit 0
  • 전체 unittest는 397 PASS / 14 skipped

따라서 이전처럼 “문서 내용이 많이 남아 있다”는 상태는 아니다.

하지만 완료를 증명하는 현재 remediation run의 관문 기록이 하네스 계약과 맞지 않는다. 이 문제가 남아 있어서 현재 상태를 완료로 판정하면 안 된다.


2. 이전 리뷰 항목별 재검증

2.1 Command analyzer — 반영됨

이전 문제:

analyzer가 bash label=..., sh label=...을 읽지 못해 shell block 99.2%를 놓쳤다.

현재 scripts/command_pedagogy.py는 fence의 첫 info token을 언어로 읽는다.

현재 전수 결과:

Record                         61
command-bearing Record         33
shell block                   992

즉 이전에 빠졌던 labeled fence까지 모두 잡힌다.

현재 테스트에도 다음 계약이 들어갔다.

  • labeled bash fence 분석
  • labeled sh fence 분석
  • 첫 token 전체 일치 검사
  • label execution context 인식
  • context가 아닌 label은 remote execution context를 숨기지 못함

이 항목은 반영 완료로 본다.


2.2 Command corpus 재분석 — 내용상 큰 결함은 새로 나오지 않음

기존 corpus 정책대로 reference mode로 61 Record 전체를 다시 분석했다.

command-bearing Record = 33
shell blocks           = 992
findings               = 53
major findings         = 0
command-like text      = 15

남은 53개 deterministic signal:

hidden-stderr         48
compound-remote-shell  5

이것들은 전역 금지 항목이 아니다.

실제 문맥을 다시 확인하면 대표적으로:

  • OpenSSL의 handshake noise를 없앤 뒤 x509 값을 보는 경우
  • JWT payload를 base64 decode하면서 decode stderr를 숨기는 경우
  • build/restore 출력을 /tmp/*.log로 모은 뒤 그 파일을 읽는 경우
  • nginx -t && nginx -s reload처럼 검증 성공 뒤에만 변경하는 안전 조건
  • conntrack 실험처럼 stderr 억제가 어떤 오판을 만드는지 본문이 오히려 설명하는 경우

가 대부분이다.

따라서 현재 전수 재검사에서 새로운 high-confidence command defect는 발견하지 못했다.

다만 아래 §4의 검토 증거 범위 문제는 별개다.


2.3 Tree 미처분 절 — 반영됨

이전 미처분 절:

2026-09-17 재현 — 어디까지 밟았고 무엇이 막았나

현재 tree에는 새 candidate가 생겼다.

id: SSOT-2026-09-17-reproduction-progress-and-blocker
disposition: KEEP_IN_SSOT
dispositionReview: CONFIRMED

이유도 적절하다.

  • 시점 의존적인 진행 추적 정보
  • 각 Setup이 실제 절차와 미완료 단계를 이미 담음
  • 별도 Record로 올리면 중복

현재 Tree 결과:

records=61
written=61
unwritten=0
KEEP_IN_SSOT=23
warn=1

남은 warn 1은 source repository 부재뿐이다.

이 항목은 반영 완료다.


2.4 깨진 문장 — 반영됨

이전:

이 기준이 선 근거.

현재:

이 기준의 근거다.

또 Relation의 반복 문형도 일부 선별 정리했다.

예:

이 절차가 만드는 두 시각의 차이에 대한 결론은 그 기록에 있다.

등으로 바뀌었다.

현재:

check_prose 61/61 PASS
check_voice 61/61 PASS

이 항목은 반영 완료다.


3. SVG — 본문 근거는 닫혔지만 layout warning 7개는 남음

이전에는 31개 중 28개가 현재 SSOT section과 달랐다.

현재 직접 비교 결과:

current_section exact match = 31 / 31

그림이 직접 근거로 삼는 현재 절은 전부 최신 SSOT와 맞는다.

Figure gate도:

Figure Text       PASS 31/31
Figure Overlap    PASS 31/31
Figure Provenance PASS 31/31

이다.

따라서 이전의 “28개 그림이 옛 본문을 보고 있다”는 핵심 문제는 닫혔다.

다만 verify-project-layout.py에는 아직 7개 context warning이 남는다.

a1-transport-vs-discovery
d2-upgrade-direction
lab-topology
measurement-control
observation-points
open-questions-answered
wrong-predictions

세부적으로 보면 앞의 여섯 개는:

  • current_section = MATCH
  • next_section = MATCH
  • 상위/이전 parent section snapshot만 STALE

인 형태다.

wrong-predictions는:

  • previous = MATCH
  • current = MATCH
  • next 자료 section = STALE

이다.

그림 자체의 직접 근거가 낡았다는 의미는 아니다. 여러 child section을 포함하는 parent/neighbor context가 뒤의 SSOT 수정 때문에 다시 달라진 잔여 warning이다.

그래도 현재 verifier가 이를 stale context로 보고 있으므로 최종 cleanup은 필요하다.

권장:

  1. 모든 SSOT 수정이 끝난 뒤 이 7개 context를 마지막에 다시 prepare
  2. spec의 semantic node/edge가 그대로인지 확인
  3. semantic 변화가 없으면 context/evidence hash만 최신화
  4. render → lint → text → overlap → provenance → preview
  5. 다시 verify-project-layout.py keycloak-session-store

또는 parent section 전체를 previous context로 잡는 구조가 계속 연쇄 stale을 만든다면 verifier/context 모델을 별도 개선한다.

SVG 내용 자체는 현재 정상으로 보지만, layout warning 7개는 아직 정리되지 않았다.


4. 완료 차단 — 새 remediation run이 evidence gate에서 --repo를 빼고 PASS를 만들었다

이것이 현재 가장 중요한 finding이다.

현재 authoritative stage contract의 S3 gate:

node .agents/skills/writing-tech-log-records/scripts/check_evidence.mjs <프로젝트> --repo

S5와 S6도 S3 gate를 다시 실행하므로 동일하게 --repo가 필요하다.

또 현재 pipeline skill은 명확히 적는다.

exit 0 = 저장소 대조 완료
exit 1 = 실제 불일치
exit 2 = 검사 대상 불성립
exit 3 = source repo 부재로 UNVERIFIABLE

새 publication run에서는 exit 3을 PASS로 기록하면 안 된다.

그런데 새로 만든 remediation run 6개를 확인하면 S3/S5/S6가 전부 다음처럼 기록돼 있다.

node .agents/skills/writing-tech-log-records/scripts/check_evidence.mjs keycloak-session-store

--repo가 없다.

대상 run:

2026-09-20-1725-remediation-01-setup-reproduce-d4-certificate-renewal
2026-09-20-1725-remediation-02-setup-reproduce-d4a-deploy-hook
2026-09-20-1725-remediation-03-setup-reproduce-a7a-volatile-cause
2026-09-20-1725-remediation-04-setup-reproduce-b7a-orphan-session
2026-09-20-1725-remediation-05-reference-look-at-the-lookup-key-before-moving-the-store
2026-09-20-1725-remediation-06-setup-reproduce-b6-key-rotation

6 run × S3/S5/S6 = 18개 evidence gate 전부 --repo 누락이다.

실제로 현재 머신에서 실행하면:

현재 run이 기록한 명령

check_evidence.mjs keycloak-session-store
→ exit 0
→ 문제 없음

계약에 적힌 명령

check_evidence.mjs keycloak-session-store --repo
→ exit 3
→ 저장소 경로가 이 기계에 없다
→ 불일치 0 / 대조 불가 1

즉 현재 run은 원본 대조를 수행하지 않은 명령을 실행하고 PASS라고 기록했다.

사용자와 합의한 기준상 source repository 부재 자체는 완료 차단으로 보지 않아도 된다.

하지만 그것은:

원본 대조를 하지 않고 PASS로 바꿔도 된다

는 뜻이 아니다.

정확한 상태는:

live source reconciliation = UNVERIFIABLE

이다.

필요한 수정

기존 17:25 remediation run은 이미 만들어진 영수증이므로 고쳐 쓰지 않는다.

대신 둘 중 하나로 해결한다.

A. source repo가 실제로 있으면

정본 경로를 찾아 tree의 sourceRepository를 실제 경로에 맞춘 뒤:

check_evidence --repo
→ exit 0

으로 새 verification/remediation run을 만든다.

B. source repo가 이 환경에는 없고 이를 사용자 예외로 허용한다면

--repo를 삭제하지 말고 결과를 그대로 남길 수 있어야 한다.

즉 run schema/verifier에 명시적인 상태를 둔다.

예:

status: UNVERIFIABLE
exit: 3
reason: source repository unavailable on current machine
acceptedByProjectReview: true

이름은 달라도 된다.

핵심은:

  • 실제 명령은 --repo 포함
  • 실제 exit 3 보존
  • PASS로 위장하지 않음
  • 이 프로젝트에서는 사용자가 허용한 환경 제약이므로 전체 완료를 막지 않는다는 정책을 별도 표현

이다.

현재처럼 flag 자체를 빼는 방식은 안 된다.


5. verifier blind spot — 잘못된 gate인데 run verifier가 PASS한다

위 6개 run에 대해:

python3 scripts/verify-pipeline-run.py <run.json>

은 전부 PASS한다.

즉 verifier는 현재:

  • evidence gate가 하나 존재하는지
  • recorded exit가 0인지

등은 보지만,

S3/S5/S6가 계약에 적힌 check_evidence.mjs <project> --repo를 실제로 실행했는가

까지는 강제하지 않는다.

그래서 계약보다 약한 명령을 기록해도 통과했다.

이 부분도 같이 막아야 한다.

권장:

  • stage gate를 raw command 문자열만으로 보지 말고 semantic gate id를 둔다.
  • 최소한 S3/S5/S6의 evidence gate는 --repo 존재를 검증한다.
  • 사용자가 허용한 source-missing 예외를 도입한다면 exit 3 + UNVERIFIABLE 상태를 verifier가 이해하게 한다.

검사기를 통과시키려고 관문을 약하게 만드는 경로를 차단해야 한다.


6. 33 Record / 992 command 재검토의 “증거 범위”는 아직 약함

이전 리뷰는:

33개 command-bearing Record
992 shell block

을 parser 수정 뒤 다시 분석하라고 했다.

현재 내용 자체는 내가 이번 검토에서 다시 전수 실행했고:

reference mode:
  records   33
  blocks   992
  findings  53
  major      0

을 확인했다.

그래서 현재 command 내용에서 새 major defect가 남았다고 보지는 않는다.

다만 repository에 새 command review artifact가 남아 있는 것은 이번 remediation에서 다룬 일부 Record뿐이다.

새 schemaVersion 4 remediation 중 command block이 있는 Record:

D-4
D-4a
A-7a
B-7a
B-6

즉 current reviewer artifact가 직접 남은 것은 5 / 33 command-bearing Record다.

나머지는 옛 schemaVersion 1/2 run만 있고, 그것은 parser가 labeled fence를 못 보던 시기의 영수증이다.

이전 리뷰는 historical ledger를 소급 조작하지 말라고 했으므로 옛 run을 고치면 안 된다.

대신 프로젝트 단위 current command audit artifact를 하나 남기는 편이 맞다.

예:

reviews/2026-09-20-keycloak-session-store-command-audit.json
reviews/2026-09-20-keycloak-session-store-command-audit.md

여기에 33 Record 각각에 대해:

  • source SHA256
  • shellBlocks
  • mode
  • findings
  • majorFindings
  • minor finding disposition
  • reviewer verdict

을 남긴다.

Record를 실제로 수정한 경우에만 새 remediation run을 만든다.

이렇게 하면 historical receipt를 위조하지 않으면서도 **“parser 수정 뒤 992개를 다시 봤다”**는 현재 증거가 남는다.


7. 현재 자동 검증 결과

프로젝트 gate

verify-tech-log-tree       PASS
verify-project-layout      PASS (warn 존재)
audit-records              PASS
check-figure-text          PASS 31/31
check-figure-overlap       PASS 31/31
check-figure-provenance    PASS 31/31
check-required-content     PASS 61
check-ssot-facts           PASS
git diff --check           PASS

문체

prose 61/61 PASS
voice 61/61 PASS

전체 pipeline

verify-pipeline.py
exit 0

parser가 수정되면서 전체 corpus도 이제 Record의 labeled shell fence를 실제로 세고 있다.

keycloak-session-store 전체(final SSOT + Record) 기준:

shell blocks = 1920
findings     = 150

이 수치가 이전보다 늘어난 것은 defect가 늘어난 것이 아니라 전에 못 보던 labeled fence를 이제 보기 시작했기 때문이다.

전체 unittest

Ran 397 tests
OK
skipped=14

새 labeled-fence 관련 테스트도 통과한다.


8. 남은 작업 순서

1. evidence gate 우회부터 고친다

가장 먼저 한다.

  • 기존 17:25 run 수정 금지
  • --repo를 제거해 PASS시키는 방식 금지
  • source missing을 명시적 UNVERIFIABLE로 보존할 수 있게 계약/verifier를 정리
  • 또는 실제 source repo를 찾을 수 있다면 정본 경로로 대조

2. run verifier가 필수 evidence gate를 검증하게 한다

최소 S3/S5/S6에서:

check_evidence.mjs <project> --repo

를 요구한다.

환경 예외가 있으면 명시적 상태로만 허용한다.

3. 33 Record command audit를 현재 artifact로 남긴다

  • 992 block
  • reference-mode 53 minor / 0 major
  • minor의 문맥상 허용 여부
  • 15 command-like text의 분류

를 프로젝트 단위 audit으로 남긴다.

실제 수정한 Record만 새 remediation run을 만든다.

4. SVG 잔여 context warning 7개를 마지막에 닫는다

current section은 이미 31/31 맞다.

남은 7개 previous/next snapshot만 모든 SSOT 수정 후 마지막에 regenerate/review한다.

5. 최종 검증

순서대로:

project gates
→ verify-pipeline.py
→ unittest

9. 최종 판정

이전 리뷰의 문서 내용 수정은 대부분 제대로 반영됐다.

특히:

  • parser
  • Tree
  • 문체
  • 그림의 직접 SSOT 근거

는 제대로 개선됐다.

하지만 현재 remediation run 6개가 계약상 필수인 --repo evidence reconciliation을 생략한 채 PASS로 기록되어 있고, verifier도 그 우회를 잡지 못한다.

따라서 지금 상태는:

keycloak-session-store = 아직 더 봐야댐

문서 내용보다 검증 계약과 영수증의 진실성을 한 번 더 고쳐야 한다.