OpenAI Codex · Code Mode

execpolicy: 정책 파일에 테스트 케이스를 심어두기

화이트리스트를 잘못 쓰면, 보통 프로덕션에 가서야 압니다. Codex는 정례와 반례를 규칙 자체에 넣고, 로드할 때 바로 한 번 돌립니다. 규칙과 예제가 싸우면, 그 정책은 세션에 들어가지 않아요.

강의 목표이 레슨을 마치면 두 가지를 말할 수 있어요. 명령이 정책에 들어간 뒤 어떻게 쪼개지고, 접두로 어떻게 맞으며, 마지막에 allow·prompt·forbidden 중 무엇으로 판정되는지. 그리고 규칙 옆의 정례와 반례가 왜 로드 시점에 오탐을 못 박을 수 있는지.
먼저 해보기 · 명령 하나가 정책을 지나갑니다
같은 정책, 명령 네 개, 쓰는 법 세 가지
명령
안전한 것, 위험한 플래그가 있는 것, 위험해 보이는 것, 포장으로 위장한 것. 하나를 고른 뒤 재생하세요.
정책
1 분해대기
2 로드 검사대기
3 접두 매칭대기
4 가장 엄한 판정대기
이 단계에서 보는 argv
아직 토큰이 없어요.
정책이 들고 있는 테스트
정례는 반드시 맞아야 함안 돌림
git reset --hard
반례는 반드시 놓아야 함안 돌림
git reset --keep
재생을 눌러, 이 명령이 어떻게 쪼개지고, 어느 규칙에 맞으며, 어떤 등급이 되는지 보세요.
논리 궤적 · 애니메이션 한 걸음이 소스의 어느 구간에 대응하는지
  1. 정책 텍스트를 읽고 parse를 시작합니다parser.rs L57
  2. Starlark가 prefix_rule을 평가하고, decision이 없으면 기본은 allowparser.rs L348
  3. 규칙과 예제를 검사 대기 큐에 먼저 겁니다parser.rs L405
  4. 반례를 먼저 돌리고, 맞으면 ExampleDidMatchparser.rs L145
  5. 이어서 정례를 돌리고, 안 맞으면 ExampleDidNotMatchparser.rs L147
  6. 포장 명령은 안쪽 argv로 먼저 쪼갭니다exec_policy.rs L831
  7. 첫 token으로 규칙 버킷을 정확히 꺼냅니다policy.rs L334
  8. 여러 규칙이나 조합 명령은 가장 엄한 쪽을 고릅니다policy.rs L403
  9. 판정은 Skip, NeedsApproval, Forbidden으로 매핑됩니다exec_policy.rs L375
재생을 눌러, 명령 하나가 정책을 어떻게 지나가는지, 그리고 딸려 있는 정례와 반례가 판정을 어떻게 못 박는지 보세요.
로드 시점에 먼저 무너집니다접두가 너무 짧거나 반례를 잘못 쓰면, 네 명령 모두 allow나 forbidden에 들어갈 기회가 없어요. 정책을 넘기기도 전에, 잘못된 예제가 로드를 끊습니다.
--keep이 살아남는 이유올바른 규칙은 pattern을 세 token으로 씁니다. 세 번째 token이 --keep과 안 맞으니 금지가 켜지지 않아요. 휴리스틱이 놓아준 게 아니라, 저자가 반례로 경계를 못 박은 겁니다.
포장으로는 막지 못합니다bash -lc로 한 겹 감싸도, 쪼개지면 안쪽을 다시 판정합니다. 쪼개지지 않을 때만 통째로 후퇴해요. 데모의 이 포장은 쪼개지므로 여전히 forbidden입니다.
수업용 스케치: 무대는 예시 정책에서 git reset --hard를 금지하고 ls를 허용하는 두 줄만 보여 줍니다. 실제 셸은 실행하지 않아요. 논리 궤적 오른쪽 행 번호는 openai/codex 저장소 commit 4f39251a01에 대응합니다.
아이디어 1 · 규칙과 예제를 한곳에 둡니다
어떤 문제를 푸는가

팀에 금지 한 줄을 쓰면서 pattern을 git 더하기 reset으로 적어요. 본뜻은 --hard를 막는 것이었죠. 일주일 뒤 누군가 --keep도 막혔다고 합니다. 접두가 짧아지면, 뒤에 무엇이 붙어도 같은 규칙에 맞아요.

또 일주일 뒤, 모델이 bash -lc로 한 겹 감쌉니다. 금지는 글자 그대로의 argv로 bash를 맞추고, 첫 token이 안 맞으면 명령은 휴리스틱 통로로 들어갑니다.

화이트리스트 한 줄은 늘 두 가지를 겁니다. 하나는 pattern이 막고 싶은 것을 정확히 덮는지. 다른 하나는 놓아주고 싶은 것을 오탐하지 않는지. 둘 다 보통 프로덕션에 가서야 알아요. 다음에 pattern을 고치는 사람도, 저자가 처음에 어떤 명령을 오탐할까 봐 두려워했는지를 볼 수 없습니다.

아이디어는 무엇인가

Codex는 정례와 반례를 규칙 자체에 넣습니다. match는 이 규칙이 반드시 맞춰야 하는 명령이고, not_match는 반드시 놓아야 하는 명령이에요. prefix_rule은 그 자리에서 예제를 돌리지 않고, 규칙과 예제를 검사 대기 큐에 먼저 넣습니다. Starlark 전체가 평가된 뒤에야 parse가 한꺼번에 검사해요.

순서는 고정입니다. 반례를 먼저, 그다음 정례. 반례가 잘못 맞으면 ExampleDidMatch. 정례가 하나도 안 맞으면 ExampleDidNotMatch. 둘 다 parse를 실패로 돌리고, Policybuild되어 나가지 않아요.출처: codex-rs/execpolicy/src/parser.rs 57–78행, 그리고 133–151행

crate README는 한 줄로 적습니다. 로드 시점 검사용 예시 호출이고, 유닛 테스트처럼 쓰면 됩니다. 문자열과 token 배열 두 표기 모두 파서에 들어가면 token 목록이 되고, 문자열은 shlex로 쪼갭니다. 검사 때 휴리스틱 콜백은 비우므로, 정례는 진짜 접두 규칙에 맞아야 하고 휴리스틱으로 숫자를 맞출 수 없어요.

Starlark 평가 규칙과 예제를 겁니다 반례를 먼저 하나도 맞으면 안 됨 이어서 정례 적어도 하나는 맞아야 함 Policy를 넘김 로드 실패 예제가 안 맞으면, 정책을 넘기기도 전에 멈춥니다 오류에는 prefix_rule 호출 위치의 행·열이 붙습니다
수업용 타임라인: 평가는 모으기만 하고, 검사는 build 전에 일어납니다.
왜 오래가는가

화이트리스트의 전형적인 실패는, 저자가 pattern이 이 뜻이라고 믿는 겁니다. 그 믿음을 예제로 쓰면 기계가 반대할 수 있어요. Starlark에 묶이지 않아서, JSON이나 YAML로 옮겨도 그대로 성립합니다.

규칙과 예제를 한곳에 두면, 정책 파일이 사용자 디렉터리로 복사되거나 overlay로 배포될 때 예제도 따라갑니다. 로더에는 규칙만 읽고 예제는 안 돌리는 분기가 없어요. 예제를 빼먹으면 테스트를 빼먹은 셈입니다. 로더가 대신 예제를 지어 주지 않고, 쓰면 강제 실행합니다.

아이디어 2 · 접두 매칭, 여러 규칙은 가장 엄한 쪽
어떤 문제를 푸는가

정규식은 git reset 뒤에 아무 인자나 붙게 쓸 수도 있고, 저자 본인도 못 읽는 예외도 쓸 수 있어요. 겹친 규칙에서 가장 넓은 쪽을 고르면, 사용자 층의 느슨한 allow 한 줄이 시스템 층의 forbidden을 덮을 수 있습니다.

아이디어는 무엇인가

규칙 본체는 접두 한 토막입니다. 매칭은 정확한 문자열 동등이고, glob도 정규식도 없어요. git reset --hard는 뒤에 origin/main이 더 붙어도 먹습니다. 남은 token은 비교에 안 들어가니까요. 가운데 --config를 끼운 쓰기는 못 먹어요. 두 번째 token이 안 맞습니다.출처: codex-rs/execpolicy/src/rule.rs 46–59행

규칙은 첫 token으로 버킷에 넣습니다. 찾을 때는 argv 0번을 먼저 정확히 꺼냅니다. 없으면 절대 경로를 basename으로 접을 수 있어요. 여러 줄이 맞으면 decisionmax를 합니다. DecisionOrd를 파생하고, variant를 쓴 순서가 곧 심각도입니다. Allow는 Prompt보다 작고, Prompt는 Forbidden보다 작아요.

조합 명령은 먼저 토막을 나누고 펼친 뒤, max를 한 번 더 합니다. 한 토막 git status가 Prompt이고 한 토막 git commit이 Forbidden이면, 파이프 전체는 여전히 Forbidden입니다.출처: codex-rs/execpolicy/src/policy.rs 265–287행, 그리고 402–411행

git 접두 decision = prompt git commit 접두 decision = forbidden git commit -m hi 둘 다 matchedRules에 들어갑니다 max = Forbidden Allow < Prompt < Forbidden 겹치면 더 엄해질 수만 있습니다. 순서는 enum variant에 쓰여 있고, 다른 우선순위 표는 없어요
수업용 대조: 같은 명령이 규칙 두 줄에 맞아도, 밖에서는 더 엄한 쪽만 봅니다.
왜 오래가는가

겹치면 더 엄해질 수만 있고, 느슨해질 수는 없어요. 그 순서는 enum variant에 있고, 런타임에 잘못 쓸 두 번째 우선순위 표는 없습니다. 다른 언어로 다시 써도, 문자열 셋을 순서 있는 enum으로 만들고 한 번 max로 접으면 됩니다.

접두는 의도를 token 수열로 떨어뜨리게 합니다. 대가는 가운데 끼운 인자가 규칙을 죽인다는 점이에요. 저자는 접두를 더 짧게 쓰거나 한 줄을 더 써야 합니다. 정례와 반례가 그 대가를 받아 줍니다. 짧게 쓰면 반례가 로드 시점에 먼저 무너져요.

아이디어 3 · 포장을 먼저 풀고, 안 풀리면 통째로 후퇴
어떤 문제를 푸는가

금지는 git reset --hard로 쓰여 있어요. 모델은 bash -lc로 한 겹 감쌉니다. 글자 그대로의 argv로 맞추면 첫 token은 bash이고, 금지는 켜지지 않아요.

아이디어는 무엇인가

판정 전에 먼저 parse_shell_lc_plain_commands를 탑니다. 스크립트는 순수 단어 명령에 &&, ||, 세미콜론, 파이프만 허용하고, 리다이렉트·치환·괄호·제어 흐름은 거절합니다. 통과하면 명령 노드를 argv 토막으로 자릅니다. bash -lcgit reset --hard를 감싸면 안쪽 세 token으로 쪼개진 뒤, 그걸로 접두를 맞춥니다.출처: codex-rs/core/src/exec_policy.rs 831–858행

쪼개지지 않으면 전체 argv를 명령 하나로 보고, 휴리스틱과 뒤의 샌드박스에 넘깁니다. 인자 안의 빈 따옴표는 아직 복원할 수 있어요. 명령 이름 안의 빈 따옴표는 word-only 파싱이 실패하고, 접두 규칙은 git을 보지 못하며, 이 명령은 휴리스틱으로 떨어집니다.

삼키지 못한 스크립트를, 이미 이해한 척하지 마세요.
왜 오래가는가

파서가 삼키지 못한 것을 인정하면, 스크립트를 이미 이해한 척하지 않습니다. 그게 fail closed의 일반적인 모양이에요. 파싱은 성공했는데 위험한 토막을 빠뜨리는 일을 막습니다. 분해가 실패한 뒤에도 휴리스틱과 샌드박스는 남아 있어요.

가로 비교 · 같은 문제에 대한 다른 답

DeepSeek Harness: 노브 두 개와 드롭다운 하나

DSH는 명령 단위 pattern을 쓰지 않아요. 권한 프리셋이 샌드박스 모드와 승인 정책을 한 묶음으로 묶습니다. 기본 표는 두 줄뿐입니다. workspace-writeask, danger-full-accessnever. 승인 정책 자체도 asknever뿐입니다.

노브는 이해하기 쉬워요. 프리셋만으로는 git reset --hard만 금지하고 나머지 git은 그대로 둘 수 없습니다. 그런 예외는 샌드박스가 거절한 뒤의 승급 승인으로 가거나, 예약 이름 custom으로 보이는 사용자 노브 조합으로 갑니다. 드롭다운은 일상 전환을 덮지만, 이름을 찍어 금지하는 롱테일은 덮지 못해요.

양쪽 모두 소스 대조 완료 · 2026-08-22 · DSH · 승인과 권한

Claude Code: 도구 이름에 선택 내용을 붙인 allowlist

규칙 문자열은 Bash, 또는 Bash(npm install), 또는 Bash(git *)처럼 생겼어요. 파서는 괄호로 도구 이름과 내용을 가릅니다. 셸 규칙은 다시 정확·접두·와일드카드 셋으로 나뉩니다.

규칙 필드로 match, not_match, example를 찾아도, 로드 시점 정례·반례 검사는 없습니다. git *가 allow에 들어가면 git reset --hard도 그 와일드카드에 먹히고, 더 구체적인 deny를 따로 써야 해요. Codex는 더 짧은 정확 접두와 반례로 예외를 로드 시점에 못 박습니다. Claude Code는 예외를 규칙 겹침 순서와 런타임 확인에 남겨 둬요.

양쪽 모두 소스 대조 완료 · 2026-08-22
수업 실습
01

접두가 짧을 때, 로드일까요 판정일까요

git reset --hard를 금지하는 pattern을 git 더하기 reset으로 짧게 쓰고, not_match는 그대로 --keep으로 둡니다. 로드 때 ExampleDidMatch일까요 ExampleDidNotMatch일까요. 명령은 판정에 들어갈 기회가 있을까요.

한 단계 더: 같은 나쁜 규칙 아래에서 ls -l이 먼저 allow가 될까요. 데모에서 정책을 “접두가 너무 짧음”으로 바꾼 뒤 다시 재생해, 당신의 추리와 맞춰 보세요.

Takeaway:규칙과 예제를 한곳에 두고, 로드할 때 바로 돌립니다. 정례는 맞아야 하고 반례는 놓아야 하며, 싸우면 로드를 거절합니다. 접두는 정확히 비교하고, 여러 규칙은 가장 엄한 쪽을 고릅니다. 포장을 먼저 풀고, 안 풀리면 통째로 후퇴해요.