@@ -73,6 +73,18 @@ pub(crate) struct InstallTargetOpts {
73
73
/// Enable verification via an ostree remote
74
74
#[ clap( long) ]
75
75
pub ( crate ) target_ostree_remote : Option < String > ,
76
+
77
+ /// By default, the accessiblity of the target image will be verified (just the manifest will be fetched).
78
+ /// Specifying this option suppresses the check; use this when you know the issues it might find
79
+ /// are addressed.
80
+ ///
81
+ /// Two main reasons this might fail:
82
+ ///
83
+ /// - Forgetting `--target-no-signature-verification` if needed
84
+ /// - Using a registry which requires authentication, but not embedding the pull secret in the image.
85
+ #[ clap( long) ]
86
+ #[ serde( default ) ]
87
+ pub ( crate ) skip_fetch_check : bool ,
76
88
}
77
89
78
90
#[ derive( clap:: Args , Debug , Clone , Serialize , Deserialize ) ]
@@ -200,7 +212,7 @@ pub(crate) struct State {
200
212
pub ( crate ) setenforce_guard : Option < crate :: lsm:: SetEnforceGuard > ,
201
213
#[ allow( dead_code) ]
202
214
pub ( crate ) config_opts : InstallConfigOpts ,
203
- pub ( crate ) target_opts : InstallTargetOpts ,
215
+ pub ( crate ) target_imgref : ostree_container :: OstreeImageReference ,
204
216
pub ( crate ) install_config : config:: InstallConfiguration ,
205
217
}
206
218
@@ -435,32 +447,8 @@ async fn initialize_ostree_root_from_self(
435
447
) -> Result < InstallAleph > {
436
448
let rootfs_dir = & root_setup. rootfs_fd ;
437
449
let rootfs = root_setup. rootfs . as_path ( ) ;
438
- let opts = & state. target_opts ;
439
450
let cancellable = gio:: Cancellable :: NONE ;
440
451
441
- // Parse the target CLI image reference options and create the *target* image
442
- // reference, which defaults to pulling from a registry.
443
- let target_sigverify = if opts. target_no_signature_verification {
444
- SignatureSource :: ContainerPolicyAllowInsecure
445
- } else if let Some ( remote) = opts. target_ostree_remote . as_deref ( ) {
446
- SignatureSource :: OstreeRemote ( remote. to_string ( ) )
447
- } else {
448
- SignatureSource :: ContainerPolicy
449
- } ;
450
- let target_imgname = opts
451
- . target_imgref
452
- . as_deref ( )
453
- . unwrap_or ( state. source . imageref . name . as_str ( ) ) ;
454
- let target_transport = ostree_container:: Transport :: try_from ( opts. target_transport . as_str ( ) ) ?;
455
- let target_imgref = ostree_container:: OstreeImageReference {
456
- sigverify : target_sigverify,
457
- imgref : ostree_container:: ImageReference {
458
- transport : target_transport,
459
- name : target_imgname. to_string ( ) ,
460
- } ,
461
- } ;
462
- tracing:: debug!( "Target image reference: {target_imgref}" ) ;
463
-
464
452
// TODO: make configurable?
465
453
let stateroot = STATEROOT_DEFAULT ;
466
454
Task :: new_and_run (
@@ -535,12 +523,12 @@ async fn initialize_ostree_root_from_self(
535
523
. collect :: < Vec < _ > > ( ) ;
536
524
let mut options = ostree_container:: deploy:: DeployOpts :: default ( ) ;
537
525
options. kargs = Some ( kargs. as_slice ( ) ) ;
538
- options. target_imgref = Some ( & target_imgref) ;
526
+ options. target_imgref = Some ( & state . target_imgref ) ;
539
527
options. proxy_cfg = Some ( proxy_cfg) ;
540
528
println ! ( "Creating initial deployment" ) ;
529
+ let target_image = state. target_imgref . to_string ( ) ;
541
530
let state =
542
531
ostree_container:: deploy:: deploy ( & sysroot, stateroot, & src_imageref, Some ( options) ) . await ?;
543
- let target_image = target_imgref. to_string ( ) ;
544
532
let digest = state. manifest_digest . as_str ( ) ;
545
533
println ! ( "Installed: {target_image}" ) ;
546
534
println ! ( " Digest: {digest}" ) ;
@@ -789,6 +777,28 @@ pub(crate) fn propagate_tmp_mounts_to_host() -> Result<()> {
789
777
Ok ( ( ) )
790
778
}
791
779
780
+ /// Verify that we can load the manifest of the target image
781
+ #[ context( "Verifying fetch" ) ]
782
+ async fn verify_target_fetch ( imgref : & ostree_container:: OstreeImageReference ) -> Result < ( ) > {
783
+ let tmpdir = tempfile:: tempdir ( ) ?;
784
+ let tmprepo = & ostree:: Repo :: new_for_path ( tmpdir. path ( ) ) ;
785
+ tmprepo
786
+ . create ( ostree:: RepoMode :: Bare , ostree:: gio:: Cancellable :: NONE )
787
+ . context ( "Init tmp repo" ) ?;
788
+
789
+ tracing:: trace!( "Verifying fetch for {imgref}" ) ;
790
+ let mut imp =
791
+ ostree_container:: store:: ImageImporter :: new ( & tmprepo, imgref, Default :: default ( ) ) . await ?;
792
+ use ostree_container:: store:: PrepareResult ;
793
+ let prep = match imp. prepare ( ) . await ? {
794
+ // SAFETY: It's impossible that the image was already fetched into this newly created temporary repository
795
+ PrepareResult :: AlreadyPresent ( _) => unreachable ! ( ) ,
796
+ PrepareResult :: Ready ( r) => r,
797
+ } ;
798
+ tracing:: debug!( "Fetched manifest with digest {}" , prep. manifest_digest) ;
799
+ Ok ( ( ) )
800
+ }
801
+
792
802
/// Preparation for an install; validates and prepares some (thereafter immutable) global state.
793
803
async fn prepare_install (
794
804
config_opts : InstallConfigOpts ,
@@ -816,6 +826,34 @@ async fn prepare_install(
816
826
817
827
let source = SourceInfo :: from_container ( & container_info) ?;
818
828
829
+ // Parse the target CLI image reference options and create the *target* image
830
+ // reference, which defaults to pulling from a registry.
831
+ let target_sigverify = if target_opts. target_no_signature_verification {
832
+ SignatureSource :: ContainerPolicyAllowInsecure
833
+ } else if let Some ( remote) = target_opts. target_ostree_remote . as_deref ( ) {
834
+ SignatureSource :: OstreeRemote ( remote. to_string ( ) )
835
+ } else {
836
+ SignatureSource :: ContainerPolicy
837
+ } ;
838
+ let target_imgname = target_opts
839
+ . target_imgref
840
+ . as_deref ( )
841
+ . unwrap_or ( source. imageref . name . as_str ( ) ) ;
842
+ let target_transport =
843
+ ostree_container:: Transport :: try_from ( target_opts. target_transport . as_str ( ) ) ?;
844
+ let target_imgref = ostree_container:: OstreeImageReference {
845
+ sigverify : target_sigverify,
846
+ imgref : ostree_container:: ImageReference {
847
+ transport : target_transport,
848
+ name : target_imgname. to_string ( ) ,
849
+ } ,
850
+ } ;
851
+ tracing:: debug!( "Target image reference: {target_imgref}" ) ;
852
+
853
+ if !target_opts. skip_fetch_check {
854
+ verify_target_fetch ( & target_imgref) . await ?;
855
+ }
856
+
819
857
ensure_var ( ) ?;
820
858
propagate_tmp_mounts_to_host ( ) ?;
821
859
@@ -841,7 +879,7 @@ async fn prepare_install(
841
879
setenforce_guard,
842
880
source,
843
881
config_opts,
844
- target_opts ,
882
+ target_imgref ,
845
883
install_config,
846
884
} ) ;
847
885
0 commit comments