@@ -73,6 +73,18 @@ pub(crate) struct InstallTargetOpts {
7373 /// Enable verification via an ostree remote
7474 #[ clap( long) ]
7575 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 ,
7688}
7789
7890#[ derive( clap:: Args , Debug , Clone , Serialize , Deserialize ) ]
@@ -200,7 +212,7 @@ pub(crate) struct State {
200212 pub ( crate ) setenforce_guard : Option < crate :: lsm:: SetEnforceGuard > ,
201213 #[ allow( dead_code) ]
202214 pub ( crate ) config_opts : InstallConfigOpts ,
203- pub ( crate ) target_opts : InstallTargetOpts ,
215+ pub ( crate ) target_imgref : ostree_container :: OstreeImageReference ,
204216 pub ( crate ) install_config : config:: InstallConfiguration ,
205217}
206218
@@ -435,32 +447,8 @@ async fn initialize_ostree_root_from_self(
435447) -> Result < InstallAleph > {
436448 let rootfs_dir = & root_setup. rootfs_fd ;
437449 let rootfs = root_setup. rootfs . as_path ( ) ;
438- let opts = & state. target_opts ;
439450 let cancellable = gio:: Cancellable :: NONE ;
440451
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-
464452 // TODO: make configurable?
465453 let stateroot = STATEROOT_DEFAULT ;
466454 Task :: new_and_run (
@@ -535,12 +523,12 @@ async fn initialize_ostree_root_from_self(
535523 . collect :: < Vec < _ > > ( ) ;
536524 let mut options = ostree_container:: deploy:: DeployOpts :: default ( ) ;
537525 options. kargs = Some ( kargs. as_slice ( ) ) ;
538- options. target_imgref = Some ( & target_imgref) ;
526+ options. target_imgref = Some ( & state . target_imgref ) ;
539527 options. proxy_cfg = Some ( proxy_cfg) ;
540528 println ! ( "Creating initial deployment" ) ;
529+ let target_image = state. target_imgref . to_string ( ) ;
541530 let state =
542531 ostree_container:: deploy:: deploy ( & sysroot, stateroot, & src_imageref, Some ( options) ) . await ?;
543- let target_image = target_imgref. to_string ( ) ;
544532 let digest = state. manifest_digest . as_str ( ) ;
545533 println ! ( "Installed: {target_image}" ) ;
546534 println ! ( " Digest: {digest}" ) ;
@@ -789,6 +777,28 @@ pub(crate) fn propagate_tmp_mounts_to_host() -> Result<()> {
789777 Ok ( ( ) )
790778}
791779
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+
792802/// Preparation for an install; validates and prepares some (thereafter immutable) global state.
793803async fn prepare_install (
794804 config_opts : InstallConfigOpts ,
@@ -816,6 +826,34 @@ async fn prepare_install(
816826
817827 let source = SourceInfo :: from_container ( & container_info) ?;
818828
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+
819857 ensure_var ( ) ?;
820858 propagate_tmp_mounts_to_host ( ) ?;
821859
@@ -841,7 +879,7 @@ async fn prepare_install(
841879 setenforce_guard,
842880 source,
843881 config_opts,
844- target_opts ,
882+ target_imgref ,
845883 install_config,
846884 } ) ;
847885
0 commit comments