syncable_cli/analyzer/hadolint/rules/
dl3001.rs

1//! DL3001: Don't use invalid commands in RUN
2//!
3//! Commands like ssh, vim, shutdown, service, ps, free, top, kill, and mount
4//! are not appropriate for Dockerfile RUN instructions.
5
6use crate::analyzer::hadolint::parser::instruction::Instruction;
7use crate::analyzer::hadolint::rules::{simple_rule, SimpleRule};
8use crate::analyzer::hadolint::shell::ParsedShell;
9use crate::analyzer::hadolint::types::Severity;
10
11/// Invalid commands that shouldn't be used in Dockerfiles.
12const INVALID_COMMANDS: &[&str] = &[
13    "ssh",
14    "vim",
15    "shutdown",
16    "service",
17    "ps",
18    "free",
19    "top",
20    "kill",
21    "mount",
22    "ifconfig",
23    "nano",
24];
25
26pub fn rule() -> SimpleRule<impl Fn(&Instruction, Option<&ParsedShell>) -> bool + Send + Sync> {
27    simple_rule(
28        "DL3001",
29        Severity::Info,
30        "For some bash commands it makes no sense running them in a Docker container like ssh, vim, shutdown, service, ps, free, top, kill, mount, ifconfig",
31        |instr, shell| {
32            match instr {
33                Instruction::Run(_) => {
34                    if let Some(shell) = shell {
35                        !shell.any_command(|cmd| INVALID_COMMANDS.contains(&cmd.name.as_str()))
36                    } else {
37                        true
38                    }
39                }
40                _ => true,
41            }
42        },
43    )
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49    use crate::analyzer::hadolint::parser::instruction::RunArgs;
50    use crate::analyzer::hadolint::rules::{Rule, RuleState};
51
52    #[test]
53    fn test_valid_command() {
54        let rule = rule();
55        let mut state = RuleState::new();
56
57        let instr = Instruction::Run(RunArgs::shell("apt-get update"));
58        let shell = ParsedShell::parse("apt-get update");
59        rule.check(&mut state, 1, &instr, Some(&shell));
60        assert!(state.failures.is_empty());
61    }
62
63    #[test]
64    fn test_invalid_ssh() {
65        let rule = rule();
66        let mut state = RuleState::new();
67
68        let instr = Instruction::Run(RunArgs::shell("ssh user@host"));
69        let shell = ParsedShell::parse("ssh user@host");
70        rule.check(&mut state, 1, &instr, Some(&shell));
71        assert_eq!(state.failures.len(), 1);
72        assert_eq!(state.failures[0].code.as_str(), "DL3001");
73    }
74
75    #[test]
76    fn test_invalid_vim() {
77        let rule = rule();
78        let mut state = RuleState::new();
79
80        let instr = Instruction::Run(RunArgs::shell("vim /etc/config"));
81        let shell = ParsedShell::parse("vim /etc/config");
82        rule.check(&mut state, 1, &instr, Some(&shell));
83        assert_eq!(state.failures.len(), 1);
84    }
85}