3
3
//! This module implements `bootc container lint`.
4
4
5
5
use std:: env:: consts:: ARCH ;
6
+ use std:: os:: unix:: ffi:: OsStrExt ;
6
7
7
- use anyhow:: { bail, ensure, Result } ;
8
+ use anyhow:: { bail, ensure, Context , Result } ;
8
9
use cap_std:: fs:: Dir ;
9
10
use cap_std_ext:: cap_std;
10
11
use cap_std_ext:: dirext:: CapStdExtDirExt as _;
11
12
use fn_error_context:: context;
12
13
13
14
use crate :: utils:: openat2_with_retry;
14
15
16
+ /// Reference to embedded default baseimage content that should exist.
17
+ const BASEIMAGE_REF : & str = "usr/share/doc/bootc/baseimage/base" ;
18
+
15
19
/// check for the existence of the /var/run directory
16
20
/// if it exists we need to check that it links to /run if not error
17
21
/// if it does not exist error.
@@ -23,6 +27,7 @@ pub(crate) fn lint(root: &Dir) -> Result<()> {
23
27
check_parse_kargs,
24
28
check_usretc,
25
29
check_utf8,
30
+ check_baseimage_root,
26
31
] ;
27
32
for lint in lints {
28
33
lint ( & root) ?;
@@ -116,6 +121,57 @@ fn check_utf8(dir: &Dir) -> Result<()> {
116
121
Ok ( ( ) )
117
122
}
118
123
124
+ /// Check for a few files and directories we expect in the base image.
125
+ fn check_baseimage_root_norecurse ( dir : & Dir ) -> Result < ( ) > {
126
+ // Check /sysroot
127
+ let meta = dir. symlink_metadata_optional ( "sysroot" ) ?;
128
+ match meta {
129
+ Some ( meta) if !meta. is_dir ( ) => {
130
+ anyhow:: bail!( "Expected a directory for /sysroot" )
131
+ }
132
+ None => anyhow:: bail!( "Missing /sysroot" ) ,
133
+ _ => { }
134
+ }
135
+
136
+ // Check /ostree -> sysroot/ostree
137
+ let Some ( meta) = dir. symlink_metadata_optional ( "ostree" ) ? else {
138
+ anyhow:: bail!( "Missing ostree -> sysroot/ostree link" )
139
+ } ;
140
+ if !meta. is_symlink ( ) {
141
+ anyhow:: bail!( "/ostree should be a symlink" ) ;
142
+ }
143
+ let link = dir. read_link_contents ( "ostree" ) ?;
144
+ let expected = "sysroot/ostree" ;
145
+ if link. as_os_str ( ) . as_bytes ( ) != expected. as_bytes ( ) {
146
+ anyhow:: bail!( "Expected /ostree -> {expected}, not {link:?}" ) ;
147
+ }
148
+
149
+ // Check the prepare-root config
150
+ let prepareroot_path = "usr/lib/ostree/prepare-root.conf" ;
151
+ let config_data = dir
152
+ . read_to_string ( prepareroot_path)
153
+ . context ( prepareroot_path) ?;
154
+ let config = ostree_ext:: glib:: KeyFile :: new ( ) ;
155
+ config. load_from_data ( & config_data, ostree_ext:: glib:: KeyFileFlags :: empty ( ) ) ?;
156
+
157
+ if !ostree_ext:: ostree_prepareroot:: overlayfs_enabled_in_config ( & config) ? {
158
+ anyhow:: bail!( "{prepareroot_path} does not have composefs enabled" )
159
+ }
160
+
161
+ Ok ( ( ) )
162
+ }
163
+
164
+ /// Check ostree-related base image content.
165
+ fn check_baseimage_root ( dir : & Dir ) -> Result < ( ) > {
166
+ check_baseimage_root_norecurse ( dir) ?;
167
+ // If we have our own documentation with the expected root contents
168
+ // embedded, then check that too! Mostly just because recursion is fun.
169
+ if let Some ( dir) = dir. open_dir_optional ( BASEIMAGE_REF ) ? {
170
+ check_baseimage_root_norecurse ( & dir) ?;
171
+ }
172
+ Ok ( ( ) )
173
+ }
174
+
119
175
#[ cfg( test) ]
120
176
mod tests {
121
177
use super :: * ;
@@ -260,4 +316,34 @@ mod tests {
260
316
root. remove_file ( badfile) . unwrap ( ) ; // Get rid of the problem
261
317
check_utf8 ( root) . unwrap ( ) ; // Check it
262
318
}
319
+
320
+ #[ test]
321
+ fn test_baseimage_root ( ) -> Result < ( ) > {
322
+ use bootc_utils:: CommandRunExt ;
323
+ use cap_std_ext:: cmdext:: CapStdExtCommandExt ;
324
+ use std:: path:: Path ;
325
+
326
+ let td = fixture ( ) ?;
327
+
328
+ // An empty root should fail our test
329
+ assert ! ( check_baseimage_root( & td) . is_err( ) ) ;
330
+
331
+ // Copy our reference base image content from the source dir
332
+ let manifest = std:: env:: var_os ( "CARGO_MANIFEST_PATH" ) . unwrap ( ) ;
333
+ let srcdir = Path :: new ( & manifest)
334
+ . parent ( )
335
+ . unwrap ( )
336
+ . join ( "../baseimage/base" ) ;
337
+ for ent in std:: fs:: read_dir ( srcdir) ? {
338
+ let ent = ent?;
339
+ std:: process:: Command :: new ( "cp" )
340
+ . cwd_dir ( td. try_clone ( ) ?)
341
+ . arg ( "-pr" )
342
+ . arg ( ent. path ( ) )
343
+ . arg ( "." )
344
+ . run ( ) ?;
345
+ }
346
+ check_baseimage_root ( & td) . unwrap ( ) ;
347
+ Ok ( ( ) )
348
+ }
263
349
}
0 commit comments