syncable_cli/analyzer/hadolint/rules/
dl3047.rs1use crate::analyzer::hadolint::parser::instruction::Instruction;
7use crate::analyzer::hadolint::rules::{CustomRule, RuleState, custom_rule};
8use crate::analyzer::hadolint::shell::ParsedShell;
9use crate::analyzer::hadolint::types::Severity;
10
11pub fn rule()
12-> CustomRule<impl Fn(&mut RuleState, u32, &Instruction, Option<&ParsedShell>) + Send + Sync> {
13 custom_rule(
14 "DL3047",
15 Severity::Info,
16 "Avoid using both `wget` and `curl` since they serve the same purpose.",
17 |state, line, instr, shell| {
18 match instr {
19 Instruction::From(_) => {
20 state.data.set_bool("seen_wget", false);
22 state.data.set_bool("seen_curl", false);
23 state.data.set_bool("reported_dl3047", false);
24 }
25 Instruction::Run(_) => {
26 if let Some(shell) = shell {
27 let uses_wget = shell.using_program("wget");
28 let uses_curl = shell.using_program("curl");
29
30 if uses_wget {
31 state.data.set_bool("seen_wget", true);
32 }
33 if uses_curl {
34 state.data.set_bool("seen_curl", true);
35 }
36
37 let seen_both =
39 state.data.get_bool("seen_wget") && state.data.get_bool("seen_curl");
40 let already_reported = state.data.get_bool("reported_dl3047");
41
42 if seen_both && !already_reported {
43 state.add_failure(
44 "DL3047",
45 Severity::Info,
46 "Avoid using both `wget` and `curl` since they serve the same purpose.",
47 line,
48 );
49 state.data.set_bool("reported_dl3047", true);
50 }
51 }
52 }
53 _ => {}
54 }
55 },
56 )
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62 use crate::analyzer::hadolint::config::HadolintConfig;
63 use crate::analyzer::hadolint::lint::{LintResult, lint};
64
65 fn lint_dockerfile(content: &str) -> LintResult {
66 lint(content, &HadolintConfig::default())
67 }
68
69 #[test]
70 fn test_wget_only() {
71 let result = lint_dockerfile("FROM ubuntu:20.04\nRUN wget https://example.com/file");
72 assert!(!result.failures.iter().any(|f| f.code.as_str() == "DL3047"));
73 }
74
75 #[test]
76 fn test_curl_only() {
77 let result = lint_dockerfile("FROM ubuntu:20.04\nRUN curl -O https://example.com/file");
78 assert!(!result.failures.iter().any(|f| f.code.as_str() == "DL3047"));
79 }
80
81 #[test]
82 fn test_both_wget_and_curl() {
83 let result = lint_dockerfile(
84 "FROM ubuntu:20.04\nRUN wget https://example.com/file1\nRUN curl -O https://example.com/file2",
85 );
86 assert!(result.failures.iter().any(|f| f.code.as_str() == "DL3047"));
87 }
88
89 #[test]
90 fn test_both_in_same_run() {
91 let result = lint_dockerfile(
92 "FROM ubuntu:20.04\nRUN wget https://a.com/f && curl -O https://b.com/g",
93 );
94 assert!(result.failures.iter().any(|f| f.code.as_str() == "DL3047"));
95 }
96
97 #[test]
98 fn test_different_stages() {
99 let result = lint_dockerfile(
101 "FROM ubuntu:20.04 AS stage1\nRUN wget https://a.com/f\nFROM ubuntu:20.04 AS stage2\nRUN curl https://b.com/g",
102 );
103 assert!(!result.failures.iter().any(|f| f.code.as_str() == "DL3047"));
104 }
105}