2
2
//!
3
3
//! This module implements `bootc container lint`.
4
4
5
+ // Unfortunately needed here to work with linkme
6
+ #![ allow( unsafe_code) ]
7
+
5
8
use std:: collections:: BTreeSet ;
6
9
use std:: env:: consts:: ARCH ;
7
10
use std:: os:: unix:: ffi:: OsStrExt ;
@@ -14,6 +17,7 @@ use cap_std_ext::cap_std::fs::MetadataExt;
14
17
use cap_std_ext:: dirext:: CapStdExtDirExt as _;
15
18
use fn_error_context:: context;
16
19
use indoc:: indoc;
20
+ use linkme:: distributed_slice;
17
21
use ostree_ext:: ostree_prepareroot;
18
22
use serde:: Serialize ;
19
23
@@ -52,6 +56,8 @@ impl LintError {
52
56
}
53
57
54
58
type LintFn = fn ( & Dir ) -> LintResult ;
59
+ #[ distributed_slice]
60
+ pub ( crate ) static LINTS : [ Lint ] ;
55
61
56
62
/// The classification of a lint type.
57
63
#[ derive( Debug , Serialize ) ]
@@ -81,85 +87,37 @@ struct Lint {
81
87
description : & ' static str ,
82
88
}
83
89
84
- const LINTS : & [ Lint ] = & [
85
- Lint {
86
- name : "var-run" ,
87
- ty : LintType :: Fatal ,
88
- f : check_var_run,
89
- description : "Check for /var/run being a physical directory; this is always a bug." ,
90
- } ,
91
- Lint {
92
- name : "kernel" ,
93
- ty : LintType :: Fatal ,
94
- f : check_kernel,
95
- description : indoc ! { r#"
96
- Check for multiple kernels, i.e. multiple directories of the form /usr/lib/modules/$kver.
97
- Only one kernel is supported in an image.
98
- "# } ,
99
- } ,
100
- Lint {
101
- name : "bootc-kargs" ,
102
- ty : LintType :: Fatal ,
103
- f : check_parse_kargs,
104
- description : "Verify syntax of /usr/lib/bootc/kargs.d." ,
105
- } ,
106
- Lint {
107
- name : "etc-usretc" ,
108
- ty : LintType :: Fatal ,
109
- f : check_usretc,
110
- description : indoc ! { r#"
111
- Verify that only one of /etc or /usr/etc exist. You should only have /etc
112
- in a container image. It will cause undefined behavior to have both /etc
113
- and /usr/etc.
114
- "# } ,
115
- } ,
116
- Lint {
117
- // This one can be lifted in the future, see https://github.com/containers/bootc/issues/975
118
- name : "utf8" ,
119
- ty : LintType :: Fatal ,
120
- f : check_utf8,
121
- description : indoc ! { r#"
122
- Check for non-UTF8 filenames. Currently, the ostree backend of bootc only supports
123
- UTF-8 filenames. Non-UTF8 filenames will cause a fatal error.
124
- "# } ,
125
- } ,
126
- Lint {
127
- name : "baseimage-root" ,
128
- ty : LintType :: Fatal ,
129
- f : check_baseimage_root,
130
- description : indoc ! { r#"
131
- Check that expected files are present in the root of the filesystem; such
132
- as /sysroot and a composefs configuration for ostree. More in
133
- <https://containers.github.io/bootc/bootc-images.html#standard-image-content>.
134
- "# } ,
135
- } ,
136
- Lint {
137
- name : "var-log" ,
138
- ty : LintType :: Warning ,
139
- f : check_varlog,
140
- description : indoc ! { r#"
141
- Check for non-empty regular files in `/var/log`. It is often undesired
142
- to ship log files in container images. Log files in general are usually
143
- per-machine state in `/var`. Additionally, log files often include
144
- timestamps, causing unreproducible container images, and may contain
145
- sensitive build system information.
146
- "# } ,
147
- } ,
148
- Lint {
149
- name : "nonempty-boot" ,
150
- ty : LintType :: Warning ,
151
- f : check_boot,
152
- description : indoc ! { r#"
153
- The `/boot` directory should be present, but empty. The kernel
154
- content should be in /usr/lib/modules instead in the container image.
155
- Any content here in the container image will be masked at runtime.
156
- "# } ,
157
- } ,
158
- ] ;
90
+ impl Lint {
91
+ pub ( crate ) const fn new_fatal (
92
+ name : & ' static str ,
93
+ description : & ' static str ,
94
+ f : LintFn ,
95
+ ) -> Self {
96
+ Lint {
97
+ name : name,
98
+ ty : LintType :: Fatal ,
99
+ f : f,
100
+ description : description,
101
+ }
102
+ }
103
+
104
+ pub ( crate ) const fn new_warning (
105
+ name : & ' static str ,
106
+ description : & ' static str ,
107
+ f : LintFn ,
108
+ ) -> Self {
109
+ Lint {
110
+ name : name,
111
+ ty : LintType :: Warning ,
112
+ f : f,
113
+ description : description,
114
+ }
115
+ }
116
+ }
159
117
160
118
pub ( crate ) fn lint_list ( output : impl std:: io:: Write ) -> Result < ( ) > {
161
119
// Dump in yaml format by default, it's readable enough
162
- serde_yaml:: to_writer ( output, LINTS ) ?;
120
+ serde_yaml:: to_writer ( output, & * LINTS ) ?;
163
121
Ok ( ( ) )
164
122
}
165
123
@@ -214,6 +172,12 @@ pub(crate) fn lint(
214
172
Ok ( ( ) )
215
173
}
216
174
175
+ #[ distributed_slice( LINTS ) ]
176
+ static LINT_VAR_RUN : Lint = Lint :: new_fatal (
177
+ "var-run" ,
178
+ "Check for /var/run being a physical directory; this is always a bug." ,
179
+ check_var_run,
180
+ ) ;
217
181
fn check_var_run ( root : & Dir ) -> LintResult {
218
182
if let Some ( meta) = root. symlink_metadata_optional ( "var/run" ) ? {
219
183
if !meta. is_symlink ( ) {
@@ -223,6 +187,16 @@ fn check_var_run(root: &Dir) -> LintResult {
223
187
lint_ok ( )
224
188
}
225
189
190
+ #[ distributed_slice( LINTS ) ]
191
+ static LINT_ETC_USRUSETC : Lint = Lint :: new_fatal (
192
+ "etc-usretc" ,
193
+ indoc ! { r#"
194
+ Verify that only one of /etc or /usr/etc exist. You should only have /etc
195
+ in a container image. It will cause undefined behavior to have both /etc
196
+ and /usr/etc.
197
+ "# } ,
198
+ check_usretc,
199
+ ) ;
226
200
fn check_usretc ( root : & Dir ) -> LintResult {
227
201
let etc_exists = root. symlink_metadata_optional ( "etc" ) ?. is_some ( ) ;
228
202
// For compatibility/conservatism don't bomb out if there's no /etc.
@@ -239,18 +213,43 @@ fn check_usretc(root: &Dir) -> LintResult {
239
213
}
240
214
241
215
/// Validate that we can parse the /usr/lib/bootc/kargs.d files.
216
+ #[ distributed_slice( LINTS ) ]
217
+ static LINT_KARGS : Lint = Lint :: new_fatal (
218
+ "bootc-kargs" ,
219
+ "Verify syntax of /usr/lib/bootc/kargs.d." ,
220
+ check_parse_kargs,
221
+ ) ;
242
222
fn check_parse_kargs ( root : & Dir ) -> LintResult {
243
223
let args = crate :: kargs:: get_kargs_in_root ( root, ARCH ) ?;
244
224
tracing:: debug!( "found kargs: {args:?}" ) ;
245
225
lint_ok ( )
246
226
}
247
227
228
+ #[ distributed_slice( LINTS ) ]
229
+ static LINT_KERNEL : Lint = Lint :: new_fatal (
230
+ "kernel" ,
231
+ indoc ! { r#"
232
+ Check for multiple kernels, i.e. multiple directories of the form /usr/lib/modules/$kver.
233
+ Only one kernel is supported in an image.
234
+ "# } ,
235
+ check_kernel,
236
+ ) ;
248
237
fn check_kernel ( root : & Dir ) -> LintResult {
249
238
let result = ostree_ext:: bootabletree:: find_kernel_dir_fs ( & root) ?;
250
239
tracing:: debug!( "Found kernel: {:?}" , result) ;
251
240
lint_ok ( )
252
241
}
253
242
243
+ // This one can be lifted in the future, see https://github.com/containers/bootc/issues/975
244
+ #[ distributed_slice( LINTS ) ]
245
+ static LINT_UTF8 : Lint = Lint :: new_fatal (
246
+ "utf8" ,
247
+ indoc ! { r#"
248
+ Check for non-UTF8 filenames. Currently, the ostree backend of bootc only supports
249
+ UTF-8 filenames. Non-UTF8 filenames will cause a fatal error.
250
+ "# } ,
251
+ check_utf8,
252
+ ) ;
254
253
fn check_utf8 ( dir : & Dir ) -> LintResult {
255
254
for entry in dir. entries ( ) ? {
256
255
let entry = entry?;
@@ -312,6 +311,16 @@ fn check_baseimage_root_norecurse(dir: &Dir) -> LintResult {
312
311
}
313
312
314
313
/// Check ostree-related base image content.
314
+ #[ distributed_slice( LINTS ) ]
315
+ static LINT_BASEIMAGE_ROOT : Lint = Lint :: new_fatal (
316
+ "baseimage-root" ,
317
+ indoc ! { r#"
318
+ Check that expected files are present in the root of the filesystem; such
319
+ as /sysroot and a composefs configuration for ostree. More in
320
+ <https://containers.github.io/bootc/bootc-images.html#standard-image-content>.
321
+ "# } ,
322
+ check_baseimage_root,
323
+ ) ;
315
324
fn check_baseimage_root ( dir : & Dir ) -> LintResult {
316
325
if let Err ( e) = check_baseimage_root_norecurse ( dir) ? {
317
326
return Ok ( Err ( e) ) ;
@@ -348,6 +357,18 @@ fn collect_nonempty_regfiles(
348
357
Ok ( ( ) )
349
358
}
350
359
360
+ #[ distributed_slice( LINTS ) ]
361
+ static LINT_VARLOG : Lint = Lint :: new_warning (
362
+ "var-log" ,
363
+ indoc ! { r#"
364
+ Check for non-empty regular files in `/var/log`. It is often undesired
365
+ to ship log files in container images. Log files in general are usually
366
+ per-machine state in `/var`. Additionally, log files often include
367
+ timestamps, causing unreproducible container images, and may contain
368
+ sensitive build system information.
369
+ "# } ,
370
+ check_varlog,
371
+ ) ;
351
372
fn check_varlog ( root : & Dir ) -> LintResult {
352
373
let Some ( d) = root. open_dir_optional ( "var/log" ) ? else {
353
374
return lint_ok ( ) ;
@@ -367,6 +388,16 @@ fn check_varlog(root: &Dir) -> LintResult {
367
388
lint_err ( format ! ( "Found non-empty logfile: {first}{others}" ) )
368
389
}
369
390
391
+ #[ distributed_slice( LINTS ) ]
392
+ static LINT_NONEMPTY_BOOT : Lint = Lint :: new_warning (
393
+ "nonempty-boot" ,
394
+ indoc ! { r#"
395
+ The `/boot` directory should be present, but empty. The kernel
396
+ content should be in /usr/lib/modules instead in the container image.
397
+ Any content here in the container image will be masked at runtime.
398
+ "# } ,
399
+ check_boot,
400
+ ) ;
370
401
fn check_boot ( root : & Dir ) -> LintResult {
371
402
let Some ( d) = root. open_dir_optional ( "boot" ) ? else {
372
403
return lint_err ( format ! ( "Missing /boot directory" ) ) ;
0 commit comments