Codex created this PR from the following prompt: > upgrade this entire repo to Rust 1.89. Note that this requires updating codex-rs/rust-toolchain.toml as well as the workflows in .github/. Make sure that things are "clippy clean" as this change will likely uncover new Clippy errors. `just fmt` and `cargo clippy --tests` are sufficient to check for correctness Note this modifies a lot of lines because it folds nested `if` statements using `&&`. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/2465). * #2467 * __->__ #2465
104 lines
3.3 KiB
Rust
104 lines
3.3 KiB
Rust
use multimap::MultiMap;
|
|
use regex_lite::Error as RegexError;
|
|
use regex_lite::Regex;
|
|
|
|
use crate::ExecCall;
|
|
use crate::Forbidden;
|
|
use crate::MatchedExec;
|
|
use crate::NegativeExamplePassedCheck;
|
|
use crate::ProgramSpec;
|
|
use crate::error::Error;
|
|
use crate::error::Result;
|
|
use crate::policy_parser::ForbiddenProgramRegex;
|
|
use crate::program::PositiveExampleFailedCheck;
|
|
|
|
pub struct Policy {
|
|
programs: MultiMap<String, ProgramSpec>,
|
|
forbidden_program_regexes: Vec<ForbiddenProgramRegex>,
|
|
forbidden_substrings_pattern: Option<Regex>,
|
|
}
|
|
|
|
impl Policy {
|
|
pub fn new(
|
|
programs: MultiMap<String, ProgramSpec>,
|
|
forbidden_program_regexes: Vec<ForbiddenProgramRegex>,
|
|
forbidden_substrings: Vec<String>,
|
|
) -> std::result::Result<Self, RegexError> {
|
|
let forbidden_substrings_pattern = if forbidden_substrings.is_empty() {
|
|
None
|
|
} else {
|
|
let escaped_substrings = forbidden_substrings
|
|
.iter()
|
|
.map(|s| regex_lite::escape(s))
|
|
.collect::<Vec<_>>()
|
|
.join("|");
|
|
Some(Regex::new(&format!("({escaped_substrings})"))?)
|
|
};
|
|
Ok(Self {
|
|
programs,
|
|
forbidden_program_regexes,
|
|
forbidden_substrings_pattern,
|
|
})
|
|
}
|
|
|
|
pub fn check(&self, exec_call: &ExecCall) -> Result<MatchedExec> {
|
|
let ExecCall { program, args } = &exec_call;
|
|
for ForbiddenProgramRegex { regex, reason } in &self.forbidden_program_regexes {
|
|
if regex.is_match(program) {
|
|
return Ok(MatchedExec::Forbidden {
|
|
cause: Forbidden::Program {
|
|
program: program.clone(),
|
|
exec_call: exec_call.clone(),
|
|
},
|
|
reason: reason.clone(),
|
|
});
|
|
}
|
|
}
|
|
|
|
for arg in args {
|
|
if let Some(regex) = &self.forbidden_substrings_pattern
|
|
&& regex.is_match(arg)
|
|
{
|
|
return Ok(MatchedExec::Forbidden {
|
|
cause: Forbidden::Arg {
|
|
arg: arg.clone(),
|
|
exec_call: exec_call.clone(),
|
|
},
|
|
reason: format!("arg `{arg}` contains forbidden substring"),
|
|
});
|
|
}
|
|
}
|
|
|
|
let mut last_err = Err(Error::NoSpecForProgram {
|
|
program: program.clone(),
|
|
});
|
|
if let Some(spec_list) = self.programs.get_vec(program) {
|
|
for spec in spec_list {
|
|
match spec.check(exec_call) {
|
|
Ok(matched_exec) => return Ok(matched_exec),
|
|
Err(err) => {
|
|
last_err = Err(err);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
last_err
|
|
}
|
|
|
|
pub fn check_each_good_list_individually(&self) -> Vec<PositiveExampleFailedCheck> {
|
|
let mut violations = Vec::new();
|
|
for (_program, spec) in self.programs.flat_iter() {
|
|
violations.extend(spec.verify_should_match_list());
|
|
}
|
|
violations
|
|
}
|
|
|
|
pub fn check_each_bad_list_individually(&self) -> Vec<NegativeExamplePassedCheck> {
|
|
let mut violations = Vec::new();
|
|
for (_program, spec) in self.programs.flat_iter() {
|
|
violations.extend(spec.verify_should_not_match_list());
|
|
}
|
|
violations
|
|
}
|
|
}
|