syncable_cli/analyzer/hadolint/rules/
dl4005.rs1use crate::analyzer::hadolint::parser::instruction::Instruction;
6use crate::analyzer::hadolint::rules::{SimpleRule, simple_rule};
7use crate::analyzer::hadolint::shell::ParsedShell;
8use crate::analyzer::hadolint::types::Severity;
9
10pub fn rule() -> SimpleRule<impl Fn(&Instruction, Option<&ParsedShell>) -> bool + Send + Sync> {
11 simple_rule(
12 "DL4005",
13 Severity::Warning,
14 "Use `SHELL` to change the default shell.",
15 |instr, _shell| {
16 match instr {
17 Instruction::Run(args) => {
18 let cmd_text = match &args.arguments {
19 crate::analyzer::hadolint::parser::instruction::Arguments::Text(t) => {
20 t.as_str()
21 }
22 crate::analyzer::hadolint::parser::instruction::Arguments::List(l) => {
23 if l.is_empty() {
24 return true;
25 }
26 l.first().map(|s| s.as_str()).unwrap_or("")
27 }
28 };
29
30 !cmd_text.contains("ln -s") || !cmd_text.contains("/bin/sh")
32 }
33 _ => true,
34 }
35 },
36 )
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42 use crate::analyzer::hadolint::config::HadolintConfig;
43 use crate::analyzer::hadolint::lint::{LintResult, lint};
44
45 fn lint_dockerfile(content: &str) -> LintResult {
46 lint(content, &HadolintConfig::default())
47 }
48
49 #[test]
50 fn test_shell_instruction() {
51 let result = lint_dockerfile("FROM ubuntu:20.04\nSHELL [\"/bin/bash\", \"-c\"]");
52 assert!(!result.failures.iter().any(|f| f.code.as_str() == "DL4005"));
53 }
54
55 #[test]
56 fn test_ln_s_shell() {
57 let result = lint_dockerfile("FROM ubuntu:20.04\nRUN ln -s /bin/bash /bin/sh");
58 assert!(result.failures.iter().any(|f| f.code.as_str() == "DL4005"));
59 }
60
61 #[test]
62 fn test_normal_run() {
63 let result = lint_dockerfile("FROM ubuntu:20.04\nRUN echo hello");
64 assert!(!result.failures.iter().any(|f| f.code.as_str() == "DL4005"));
65 }
66}