syncable_cli/analyzer/hadolint/rules/
dl3061.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 "DL3061",
13 Severity::Error,
14 "Invalid image name in `FROM`.",
15 |instr, _shell| {
16 match instr {
17 Instruction::From(base_image) => {
18 is_valid_image_name(&base_image.image.name)
19 }
20 _ => true,
21 }
22 },
23 )
24}
25
26fn is_valid_image_name(name: &str) -> bool {
27 if name.is_empty() {
28 return false;
29 }
30
31 if name == "scratch" {
33 return true;
34 }
35
36 if name.starts_with('$') {
38 return true;
39 }
40
41 let valid_chars = |c: char| {
48 c.is_ascii_lowercase()
49 || c.is_ascii_digit()
50 || c == '-'
51 || c == '_'
52 || c == '.'
53 || c == '/'
54 || c == ':'
55 };
56
57 name.chars().all(valid_chars)
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use crate::analyzer::hadolint::lint::{lint, LintResult};
64 use crate::analyzer::hadolint::config::HadolintConfig;
65
66 fn lint_dockerfile(content: &str) -> LintResult {
67 lint(content, &HadolintConfig::default())
68 }
69
70 #[test]
71 fn test_valid_image() {
72 let result = lint_dockerfile("FROM ubuntu:20.04");
73 assert!(!result.failures.iter().any(|f| f.code.as_str() == "DL3061"));
74 }
75
76 #[test]
77 fn test_valid_registry_image() {
78 let result = lint_dockerfile("FROM registry.example.com/myimage:latest");
79 assert!(!result.failures.iter().any(|f| f.code.as_str() == "DL3061"));
80 }
81
82 #[test]
83 fn test_scratch() {
84 let result = lint_dockerfile("FROM scratch");
85 assert!(!result.failures.iter().any(|f| f.code.as_str() == "DL3061"));
86 }
87
88 #[test]
89 fn test_variable_image() {
90 let result = lint_dockerfile("ARG BASE=ubuntu\nFROM $BASE");
91 assert!(!result.failures.iter().any(|f| f.code.as_str() == "DL3061"));
92 }
93}