Skip to content

Commit

Permalink
Merge pull request #135 from ltratt/exit_code
Browse files Browse the repository at this point in the history
Allow `%x` and `%?` to be used in `errorcmd`.
  • Loading branch information
vext01 authored Mar 28, 2024
2 parents df52c4e + b40e853 commit dd4996d
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 17 deletions.
15 changes: 15 additions & 0 deletions snare.conf.5
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ the repository.
a literal
.Ql % .
.El
.Pp
Note that
.Ql %
may not be followed by any character other than those above.
Expand Down Expand Up @@ -147,10 +148,24 @@ the repository owner.
the repository.
.It Sy %s
the path to the file containing the job's combined stderr / stdout.
.It Sy %x
the exit type:
.Qq status
(i.e. normal exit);
.Qq signal ;
or
.Qq unknown .
.It Sy %?
the exit status / signal number (either an integer or the literal string
.Qq unknown )
that
.Em cmd
failed with.
.It Sy %%
a literal
.Ql % .
.El
.Pp
Note that
.Ql %
may not be followed by any character other than those above.
Expand Down
4 changes: 2 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ impl GitHub {

/// Verify that the `errorcmd` string is valid, returning `Ok())` if so or `Err(String)` if not.
fn verify_errorcmd_str(errorcmd: &str) -> Result<(), String> {
GitHub::verify_str(errorcmd, &['e', 'o', 'r', 'j', 's', '%'])
GitHub::verify_str(errorcmd, &['e', 'o', 'r', 'j', 's', '?', 'x', '%'])
}

fn verify_str(s: &str, modifiers: &[char]) -> Result<(), String> {
Expand Down Expand Up @@ -473,7 +473,7 @@ mod test {
fn test_verify_errorcmd_string() {
assert!(GitHub::verify_errorcmd_str("").is_ok());
assert!(GitHub::verify_errorcmd_str("a").is_ok());
assert!(GitHub::verify_errorcmd_str("%% %e %o %r %j %s %%").is_ok());
assert!(GitHub::verify_errorcmd_str("%% %e %o %r %j %s %x %? %%").is_ok());
assert!(GitHub::verify_errorcmd_str("%%").is_ok());
assert!(GitHub::verify_errorcmd_str("%").is_err());
assert!(GitHub::verify_errorcmd_str("a%").is_err());
Expand Down
50 changes: 43 additions & 7 deletions src/jobrunner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ use std::{
error::Error,
fs::{self, remove_file},
io::{Read, Write},
os::unix::io::{AsRawFd, RawFd},
os::unix::{
io::{AsRawFd, RawFd},
process::ExitStatusExt,
},
path::PathBuf,
process::{self, Child, Command},
sync::Arc,
Expand Down Expand Up @@ -201,14 +204,28 @@ impl JobRunner {
// `Some(_)` and the unwrap thus safe.
let mut exited = false;
let mut exited_success = false;
let mut exit_type = "";
let mut exit_code = String::new();
match self.running[i].as_mut().unwrap().child.try_wait() {
Ok(Some(status)) => {
exited = true;
exited_success = status.success();
if let Some(x) = status.code() {
exit_type = "status";
exit_code = x.to_string();
} else if let Some(x) = status.signal() {
exit_type = "signal";
exit_code = x.to_string();
} else {
exit_type = "unknown";
exit_code = "unknown".to_owned();
}
}
Err(_) => {
exited = true;
exited_success = false;
exit_type = "unknown";
exit_code = "unknown".to_string();
}
Ok(None) => (),
}
Expand All @@ -220,7 +237,9 @@ impl JobRunner {
"errorcmd exited unsuccessfully: {}",
job.rconf.errorcmd.as_ref().unwrap()
));
} else if let Some(errorchild) = self.run_errorcmd(job) {
} else if let Some(errorchild) =
self.run_errorcmd(job, exit_type, &exit_code)
{
let job = &mut self.running[i].as_mut().unwrap();
job.child = errorchild;
job.is_errorcmd = true;
Expand Down Expand Up @@ -489,7 +508,7 @@ impl JobRunner {
}

/// Run the user's errorcmd (if they've specified one).
fn run_errorcmd(&self, job: &Job) -> Option<Child> {
fn run_errorcmd(&self, job: &Job, exit_type: &str, exit_code: &str) -> Option<Child> {
if let Some(raw_errorcmd) = &job.rconf.errorcmd {
let errorcmd = errorcmd_replace(
raw_errorcmd,
Expand All @@ -498,6 +517,8 @@ impl JobRunner {
&job.repo,
job.json_path.as_os_str().to_str().unwrap(),
job.stderrout.path().as_os_str().to_str().unwrap(),
exit_type,
exit_code,
);
match Command::new(&self.shell)
.arg("-c")
Expand Down Expand Up @@ -550,6 +571,8 @@ fn cmd_replace(
/// * `%r` with `repo`
/// * `%j` with `json_path`
/// * `%s` with `stderrout_path`
/// * `%x` with `exit_type` ("status", "signal", or "unknown")
/// * `%?` with `exit_code` (integer or "unknown")
///
/// Note that `raw_cmd` *must* have been validated by config::GitHub::verify_errorcmd_str or
/// undefined behaviour will occur.
Expand All @@ -560,13 +583,17 @@ fn errorcmd_replace(
repo: &str,
json_path: &str,
stderrout_path: &str,
exit_type: &str,
exit_code: &str,
) -> String {
let modifiers = [
('e', event_type),
('o', owner),
('r', repo),
('j', json_path),
('s', stderrout_path),
('x', exit_type),
('?', exit_code),
('%', "%"),
]
.iter()
Expand Down Expand Up @@ -656,11 +683,20 @@ mod test {

#[test]
fn test_errorcmd_replace() {
assert_eq!(errorcmd_replace("", "", "", "", "", ""), "");
assert_eq!(errorcmd_replace("a", "", "", "", "", ""), "a");
assert_eq!(errorcmd_replace("", "", "", "", "", "", "", ""), "");
assert_eq!(errorcmd_replace("a", "", "", "", "", "", "", ""), "a");
assert_eq!(
errorcmd_replace("%% %e %o %r %j %s %%", "ee", "oo", "rr", "jj", "ss"),
"% ee oo rr jj ss %"
errorcmd_replace(
"%% %e %o %r %j %s %x %? %%",
"ee",
"oo",
"rr",
"jj",
"ss",
"ex",
"ec"
),
"% ee oo rr jj ss ex ec %"
);
}
}
14 changes: 9 additions & 5 deletions tests/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,20 @@ fn errorcmd() {
let td = Builder::new()
.tempdir_in(env!("CARGO_TARGET_TMPDIR"))
.unwrap();
let mut tp = td.path().to_owned();
tp.push("t");
let tps = tp.as_path().to_str().unwrap();
let mut tp1 = td.path().to_owned();
tp1.push("t1");
let tp1s = tp1.as_path().to_str().unwrap();
let mut tp2 = td.path().to_owned();
tp2.push("t2");
let tp2s = tp2.as_path().to_str().unwrap();

run_success(
&format!(
r#"listen = "127.0.0.1:0";
github {{
match ".*" {{
cmd = "dd if=/dev/zero bs=1k count=256 status=none && dd if=/dev/zero of=/dev/stderr bs=1k count=256 status=none && exit 1";
errorcmd = "cp %s {tps}";
errorcmd = "echo %x %? > {tp1s} && cp %s {tp2s}";
secret = "secretsecret";
}}
}}"#
Expand Down Expand Up @@ -135,7 +138,8 @@ payload={{
move |response: String| {
if response.starts_with("HTTP/1.1 200 OK") {
sleep(SNARE_PAUSE);
assert_eq!(read_to_string(&tp).unwrap().len(), 2 * 256 * 1024);
assert_eq!(read_to_string(&tp1).unwrap().trim(), "status 1");
assert_eq!(read_to_string(&tp2).unwrap().len(), 2 * 256 * 1024);
Ok(())
} else {
Err(format!("Received HTTP response '{response}'").into())
Expand Down
14 changes: 11 additions & 3 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,17 @@ where
G: Fn(String) -> Result<(), Box<dyn Error>> + RefUnwindSafe + UnwindSafe + 'static,
{
let (mut sn, tp) = snare_command(cfg)?;
match sn.try_wait() {
Ok(None) => (),
_ => todo!(),
for i in 0..5 {
match sn.try_wait() {
Ok(None) => break,
_ => {
if i < 4 {
sleep(Duration::from_secs(1))
} else {
panic!()
}
}
}
}
let tp = Rc::new(tp);

Expand Down

0 comments on commit dd4996d

Please sign in to comment.