Skip to content

fix(crush): bridge 레인에 owner-operator 권한 설정을 준다 (#940 정정) - #944

Merged
jinon86 merged 3 commits into
mainfrom
fix/crush-bridge-lane-permissions
Aug 4, 2026
Merged

fix(crush): bridge 레인에 owner-operator 권한 설정을 준다 (#940 정정)#944
jinon86 merged 3 commits into
mainfrom
fix/crush-bridge-lane-permissions

Conversation

@jinon86

@jinon86 jinon86 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

등애를 crush로 전환한 뒤 owner 봇이 이렇게 답했습니다:

Crush 환경에서 bash 도구가 비활성화되어 있어 직접 셸 명령을 실행할 수 없습니다

봇 말이 맞고, 원인은 #940입니다.

무엇이 잘못됐나

#940에서 bridge가 crush 설정을 못 읽는 문제를 고치면서 레포의 crush/crushrc.readonly를 물렸습니다. 그 파일은 이름 그대로 agent-cron 비대화형 러너용입니다:

permissions deny bash edit write download question

정작 그 레인의 실제 정책은 반대입니다 (dungae 실측):

execution_profile=owner-operator  bash_policy=auto-approve  host_scope=true

같은 정책에서 **Codex 레인은 approval=never + sandbox=dangerFullAccess**를 받습니다 (bot_access.py_codex_approval_policy / _codex_sandbox_policy). crush만 읽기 전용으로 두면 프로바이더를 바꿨을 때 능력이 줄어듭니다.

#938 이슈에서 제가 이걸 *"bridge 레인에만 읽기전용 경계가 없다"*고 보안 구멍으로 규정했는데, 반대였습니다. 그 레인은 의도적으로 넓은 레인입니다.

수정

crush/crushrc.bridge를 추가하고 crush_runtime의 기본값을 그리로 옮깁니다.

안전장치는 그대로입니다

crush의 permission 요청은 여전히 _decide_permission → bridge approval handler로 가고, 운영자의 bash_policy가 판단합니다:

bash_policy 결과
auto-approve ApprovalDecision.ALLOW (안 물음)
approve-each 매번 Telegram 확인
그 외 DENY

이 파일은 "무엇을 제안할 수 있는가"만 정하고, 실행 여부는 bridge 정책이 정합니다. 오히려 Codex보다 통제 지점이 하나 더 있습니다 — Codex는 never면 아예 안 묻지만, crush는 approve-each로 바꾸면 매번 확인이 됩니다.

실측

설정 도구 수 bash/edit/write question
crushrc.bridge 26 있음 없음
crushrc.readonly 22 없음 없음

permissions는 나중 줄이 이기지 않습니다. deny 뒤에 allow를 붙여도 뒤집히지 않아(실측) 파일 분리가 필요했습니다. 한 파일에 override를 얹는 방식은 불가능합니다.

테스트

tests/test_crush_model_pin.py   25 passed
전체 bridge 스위트               2238 passed, 1 skipped

4건 추가:

  • bridge는 셸 도구를 막지 않고 question은 막는다
  • readonly는 여전히 전부 막는다 (기존 계약 유지)
  • 두 파일의 provider 정의가 동일하다 — 드리프트 가드. 갈리면 한 레인만 도달 못 하는 모델이 생기는데, 에러 없이 다른 답이 나옵니다
  • 런타임 기본값이 crushrc.bridge

관련

🤖 Generated with Claude Code

#940 에서 bridge 가 crush 설정을 못 읽는 문제를 고치면서 레포의
crush/crushrc.readonly 를 물렸다. 그 파일은 이름 그대로 **agent-cron
비대화형 러너용**이고 bash/edit/write 를 막는다.

그래서 owner 봇이 셸을 못 쓰게 됐다. dungae 실사용:

  "Crush 환경에서 bash 도구가 비활성화되어 있어 직접 셸 명령을 실행할 수
   없습니다"

정작 그 레인의 실제 정책은 반대다(dungae 실측):

  execution_profile=owner-operator  bash_policy=auto-approve  host_scope=true

같은 정책에서 Codex 레인은 approval=never + sandbox=dangerFullAccess 를
받는다(bot_access.py `_codex_approval_policy`/`_codex_sandbox_policy`).
crush 만 읽기 전용으로 두면 프로바이더를 바꿨을 때 능력이 줄어든다.

crushrc.bridge 를 추가하고 crush_runtime 의 기본값을 그리로 옮긴다.
provider/model 정의는 동일하고 permissions 만 다르다 — question 만 막는다
(bridge 에 응답 경로가 없어 모델이 쓰면 턴 전체가 실패한다, #934).

안전장치는 유지된다: crush 의 permission 요청은 여전히 `_decide_permission`
-> bridge approval handler 로 가고 운영자의 bash_policy 가 판단한다
(auto-approve=허용, approve-each=매번 확인, 그 외=거부). 이 파일은 무엇을
제안할 수 있는가를 정할 뿐 실행 여부는 bridge 정책이 정한다.

실측: crushrc.bridge 로 26개 전체 도구 노출(bash/edit/write/download 포함),
question 없음. crushrc.readonly 는 그대로 22개.
※ permissions 는 나중 줄이 이기지 않는다 — deny 뒤에 allow 를 붙여도
   뒤집히지 않아서 파일 분리가 필요했다(실측).

테스트 4건 추가: bridge 는 셸 도구를 막지 않고 question 은 막는다 /
readonly 는 여전히 전부 막는다 / 두 파일의 provider 정의가 동일하다
(드리프트 가드) / 런타임 기본값이 crushrc.bridge 다.
전체 스위트 2238 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jinon86
jinon86 requested a review from seoseo-ai as a code owner August 4, 2026 14:31
앞 커밋은 도구를 열어줬지만 승인 왕복은 남겼다. 실측해 보니 crush 는
도구마다 다르게 굴었다(dungae, 2026-08-04, DENY 핸들러로 확인):

  bash(echo)  crush 가 묻지 않고 실행
  write       crush 가 승인을 요청 -> 거부되니 파일도 안 생기고 출력도
              비었는데 **에러는 없다**(조용한 실패)

그 왕복에는 실패 경로가 하나 더 있다 — `_decide_permission` 은
`turn_ready` 를 5초 기다리고 타임아웃이면 DENY 한다. 부하가 걸리면
승인될 도구가 조용히 거부될 수 있다.

Codex 는 같은 정책에서 approval=never 를 받아 아예 묻지 않는다. crush 도
같은 자리에 두려면 왕복 자체를 없애야 한다.

crushrc 에 박지 않고 bash_policy 에서 파생시킨다 — 파일에 allow 를 적으면
approve-each 로 조여도 crush 가 묻지 않아 가로챌 수 없다. 정책은 한
곳에서만 나와야 한다.

  auto-approve  -> permissions allow <26개 도구> 를 스테이징 시 덧붙임
  approve-each  -> 덧붙이지 않음. crush 가 묻고 bridge 가 매번 확인
  그 외         -> 덧붙이지 않음. crush 가 묻고 bridge 가 거부

question 은 어느 경우에도 허용 목록에 없다.

실측(preapprove_tools=True, DENY 핸들러):
  승인요청 없음 · 파일 생성 True 'WROTE-5521' · OUTPUT 'WROTE-5521'

전체 스위트 2239 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jinon86

jinon86 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

never 동등까지 밀었습니다 (1379b8c)

앞 커밋은 도구를 열어줬지만 승인 왕복은 남아 있었습니다. 실측해 보니 crush는 도구마다 다르게 굴었습니다 — DENY 핸들러를 걸고 확인:

도구 crush 동작
bash (echo) 묻지 않고 실행
write 승인 요청 → 거부되니 파일도 안 생기고 출력도 비었는데 에러는 없음 (조용한 실패)

그 왕복에는 실패 경로가 하나 더 있습니다:

await asyncio.wait_for(active.turn_ready.wait(), timeout=5.0)
except asyncio.TimeoutError:
    return ApprovalDecision.DENY

부하가 걸리면 승인될 도구가 조용히 거부될 수 있습니다.

수정 — crushrc에 박지 않고 bash_policy에서 파생

파일에 allow를 적으면 approve-each로 조여도 crush가 묻지 않아 가로챌 수 없습니다. 정책은 한 곳에서만 나와야 합니다.

bash_policy 스테이징 결과 동작
auto-approve permissions allow <26개> 덧붙임 crush가 안 물음 (Codex never 동등)
approve-each 안 덧붙임 crush가 묻고 bridge가 매번 확인
그 외 안 덧붙임 crush가 묻고 bridge가 거부

question은 어느 경우에도 허용 목록에 없습니다.

이건 Codex의 _codex_approval_policy()bash_policynever/on-request/untrusted로 매핑하는 것과 같은 파생입니다.

실측 (dungae, preapprove_tools=True, DENY 핸들러)

승인요청  : 없음 (DENY 핸들러인데도 안 물음 = never)
errors    : 없음
파일 생성 : True 'WROTE-5521'
OUTPUT    : 'WROTE-5521'

거부하도록 만든 핸들러를 걸어놨는데도 호출조차 안 됐습니다. 진짜 never입니다.

테스트

tests/test_crush_model_pin.py   26 passed
전체 bridge 스위트               2239 passed, 1 skipped

preapprove_tools가 꺼져 있으면 permissions allow가 안 붙고, 켜져 있으면 붙되 question은 여전히 deny인 것까지 검증합니다.

애매한 변수명 l -> line, 플레이스홀더 없는 f-string 제거.
로컬에서 pytest 만 돌리고 ruff 를 안 돌려 CI python-lint 에서 잡혔다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@seoseo-ai seoseo-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved after explicit operator authorization using the local seoseo-ai credential.

@jinon86
jinon86 merged commit 441678c into main Aug 4, 2026
8 checks passed
@jinon86
jinon86 deleted the fix/crush-bridge-lane-permissions branch August 4, 2026 14:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants