Review loop (--review-only, --all-reviewer): round 1 (@325b056) 4/4 PASS,
round 2 (@db7f4ca, HERDR_SESSION) 4/4 PASS. Full suite at 325b056 on
macOS / Python 3.9 / bash 3.2 / herdr 0.9.3 from an agent pane:
1845 passed / 0 failed / 56 skipped (18 test_deploy_freshness skips: no
nats-docker submodule in the fresh worktree); the panes of the real
servers (default, multi-agent-mux) and ~/.claude/projects were unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
8.9 KiB
Job efb52908 — herdr leak fix review
판정: PASS. 지정된 2개 커밋/4개 파일에서 이번 변경을 차단할 결함은 발견하지 않았다. 관련 테스트 105 passed, 1 deselected이고, base/head 디코이 탐침으로 경로 선택 수정과 기존 래퍼 제외 동작을 확인했다. 아래 기존 해석기 차이와 운영상 한계는 이번 변경의 회귀와 구분한다.
검증 identity 및 범위
- loop:
loop-20261013T001819Z-131fa6 - base:
8b0b4a07dc76a4915895bdde6170dc8eed9b5f74 - head:
325b056057fcdd717d2c81017fc5ef57183cb4d0 - tree:
7905896f005159d596e3872d0ee2c3c12061f09a - 검증 cwd:
/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261013T001819Z-131fa6/1 - Python:
/Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.venv/bin/python
검증 종료 시에도 HEAD/tree가 위 identity와 일치하고 git status --short는 비어 있었다. git diff --check <base>와 /bin/bash -n .agents/skills/lib.sh 모두 통과했다. 리뷰 소스 수정, creator 작업 트리 실행, 커밋·push는 하지 않았다.
변경 검토
L1: 조상 디렉터리 이름 때문에 mock이 가려지는 문제
.agents/skills/lib.sh:113–124는 일반 *-shim 제외를 디렉터리 자체의 접미사로 제한한다. :132에서 PATH 디렉터리를 검사하고, :134–136에서는 심볼릭 링크 해석 후 후보 파일의 dirname을 검사한다. 따라서 파일 이름 herdr 때문에 접미사 검사가 무력화되지 않고, wrapper를 가리키는 링크도 기존처럼 제외된다. 생성 shim의 :172–176도 일반 접미사 조건을 같은 방향으로 좁힌다.
검증 트리의 base와 head에서 해당 함수 본문만 추출해 /bin/bash로 실행했다. PATH 후보는 모두 /tmp에 만든 디코이이며 실제 herdr는 후보에 없었다.
| 후보 위치 | base 결과 | head 결과 |
|---|---|---|
pytest-x-shim/case/bin/herdr |
두 해석기 모두 후보를 건너뛰고 다음 디코이 선택 | 두 해석기 모두 첫 후보 선택 |
herdr-shim/herdr |
두 해석기 모두 제외 | 두 해석기 모두 제외 |
.mam/shim/herdr |
두 해석기 모두 제외 | 두 해석기 모두 제외 |
multi-agent-herdr-shim/herdr |
두 해석기 모두 제외 | 두 해석기 모두 제외 |
.agents/skills/.bin/herdr |
lib 해석기는 제외; 생성 shim은 선택 | 동일: lib 해석기는 제외; 생성 shim은 선택 |
추가로 lib 해석기에서 일반 front/herdr 심볼릭 링크가 wrapped-shim/herdr 또는 .agents/skills/.bin/herdr를 가리키면 제외됨을 확인했다. 링크 대상이 parent-shim/bin/herdr이면 허용됐다. 조상 이름과 wrapper 자체의 이름을 구분하려는 변경에 부합한다.
L2: pane 라우팅 환경 격리
tests/conftest.py:290–303에서 기존 세션 이름·workspace·config 격리에 socket/pane/tab 삭제가 추가됐다. tests/test_herdr_real_server_leak.py:73–87은 안전한 가짜 socket 값과 pane 변수를 먼저 주입하고 mam_sandbox 이후 남지 않는지 검증하며 통과했다. 바깥 실행 환경을 미리 정리했더라도 이 시험은 자체적으로 오염 환경을 다시 만들어 검사한다.
브리프에 기록된 실제 herdr의 socket 우선순위 실측과 일치하는 수정이다. 이번 리뷰에서는 운영 서버 접촉을 금지한 조건에 따라 실제 서버 라우팅을 재현하지 않았다. 따라서 socket 우선순위의 실서버 증거는 브리프의 실측이고, 본 리뷰의 독립 증거는 fixture 삭제 동작 및 디코이 호출 경로 검증이다.
mam_sandbox 밖의 경로와 HERDR_SESSION
삭제 범위는 mam_sandbox를 사용하는 시험에 한정된다. 검토한 비-sandbox 경로에서 이번 사고와 같은 추가 실제 서버 변경 경로는 찾지 못했다.
tests/test_issue50_dispatch_herdr.py:73–85의 실제 서버용 Box 환경은 모든HERDR_*를 제거하고 일회용 HOME/서버를 지정한다.tests/test_issue45_restore.py:41–57의 Rig는 socket/pane/tab/workspace 및HERDR_SESSION, config 관련 값을 제거한다. 이 실서버 모듈들은 이번 리뷰에서 실행하지 않고 코드만 확인했다.tests/test_issue17_item4_decisions.py:224–233은 별도 환경 구성에서HERDR_*전체를 제거한다. 다른 비-sandbox 단위 시험은 in-process stub, 추출한 shell 함수, 또는 명시적인 mock을 사용하는 경로인지 확인했다.mam_sandbox는HERDR_SESSION자체를 삭제하지 않는다. 해당 값은lib.sh:1425–1427의 caller 식별 및lib_py/pane_lock.py:45–65의 lock 이름에 사용될 수 있다. lock 경로는 sandbox HOME 아래이며, socket·config 경로가 제거된 상태에서 이 변수만으로 운영 서버에 접속하는 재현은 얻지 않았다. 따라서 이를 이번 수정의 차단 결함으로 확대하지 않는다. 향후 공통 환경 정리 시 함께 다룰 수 있는 격리 보강 항목이다.
공유 생성 shim의 영향
이번 변경은 생성 heredoc의 한 조건을 의도적으로 바꾼다. _init_herdr_isolation은 lib.sh:149–157에서 제어 루트 아래 임시 shim을 만들고 :1389–1390에서 rename으로 교체한다. 별도 wrapper 내용 변경 외의 프로토콜 변경은 없다.
test_issue23_24_startup_path.py:295–315의 기준을 525df2b로 이동한 것은 이 의도적인 heredoc 변경을 반영하며 해당 테스트가 실제로 통과했다. 다만 이 테스트는 head와 그 새 기준의 동일성을 확인할 뿐, 현재 실행 중인 모든 체크아웃이 새 버전을 사용한다는 증명은 아니다. 오래된 코드와 새 코드가 동일 제어 루트를 공유하며 shim을 다시 생성하면 마지막 writer의 버전이 적용된다. 배포 시 같은 제어 루트의 생성 주체를 같은 버전으로 맞추는 것이 필요하다. 리뷰 중에는 운영 제어 루트의 shim을 읽거나 갱신하지 않았다.
비차단 기존 차이: 생성 shim의 .bin 제외 누락
lib.sh:115의 lib 해석기는 .agents/skills/.bin을 제외하지만, :176의 생성 shim 해석기는 그 별도 규칙을 가지고 있지 않다. 위 디코이 탐침에서 base와 head 모두 동일하게 확인했다. 그러므로 두 해석기가 모든 wrapper 경로에 대해 동일한 제외 규칙을 갖는다고 결론 내릴 수는 없다.
재현: .agents/skills/.bin/herdr 디코이를 PATH 첫 번째에, 다른 디렉터리의 디코이를 그 다음에 놓고 각 해석기를 호출한다. lib는 두 번째를 반환하고 생성 shim은 첫 번째를 반환한다. 원하는 완전한 일관성 기준에서는 생성 shim도 첫 번째를 제외해야 한다. 별도 보강 시 두 해석기의 명시적 wrapper 경로 규칙을 맞추고 이 경우를 회귀 테스트에 추가하는 방향이 적절하다. base부터 있던 차이이고 이번 접미사 축소로 새로 생긴 동작이 아니므로 본 변경의 PASS를 막지 않는다.
실행 결과와 재현
안전 launcher: /tmp/efb52908-review/run.py
env -u HERDR_SOCKET_PATH -u HERDR_PANE_ID -u HERDR_TAB_ID -u HERDR_WORKSPACE_ID -u HERDR_SESSION_NAME -u WORKSPACE_ROOT -u MAM_ENV_FILE <Python> /tmp/efb52908-review/run.py tests/test_herdr_real_server_leak.py tests/test_herdr_shim_contract.py tests/test_issue23_24_startup_path.py tests/test_issue9_server_env.py -k 'not test_h10_real_herdr_schema_match'
- 결과: 105 passed, 1 deselected in 177.07s, exit 0.
- 실제 설치 herdr의 schema를 조회하는
test_h10_real_herdr_schema_match만 명시적으로 제외했다. 전체 프로젝트 스위트는 실행하지 않았다. - 로그:
/tmp/efb52908-review/tests.log - basetemp:
/tmp/efb52908-bbxxt8p8/bt(이름에 shim 없음). - launcher는 추가로 모든 상속
HERDR_*,MAM_*,MQTT_*,SKS_*및 제어/에이전트 경로 변수를 제거하고 일회용 HOME, 지정 Python,PYTHONDONTWRITEBYTECODE=1,-p no:cacheprovider를 사용했다. - fallback PATH에 호출을 기록하고 exit 97로 종료하는 herdr 디코이를 설치했다. fallback 호출 기록 없음. 테스트별 mock이 가려져 설치 herdr까지 내려가는 상황을 허용하지 않았다.
- broker는 기존 suite의 로컬 fixture를 사용했다. 운영
.mam.env를 export/출력하지 않았고 실제 사용자 홈·서버·모니터를 변경하지 않았다. agent-home 가드 오탐도 없었다. - 독립 경로 탐침:
/tmp/efb52908-review/probe.py, 로그/tmp/efb52908-review/probe.log. 검증 cwd에서 같은env -u ... <Python>으로 실행 가능하다. 5개 경로 × 2개 해석기의 base/head 관측과 3개 링크 사례를 기록했다. 위 기존 .bin 차이를 제외한 기대 조건 assertion은 모두 통과했다. 실제 herdr를 실행하지 않았다.
소스 변경 없이 지정 범위의 검토를 마쳤으며 재계획이 필요한 결함은 발견하지 않았다.
[VERDICT: PASS]