@@ -30,6 +30,7 @@ import shutil
3030import subprocess
3131import sys
3232import time
33+ from typing import Optional , Tuple
3334
3435# local imports
3536import csmock .common .util
@@ -203,6 +204,8 @@ class MockWrapper:
203204 self .results = results
204205 self .mock_profile = props .mock_profile
205206 self .mock_root_override = props .mock_root_override
207+ self .hermetic_build = props .hermetic_build
208+ self .srpm = props .srpm
206209 self .pid = os .getpid ()
207210 self .scrub_done = props .skip_mock_init
208211 self .init_done = props .skip_mock_init
@@ -282,6 +285,17 @@ echo \"$self_pid\" > \"$lock_file\"'" \
282285 "--disable-plugin=yum_cache" ]
283286 self .def_cmd += [f"--config-opts=root={ self .mock_root_override } " ]
284287
288+ if self .hermetic_build is not None :
289+ (lockfile , repo_dir ) = self .hermetic_build
290+
291+ hermetic_cmd = [mock , "--hermetic-build" , lockfile , repo_dir , "--short-circuit=prep" , "-N" , self .srpm ]
292+ ec = self .results .exec_cmd (hermetic_cmd )
293+ if ec != 0 :
294+ self .results .error ("failed to set up hermetic chroot" , ec = ec )
295+
296+ # provide the offline repo for subsequent mock commands
297+ self .def_cmd += [f"--config-opts=offline_local_repository={ repo_dir } " ]
298+
285299 return self
286300
287301 def __exit__ (self , exc_type , exc_val , exc_tb ):
@@ -403,7 +417,8 @@ echo \"$self_pid\" > \"$lock_file\"'" \
403417 self .init_done = True
404418
405419 # run `mock --calculate-build-dependencies`
406- srpm_deps_ok = srpm is None or self .install_deps (srpm )
420+ # skip for hermetic builds (deps should be calculated prior)
421+ srpm_deps_ok = srpm is None or self .hermetic_build is not None or self .install_deps (srpm )
407422 if not srpm_deps_ok and not try_only :
408423 srpm_base = os .path .basename (srpm )
409424 self .results .error (f"failed to install build dependencies of { srpm_base } " , ec = ec_by_scrub )
@@ -422,6 +437,13 @@ echo \"$self_pid\" > \"$lock_file\"'" \
422437 if not missing_deps :
423438 # no misssing dependencies
424439 return srpm_deps_ok
440+
441+ if self .hermetic_build and missing_deps :
442+ self .results .print_with_ts (
443+ f"WARN: Proceeding with hermetic build despite missing deps: { strlist_to_shell_cmd (missing_deps )} "
444+ )
445+ return srpm_deps_ok
446+
425447 if try_only :
426448 return False
427449
@@ -476,7 +498,7 @@ class ScanProps:
476498 self .shell_cmd_to_build = None
477499 self .srpm = None
478500 self .base_srpm = None
479- self .mock_profile = None
501+ self .mock_profile : Optional [ str ] = None
480502 self .base_mock_profile = None
481503 self .mock_root_override = None
482504 self .any_tool = False
@@ -486,6 +508,8 @@ class ScanProps:
486508 self .imp_csgrep_filters = []
487509 self .cswrap_path = None
488510 self .kfp_git_url = None
511+ self .hermetic_build : Optional [Tuple ] = None
512+ self .known_false_positives = None
489513
490514 def enable_cswrap (self ):
491515 if self .cswrap_enabled :
@@ -862,6 +886,14 @@ exceeds the specified limit (defaults to 1024).")
862886 help = 'override the build root directory for mock (disables yum and root cache)'
863887 )
864888
889+ parser .add_argument (
890+ "--hermetic-build" ,
891+ nargs = 2 ,
892+ metavar = ("LOCKFILE" , "REPO_DIRECTORY" ),
893+ help = "perform a hermetic (fully offline) build using a pre-generated "
894+ "lockfile and offline RPM repository (see mock --hermetic-build)" ,
895+ )
896+
865897 # --skip-patches, --diff-patches, and --shell-cmd are mutually exclusive
866898 group = parser .add_mutually_exclusive_group ()
867899 group .add_argument (
@@ -996,6 +1028,17 @@ exceeds the specified limit (defaults to 1024).")
9961028
9971029 props .mock_root_override = args .mock_root_override
9981030
1031+ if args .hermetic_build is not None :
1032+ (lockfile , repo_dir ) = args .hermetic_build
1033+ require_file (parser , lockfile )
1034+ if not os .path .isdir (repo_dir ):
1035+ parser .error ("not a directory: %s" % repo_dir )
1036+ if not os .path .isdir (os .path .join (repo_dir , "repodata" )):
1037+ parser .error ("repo directory missing repodata/: %s" % repo_dir )
1038+ props .hermetic_build = (os .path .realpath (lockfile ), os .path .realpath (repo_dir ))
1039+ props .mock_profile = "hermetic-build"
1040+ props .skip_mock_init = True
1041+
9991042 # append the list of packages to install specified on command-line
10001043 for pkg in args .install :
10011044 props .install_pkgs += pkg .split ()
0 commit comments