syncable_cli/analyzer/hadolint/rules/
dl4006.rs1use crate::analyzer::hadolint::parser::instruction::Instruction;
7use crate::analyzer::hadolint::rules::{SimpleRule, simple_rule};
8use crate::analyzer::hadolint::shell::ParsedShell;
9use crate::analyzer::hadolint::types::Severity;
10
11pub fn rule() -> SimpleRule<impl Fn(&Instruction, Option<&ParsedShell>) -> bool + Send + Sync> {
12 simple_rule(
13 "DL4006",
14 Severity::Warning,
15 "Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check",
16 |instr, shell| {
17 match instr {
18 Instruction::Run(_) => {
19 if let Some(shell) = shell {
20 !shell.has_pipes
24 } else {
25 true
26 }
27 }
28 _ => true,
29 }
30 },
31 )
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37 use crate::analyzer::hadolint::parser::instruction::RunArgs;
38 use crate::analyzer::hadolint::rules::{Rule, RuleState};
39
40 #[test]
41 fn test_no_pipe() {
42 let rule = rule();
43 let mut state = RuleState::new();
44
45 let instr = Instruction::Run(RunArgs::shell("apt-get update"));
46 let shell = ParsedShell::parse("apt-get update");
47 rule.check(&mut state, 1, &instr, Some(&shell));
48 assert!(state.failures.is_empty());
49 }
50
51 #[test]
52 fn test_with_pipe() {
53 let rule = rule();
54 let mut state = RuleState::new();
55
56 let instr = Instruction::Run(RunArgs::shell("cat file | grep pattern"));
57 let shell = ParsedShell::parse("cat file | grep pattern");
58 rule.check(&mut state, 1, &instr, Some(&shell));
59 assert_eq!(state.failures.len(), 1);
60 assert_eq!(state.failures[0].code.as_str(), "DL4006");
61 }
62}