Skip to content

Commit

A cancelled step's cleanup trap runs even when the runner was started with SIGINT ignored, and the backup test tags with its own identity

A shell cannot trap a signal it inherits as ignored, and a runner started in the background passes SIGINT on ignored, so a cancelled step went straight to the kill after the grace period. Each step now starts with SIGINT, SIGTERM and SIGQUIT at their defaults. CI on g1t's own runners caught both: the cancellation test, and a backup test whose annotated tag needed a committer identity the machine does not have.

syntaqxcommitted Parenta29e867Browse files
4 files+23−20/4 viewed
+1−0
11051105 "g1t-actions",
11061106 "g1t-scan",
11071107 "hex",
1108+ "libc",
11081109 "serde",
11091110 "serde_json",
11101111 "serde_yaml",
+4−0
2525 # native-certs: a guarded sandbox re-signs HTTPS with a certificate the
2626 # runner adds to the system store (guard.rs), which webpki-roots never sees.
2727 ureq = { version = "2", features = ["json", "native-certs"] }
28+
29+[target.'cfg(unix)'.dependencies]
30+# A step's signals back to their defaults before it runs (actions/process.rs).
31+libc = "0.2"
+17−1
158158 command.stdin(Stdio::null()).stdout(Stdio::piped()).stderr(Stdio::piped());
159159 // A group of its own, so a cancellation reaches what the step started.
160160 #[cfg(unix)]
161− std::os::unix::process::CommandExt::process_group(&mut command, 0);
161+ {
162+ use std::os::unix::process::CommandExt;
163+ command.process_group(0);
164+ // A shell cannot trap a signal it was started with ignored, and a
165+ // runner started in the background (as a service, or under `&`)
166+ // passes SIGINT on ignored. Back to the defaults, so a cancelled
167+ // step hears SIGINT and its own trap runs.
168+ // SAFETY: only signal(), which is async-signal-safe, between fork and exec.
169+ unsafe {
170+ command.pre_exec(|| {
171+ for signal in [libc::SIGINT, libc::SIGTERM, libc::SIGQUIT] {
172+ libc::signal(signal, libc::SIG_DFL);
173+ }
174+ Ok(())
175+ });
176+ }
177+ }
162178 let mut child = command.spawn()?;
163179 let (sender, lines) = mpsc::channel::<String>();
164180 let mut readers = Vec::new();
+1−1
387387 std::fs::create_dir_all(&origin).unwrap();
388388 git_in(&origin, &["init", "--quiet", "--initial-branch=main"], None).unwrap();
389389 commit(&origin, "a.txt", "one");
390− git_in(&origin, &["tag", "-a", "v1", "-m", "v1"], None).unwrap();
390+ git_in(&origin, &["-c", "user.name=t", "-c", "user.email=t@example.com", "-c", "tag.gpgsign=false", "tag", "-a", "v1", "-m", "v1"], None).unwrap();
391391 let mirror = root.join("mirror.git");
392392
393393 // Full.