syncable_cli/analyzer/hadolint/rules/
dl3006.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 "DL3006",
15 Severity::Warning,
16 "Always tag the version of an image explicitly",
17 |state, line, instr, _shell| {
18 if let Instruction::From(base) = instr {
19 if let Some(alias) = &base.alias {
21 state.data.insert_to_set("aliases", alias.as_str());
22 }
23
24 let image_name = &base.image.name;
26
27 if base.is_scratch() {
35 return;
36 }
37
38 if base.has_version() {
39 return;
40 }
41
42 if base.is_variable() {
43 return;
44 }
45
46 if state.data.set_contains("aliases", image_name) {
48 return;
49 }
50
51 state.add_failure(
53 "DL3006",
54 Severity::Warning,
55 "Always tag the version of an image explicitly",
56 line,
57 );
58 }
59 },
60 )
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66 use crate::analyzer::hadolint::parser::instruction::{BaseImage, ImageAlias};
67 use crate::analyzer::hadolint::rules::Rule;
68
69 #[test]
70 fn test_tagged_image() {
71 let rule = rule();
72 let mut state = RuleState::new();
73
74 let mut base = BaseImage::new("ubuntu");
75 base.tag = Some("20.04".to_string());
76 let instr = Instruction::From(base);
77
78 rule.check(&mut state, 1, &instr, None);
79 assert!(state.failures.is_empty());
80 }
81
82 #[test]
83 fn test_untagged_image() {
84 let rule = rule();
85 let mut state = RuleState::new();
86
87 let instr = Instruction::From(BaseImage::new("ubuntu"));
88 rule.check(&mut state, 1, &instr, None);
89 assert_eq!(state.failures.len(), 1);
90 assert_eq!(state.failures[0].code.as_str(), "DL3006");
91 }
92
93 #[test]
94 fn test_scratch_image() {
95 let rule = rule();
96 let mut state = RuleState::new();
97
98 let instr = Instruction::From(BaseImage::new("scratch"));
99 rule.check(&mut state, 1, &instr, None);
100 assert!(state.failures.is_empty());
101 }
102
103 #[test]
104 fn test_stage_reference() {
105 let rule = rule();
106 let mut state = RuleState::new();
107
108 let mut base1 = BaseImage::new("node");
110 base1.tag = Some("18".to_string());
111 base1.alias = Some(ImageAlias::new("builder"));
112 let instr1 = Instruction::From(base1);
113 rule.check(&mut state, 1, &instr1, None);
114
115 let instr2 = Instruction::From(BaseImage::new("builder"));
117 rule.check(&mut state, 10, &instr2, None);
118
119 assert!(state.failures.is_empty());
120 }
121
122 #[test]
123 fn test_variable_image() {
124 let rule = rule();
125 let mut state = RuleState::new();
126
127 let instr = Instruction::From(BaseImage::new("${BASE_IMAGE}"));
128 rule.check(&mut state, 1, &instr, None);
129 assert!(state.failures.is_empty());
130 }
131}