From ca9e61497d231c51bd637053ab44550f11bac45a Mon Sep 17 00:00:00 2001 From: kevin zhao Date: Mon, 10 Nov 2025 16:14:38 -0800 Subject: [PATCH] README --- codex-rs/execpolicy2/README.md | 57 ++++++++++++++++++++++++++++++++ codex-rs/execpolicy2/src/main.rs | 13 ++------ 2 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 codex-rs/execpolicy2/README.md diff --git a/codex-rs/execpolicy2/README.md b/codex-rs/execpolicy2/README.md new file mode 100644 index 0000000000..859854acd7 --- /dev/null +++ b/codex-rs/execpolicy2/README.md @@ -0,0 +1,57 @@ +# codex-execpolicy2 + +## Overview +- Policy engine and CLI built around `prefix_rule(pattern=[...], decision?, match?, not_match?, id?)`. +- Tokens are matched in order; any `pattern` element may be a list to denote alternatives. `decision` defaults to `allow`; valid values: `allow`, `prompt`, `forbidden`. +- `match` / `not_match` supply example invocations that are validated at load time (think of them as unit tests). `id` is optional; auto-generated if omitted. +- The CLI always prints the JSON serialization of the evaluation result (whether a match or not). + +## Policy shapes +- Prefix rules use Starlark syntax: +```starlark +prefix_rule( + id = "rule_id", # optional; autogenerated if omitted + pattern = ["cmd", ["alt1", "alt2"]], # ordered tokens; list entries denote alternatives + decision = "prompt", # allow | prompt | forbidden; defaults to allow + match = [["cmd", "alt1"]], # examples that must match this rule + not_match = [["cmd", "oops"]], # examples that must not match this rule +) +``` + +## Response shapes +- Match: +```json +{ + "Match": { + "decision": "allow|prompt|forbidden", + "matched_rules": [ + { + "rule_id": "", + "matched_prefix": ["", "..."], + "decision": "allow|prompt|forbidden" + } + ] + } +} +``` + +- No match: +```json +"NoMatch" +``` + +- `matched_rules` lists every rule whose prefix matched the command; `matched_prefix` is the exact prefix that matched. +- The effective `decision` is the strictest severity across all matches (`forbidden` > `prompt` > `allow`). + +## CLI +- Check a command against a policy (default bundled policy shown): +```bash +cargo run -p codex-execpolicy2 -- check git status +``` +- Use a specific policy file instead of the default: +```bash +cargo run -p codex-execpolicy2 -- --policy path/to/policy.star check git status +``` +- Example outcomes: + - Match: `{"Match": { ... "decision": "allow" ... }}` + - No match: `"NoMatch"` diff --git a/codex-rs/execpolicy2/src/main.rs b/codex-rs/execpolicy2/src/main.rs index 15383af492..5238057f3e 100644 --- a/codex-rs/execpolicy2/src/main.rs +++ b/codex-rs/execpolicy2/src/main.rs @@ -4,7 +4,6 @@ use std::path::Path; use anyhow::Context; use anyhow::Result; use anyhow::bail; -use codex_execpolicy2::Evaluation; use codex_execpolicy2::PolicyParser; use codex_execpolicy2::load_default_policy; @@ -49,15 +48,9 @@ fn cmd_check(policy_path: Option, args: Vec) -> Result<()> { } let policy = load_policy(policy_path)?; - match policy.evaluate(&args) { - eval @ Evaluation::Match { .. } => { - let json = serde_json::to_string_pretty(&eval)?; - println!("{json}"); - } - Evaluation::NoMatch => { - println!("no match"); - } - }; + let eval = policy.evaluate(&args); + let json = serde_json::to_string_pretty(&eval)?; + println!("{json}"); Ok(()) }