syncable_cli/analyzer/hadolint/rules/
dl3019.rs1use crate::analyzer::hadolint::parser::instruction::Instruction;
6use crate::analyzer::hadolint::rules::{simple_rule, SimpleRule};
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 "DL3019",
13 Severity::Info,
14 "Use the `--no-cache` switch to avoid the need to use `--update` and remove `/var/cache/apk/*`.",
15 |instr, shell| {
16 match instr {
17 Instruction::Run(_) => {
18 if let Some(shell) = shell {
19 !shell.any_command(|cmd| {
20 if cmd.name == "apk" && cmd.has_any_arg(&["add"]) {
21 !cmd.has_any_flag(&["no-cache"])
23 } else {
24 false
25 }
26 })
27 } else {
28 true
29 }
30 }
31 _ => true,
32 }
33 },
34 )
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40 use crate::analyzer::hadolint::lint::{lint, LintResult};
41 use crate::analyzer::hadolint::config::HadolintConfig;
42
43 fn lint_dockerfile(content: &str) -> LintResult {
44 lint(content, &HadolintConfig::default())
45 }
46
47 #[test]
48 fn test_apk_add_without_no_cache() {
49 let result = lint_dockerfile("FROM alpine:3.18\nRUN apk add nginx=1.24.0");
50 assert!(result.failures.iter().any(|f| f.code.as_str() == "DL3019"));
51 }
52
53 #[test]
54 fn test_apk_add_with_no_cache() {
55 let result = lint_dockerfile("FROM alpine:3.18\nRUN apk add --no-cache nginx=1.24.0");
56 assert!(!result.failures.iter().any(|f| f.code.as_str() == "DL3019"));
57 }
58
59 #[test]
60 fn test_apk_update() {
61 let result = lint_dockerfile("FROM alpine:3.18\nRUN apk update");
62 assert!(!result.failures.iter().any(|f| f.code.as_str() == "DL3019"));
63 }
64}