syncable_cli/analyzer/hadolint/rules/
dl3059.rs1use crate::analyzer::hadolint::parser::instruction::Instruction;
6use crate::analyzer::hadolint::rules::{CustomRule, RuleState, custom_rule};
7use crate::analyzer::hadolint::shell::ParsedShell;
8use crate::analyzer::hadolint::types::Severity;
9
10pub fn rule()
11-> CustomRule<impl Fn(&mut RuleState, u32, &Instruction, Option<&ParsedShell>) + Send + Sync> {
12 custom_rule(
13 "DL3059",
14 Severity::Info,
15 "Multiple consecutive `RUN` instructions. Consider consolidation.",
16 |state, line, instr, _shell| {
17 match instr {
18 Instruction::From(_) => {
19 state.data.set_int("consecutive_runs", 0);
21 state.data.set_int("last_run_line", 0);
22 }
23 Instruction::Run(_) => {
24 let consecutive = state.data.get_int("consecutive_runs");
25 state.data.set_int("consecutive_runs", consecutive + 1);
26 state.data.set_int("last_run_line", line as i64);
27
28 if consecutive >= 1 {
30 state.add_failure(
31 "DL3059",
32 Severity::Info,
33 "Multiple consecutive `RUN` instructions. Consider consolidation.",
34 line,
35 );
36 }
37 }
38 _ => {
40 state.data.set_int("consecutive_runs", 0);
41 }
42 }
43 },
44 )
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50 use crate::analyzer::hadolint::config::HadolintConfig;
51 use crate::analyzer::hadolint::lint::{LintResult, lint};
52
53 fn lint_dockerfile(content: &str) -> LintResult {
54 lint(content, &HadolintConfig::default())
55 }
56
57 #[test]
58 fn test_consecutive_runs() {
59 let result =
60 lint_dockerfile("FROM ubuntu:20.04\nRUN apt-get update\nRUN apt-get install -y nginx");
61 assert!(result.failures.iter().any(|f| f.code.as_str() == "DL3059"));
62 }
63
64 #[test]
65 fn test_single_run() {
66 let result =
67 lint_dockerfile("FROM ubuntu:20.04\nRUN apt-get update && apt-get install -y nginx");
68 assert!(!result.failures.iter().any(|f| f.code.as_str() == "DL3059"));
69 }
70
71 #[test]
72 fn test_runs_separated_by_other() {
73 let result = lint_dockerfile(
74 "FROM ubuntu:20.04\nRUN apt-get update\nENV DEBIAN_FRONTEND=noninteractive\nRUN apt-get install -y nginx",
75 );
76 assert!(!result.failures.iter().any(|f| f.code.as_str() == "DL3059"));
77 }
78
79 #[test]
80 fn test_three_consecutive_runs() {
81 let result = lint_dockerfile("FROM ubuntu:20.04\nRUN echo 1\nRUN echo 2\nRUN echo 3");
82 let count = result
84 .failures
85 .iter()
86 .filter(|f| f.code.as_str() == "DL3059")
87 .count();
88 assert_eq!(count, 2);
89 }
90
91 #[test]
92 fn test_different_stages() {
93 let result = lint_dockerfile(
94 "FROM ubuntu:20.04 AS stage1\nRUN echo 1\nFROM ubuntu:20.04 AS stage2\nRUN echo 2",
95 );
96 assert!(!result.failures.iter().any(|f| f.code.as_str() == "DL3059"));
98 }
99}