@@ -13,7 +13,7 @@ const DOCKERFILE_NETWORK_CUTOFF: &str = "external dependency cutoff point";
1313///
1414/// - Reproducible builds for the RPM
1515/// - Dockerfile network isolation after cutoff point
16- /// - Dockerfile tmpfs on /run for all RUN instructions
16+ /// - Dockerfile tmpfs on /run and /tmp for all RUN instructions
1717#[ context( "Checking build system" ) ]
1818pub fn check_buildsys ( sh : & Shell , dockerfile_path : & Utf8Path ) -> Result < ( ) > {
1919 check_package_reproducibility ( sh) ?;
@@ -75,11 +75,16 @@ fn check_dockerfile_rules(dockerfile_path: &Utf8Path) -> Result<()> {
7575}
7676
7777const RUN_NETWORK_NONE : & str = "RUN --network=none" ;
78- const RUN_TMPFS : & str = "--mount=type=tmpfs,target=/run" ;
78+ const RUN_TMPFS_RUN : & str = "--mount=type=tmpfs,target=/run" ;
79+ const RUN_TMPFS_TMP : & str = "--mount=type=tmpfs,target=/tmp" ;
80+ const ALLOW_NON_TMPFS : & str = "# lint: allow non-tmpfs" ;
7981
8082/// Verify Dockerfile rules:
81- /// - All RUN instructions must include `--mount=type=tmpfs,target=/run` to prevent
82- /// podman's DNS resolver files from leaking into the image
83+ /// - All RUN instructions must include `--mount=type=tmpfs,target=/run` and
84+ /// `--mount=type=tmpfs,target=/tmp` to prevent podman's DNS resolver files
85+ /// and temporary files from leaking into the image
86+ /// - A comment `# lint: allow non-tmpfs` on the preceding line exempts a RUN
87+ /// instruction from the tmpfs requirement
8388/// - After the network cutoff, all RUN instructions must start with `--network=none`
8489///
8590/// Returns Ok(()) if all RUN instructions comply, or an error listing violations.
@@ -96,20 +101,38 @@ pub fn verify_dockerfile_rules(dockerfile: &str) -> Result<()> {
96101 } ) ?;
97102
98103 let mut errors = Vec :: new ( ) ;
104+ let mut skip_tmpfs_check = false ;
99105
100106 for ( idx, line) in dockerfile. lines ( ) . enumerate ( ) {
101107 let line_num = idx + 1 ; // 1-based line numbers
102108 let trimmed = line. trim ( ) ;
103109
110+ // Check for the allow comment directive
111+ if trimmed. starts_with ( ALLOW_NON_TMPFS ) {
112+ skip_tmpfs_check = true ;
113+ continue ;
114+ }
115+
104116 // Check if this is a RUN instruction
105117 if trimmed. starts_with ( "RUN " ) {
106- // All RUN instructions must include tmpfs mount on /run
107- if !trimmed. contains ( RUN_TMPFS ) {
108- errors. push ( format ! (
109- " line {}: RUN instruction must include `{}`" ,
110- line_num, RUN_TMPFS
111- ) ) ;
118+ if !skip_tmpfs_check {
119+ // All RUN instructions must include tmpfs mount on /run
120+ if !trimmed. contains ( RUN_TMPFS_RUN ) {
121+ errors. push ( format ! (
122+ " line {}: RUN instruction must include `{}`" ,
123+ line_num, RUN_TMPFS_RUN
124+ ) ) ;
125+ }
126+
127+ // All RUN instructions must include tmpfs mount on /tmp
128+ if !trimmed. contains ( RUN_TMPFS_TMP ) {
129+ errors. push ( format ! (
130+ " line {}: RUN instruction must include `{}`" ,
131+ line_num, RUN_TMPFS_TMP
132+ ) ) ;
133+ }
112134 }
135+ skip_tmpfs_check = false ;
113136
114137 // After cutoff, must start with exactly "RUN --network=none"
115138 if idx > cutoff_line && !trimmed. starts_with ( RUN_NETWORK_NONE ) {
@@ -139,35 +162,57 @@ mod tests {
139162 fn test_dockerfile_rules_valid ( ) {
140163 let dockerfile = r#"
141164FROM base
142- RUN --mount=type=tmpfs,target=/run echo "before cutoff, network allowed"
165+ RUN --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp echo "before cutoff, network allowed"
143166# external dependency cutoff point
144- RUN --network=none --mount=type=tmpfs,target=/run echo "good"
145- RUN --network=none --mount=type=tmpfs,target=/run --mount=type=bind,from=foo,target=/bar some-command
167+ RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp echo "good"
168+ RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp --mount=type=bind,from=foo,target=/bar some-command
169+ # lint: allow non-tmpfs
170+ RUN --network=none bootc container lint --fatal-warnings
146171"# ;
147172 verify_dockerfile_rules ( dockerfile) . unwrap ( ) ;
148173 }
149174
150175 #[ test]
151- fn test_dockerfile_rules_missing_tmpfs_before_cutoff ( ) {
176+ fn test_dockerfile_rules_missing_tmpfs_run_before_cutoff ( ) {
152177 let dockerfile = r#"
153178FROM base
154- RUN echo "bad - missing tmpfs"
179+ RUN --mount=type=tmpfs,target=/tmp echo "bad - missing /run tmpfs"
155180# external dependency cutoff point
156- RUN --network=none --mount=type=tmpfs,target=/run echo "good"
181+ RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp echo "good"
157182"# ;
158183 let err = verify_dockerfile_rules ( dockerfile) . unwrap_err ( ) ;
159184 let msg = err. to_string ( ) ;
160185 assert ! ( msg. contains( "line 3" ) , "error should mention line 3: {msg}" ) ;
161- assert ! ( msg. contains( "tmpfs" ) , "error should mention tmpfs: {msg}" ) ;
186+ assert ! (
187+ msg. contains( "target=/run" ) ,
188+ "error should mention target=/run: {msg}"
189+ ) ;
190+ }
191+
192+ #[ test]
193+ fn test_dockerfile_rules_missing_tmpfs_tmp_before_cutoff ( ) {
194+ let dockerfile = r#"
195+ FROM base
196+ RUN --mount=type=tmpfs,target=/run echo "bad - missing /tmp tmpfs"
197+ # external dependency cutoff point
198+ RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp echo "good"
199+ "# ;
200+ let err = verify_dockerfile_rules ( dockerfile) . unwrap_err ( ) ;
201+ let msg = err. to_string ( ) ;
202+ assert ! ( msg. contains( "line 3" ) , "error should mention line 3: {msg}" ) ;
203+ assert ! (
204+ msg. contains( "target=/tmp" ) ,
205+ "error should mention target=/tmp: {msg}"
206+ ) ;
162207 }
163208
164209 #[ test]
165210 fn test_dockerfile_rules_missing_network_flag_after_cutoff ( ) {
166211 let dockerfile = r#"
167212FROM base
168- RUN --mount=type=tmpfs,target=/run echo "before cutoff"
213+ RUN --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp echo "before cutoff"
169214# external dependency cutoff point
170- RUN --mount=type=tmpfs,target=/run echo "bad - missing network flag"
215+ RUN --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp echo "bad - missing network flag"
171216"# ;
172217 let err = verify_dockerfile_rules ( dockerfile) . unwrap_err ( ) ;
173218 let msg = err. to_string ( ) ;
@@ -182,9 +227,9 @@ RUN --mount=type=tmpfs,target=/run echo "bad - missing network flag"
182227 fn test_dockerfile_rules_missing_tmpfs_after_cutoff ( ) {
183228 let dockerfile = r#"
184229FROM base
185- RUN --mount=type=tmpfs,target=/run echo "before cutoff"
230+ RUN --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp echo "before cutoff"
186231# external dependency cutoff point
187- RUN --network=none echo "bad - missing tmpfs"
232+ RUN --network=none echo "bad - missing both tmpfs"
188233"# ;
189234 let err = verify_dockerfile_rules ( dockerfile) . unwrap_err ( ) ;
190235 let msg = err. to_string ( ) ;
@@ -197,9 +242,9 @@ RUN --network=none echo "bad - missing tmpfs"
197242 // --network=none must come immediately after RUN
198243 let dockerfile = r#"
199244FROM base
200- RUN --mount=type=tmpfs,target=/run echo "before cutoff"
245+ RUN --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp echo "before cutoff"
201246# external dependency cutoff point
202- RUN --mount=type=tmpfs,target=/run --network=none echo "bad - network flag not first"
247+ RUN --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp -- network=none echo "bad - network flag not first"
203248"# ;
204249 let err = verify_dockerfile_rules ( dockerfile) . unwrap_err ( ) ;
205250 let msg = err. to_string ( ) ;
0 commit comments