@@ -43,6 +43,7 @@ if [[ "${BASH_VERSINFO[0]}" -lt "4" ]]; then
4343 log_warning " Using bash version >=4 is recommended."
4444fi
4545
46+ # Determine the Macaron image tag.
4647if [[ -z ${MACARON_IMAGE_TAG:- } ]]; then
4748 MACARON_IMAGE_TAG=" latest"
4849fi
@@ -104,8 +105,14 @@ function to_absolute_path() {
104105# With the `set -e` option turned on, this function exits the script with
105106# return code 1 if the directory does not exist.
106107function assert_dir_exists() {
107- if [[ ! -d " $1 " ]]; then
108- log_err " Directory $1 of argument $2 does not exist."
108+ path=$1
109+ arg_name=$2
110+ if [[ ! -d " $path " ]]; then
111+ if [[ -z " ${arg_name:- } " ]]; then
112+ log_err " Directory $path does not exist."
113+ else
114+ log_err " Directory $path of argument $arg_name does not exist."
115+ fi
109116 return 1
110117 fi
111118}
@@ -140,6 +147,114 @@ function assert_path_exists() {
140147 fi
141148}
142149
150+ # Create a directory if it does not exist.
151+ # Arguments:
152+ # $1: The directory to create.
153+ function create_dir_if_not_exists() {
154+ dir=$1
155+ if [ ! -d " $dir " ]; then
156+ mkdir --parents " $dir "
157+ fi
158+ }
159+
160+ # Add a directory to the list of volume mounts stored in the ``mounts`` global variable.
161+ # Note: Do not use this function directly for mounting directories.
162+ # Use one among these instead: `mount_dir_ro`, `mount_dir_rw_allow_create`, or
163+ # `mount_dir_rw_forbid_create` instead.
164+ #
165+ # Arguments:
166+ # $1: The macaron argument from which the directory is passed into this script.
167+ # $2: The path to the directory on the host.
168+ # $3: The path to the directory inside the container.
169+ # $4: Mount option. Note: this MUST be either `ro,Z` for readonly volume mounts,
170+ # or `rw,Z` otherwise.
171+ function _mount_dir() {
172+ arg_name=$1
173+ dir_on_host=$2
174+ dir_in_container=$3
175+ mount_option=$4
176+
177+ dir_on_host=$( to_absolute_path " $dir_on_host " )
178+ mounts+=(" -v" " ${dir_on_host} :${dir_in_container} :${mount_option} " )
179+ }
180+
181+ # Add a directory to the list of volume mounts stored in the ``mounts`` global variable,
182+ # with the `ro,Z` mount option.
183+ # If the mounted directory does not exist on the host, this function errors
184+ # and exits the script.
185+ #
186+ # Arguments:
187+ # $1: The macaron argument from which the directory is passed into this script.
188+ # $2: The path to the directory on the host.
189+ # $3: The path to the directory inside the container.
190+ function mount_dir_ro() {
191+ arg_name=$1
192+ dir_on_host=$2
193+ dir_in_container=$3
194+
195+ assert_dir_exists " $dir_on_host " " $arg_name "
196+ _mount_dir " $arg_name " " $dir_on_host " " $dir_in_container " " ro,Z"
197+ }
198+
199+ # Add a directory to the list of volume mounts stored in the ``mounts`` global variable,
200+ # with the `rw,Z` mount option.
201+ # If the mounted directory does not exist on the host, this function creates
202+ # that directory before mounting.
203+ # Note: This function ensures compatibility with podman, as podman does not
204+ # create the directory on host if it does not exist and instead errors on mount.
205+ #
206+ # Arguments:
207+ # $1: The macaron argument from which the directory is passed into this script.
208+ # $2: The path to the directory on the host.
209+ # $3: The path to the directory inside the container.
210+ function mount_dir_rw_allow_create() {
211+ arg_name=$1
212+ dir_on_host=$2
213+ dir_in_container=$3
214+
215+ create_dir_if_not_exists " $dir_on_host "
216+ _mount_dir " $arg_name " " $dir_on_host " " $dir_in_container " " rw,Z"
217+ }
218+
219+ # Add a directory to the list of volume mounts stored in the ``mounts`` global variable,
220+ # with the `rw,Z` mount option.
221+ # If the mounted directory does not exist on the host, this function errors and
222+ # exits the script.
223+ # Note: This function ensures compatibility with podman, as podman does not
224+ # create the directory on host if it does not exist and instead errors on mount.
225+ #
226+ # Arguments:
227+ # $1: The macaron argument from which the directory is passed into this script.
228+ # $2: The path to the directory on the host.
229+ # $3: The path to the directory inside the container.
230+ function mount_dir_rw_forbid_create() {
231+ arg_name=$1
232+ dir_on_host=$2
233+ dir_in_container=$3
234+
235+ assert_dir_exists " $dir_on_host " " $arg_name "
236+ _mount_dir " $arg_name " " $dir_on_host " " $dir_in_container " " rw,Z"
237+ }
238+
239+ # Add a file to the list of volume mounts stored in the ``mounts`` global variable.
240+ #
241+ # Arguments:
242+ # $1: The macaron argument from which the file is passed into this script.
243+ # $2: The path to the file on the host.
244+ # $3: The path to the file inside the container.
245+ # $4: Mount option. Note: this MUST be either `ro,Z` for readonly volumes,
246+ # or `rw,Z` otherwise.
247+ function mount_file() {
248+ arg_name=$1
249+ file_on_host=$2
250+ file_in_container=$3
251+ mount_option=$4
252+
253+ assert_file_exists " $file_on_host " " $arg_name "
254+ file_on_host=$( to_absolute_path " $file_on_host " )
255+ mounts+=(" -v" " ${file_on_host} :${file_in_container} :${mount_option} " )
256+ }
257+
143258# Parse main arguments.
144259while [[ $# -gt 0 ]]; do
145260 case $1 in
@@ -222,130 +337,124 @@ fi
222337# Determine the output path to be mounted into ${MACARON_WORKSPACE}/output/
223338if [[ -n " ${arg_output:- } " ]]; then
224339 output=" ${arg_output} "
225- assert_dir_exists " ${output} " " -o/--output"
226340 argv_main+=(" --output" " ${MACARON_WORKSPACE} /output/" )
227341else
228342 output=$( pwd) /output
229343 echo " Setting default output directory to ${output} ."
230344fi
231345
232- output=" $( to_absolute_path " ${output} " ) "
233- # Mounting the necessary .m2 and .gradle directories.
346+ # Mount the necessary .m2 and .gradle directories.
234347m2_dir=" ${output} /.m2"
235348gradle_dir=" ${output} /.gradle"
236- mounts+=(" -v" " ${output} :${MACARON_WORKSPACE} /output:rw,Z" )
237- mounts+=(" -v" " ${m2_dir} :${MACARON_WORKSPACE} /.m2:rw,Z" )
238- mounts+=(" -v" " ${gradle_dir} :${MACARON_WORKSPACE} /.gradle:rw,Z" )
349+
350+ mount_dir_rw_allow_create " " " $output " " ${MACARON_WORKSPACE} /output"
351+ mount_dir_rw_allow_create " " " $m2_dir " " ${MACARON_WORKSPACE} /.m2"
352+ mount_dir_rw_allow_create " " " $gradle_dir " " ${MACARON_WORKSPACE} /.gradle"
239353
240354# Determine the local repos path to be mounted into ${MACARON_WORKSPACE}/output/git_repos/local_repos/
241355if [[ -n " ${arg_local_repos_path:- } " ]]; then
242- local_repos_path=" ${arg_local_repos_path} "
243- assert_dir_exists " ${local_repos_path} " " -lr/--local-repos-path"
244- argv_main+=(" --local-repos-path" " ${MACARON_WORKSPACE} /output/git_repos/local_repos/" )
356+ local_repo_path_in_container=" ${MACARON_WORKSPACE} /output/git_repos/local_repos"
245357
246- local_repos_path= " $( to_absolute_path " ${local_repos_path} " ) "
247- mounts+=( " -v " " ${local_repos_path} : ${MACARON_WORKSPACE} /output/git_repos/local_repos/:rw,Z " )
358+ argv_main+=( " --local-repos-path " " $local_repo_path_in_container " )
359+ mount_dir_rw_allow_create " -lr/--local-repos-path " " $arg_local_repos_path " " $local_repo_path_in_container "
248360fi
249361
250362# Determine the defaults path to be mounted into ${MACARON_WORKSPACE}/defaults/${file_name}
251363if [[ -n " ${arg_defaults_path:- } " ]]; then
252364 defaults_path=" ${arg_defaults_path} "
253- assert_file_exists " ${defaults_path} " " -dp/--defaults-path"
254- file_name=" $( basename " ${defaults_path} " ) "
255- argv_main+=(" --defaults-path" " ${MACARON_WORKSPACE} /defaults/${file_name} " )
365+ file_name=" $( basename " ${arg_defaults_path} " ) "
366+ defaults_path_in_container=" ${MACARON_WORKSPACE} /defaults/${file_name} "
256367
257- defaults_path= " $( to_absolute_path " ${defaults_path} " ) "
258- mounts+=( " -v " " ${ defaults_path} : ${MACARON_WORKSPACE} /defaults/ ${file_name} :ro " )
368+ argv_main+=( " --defaults-path " " $defaults_path_in_container " )
369+ mount_file " -dp/--defaults-path " " $defaults_path " " $defaults_path_in_container " " ro,Z "
259370fi
260371
261372# Determine the policy path to be mounted into ${MACARON_WORKSPACE}/policy/${file_name}
262373if [[ -n " ${arg_policy:- } " ]]; then
263- policy=" ${arg_policy} "
264- assert_file_exists " ${policy} " " -po/--policy"
265- file_name=" $( basename " ${policy} " ) "
266- argv_main+=(" --policy" " ${MACARON_WORKSPACE} /policy/${file_name} " )
374+ policy_file=" ${arg_policy} "
375+ file_name=" $( basename " ${policy_file} " ) "
376+ policy_file_in_container=" ${MACARON_WORKSPACE} /policy/${file_name} "
267377
268- policy= " $( to_absolute_path " ${policy} " ) "
269- mounts+=( " -v " " ${policy} : ${MACARON_WORKSPACE} /policy/ ${file_name} :ro " )
378+ argv_main+=( " --policy " " $policy_file_in_container " )
379+ mount_file " -po/--policy " " $policy_file " " $policy_file_in_container " " ro,Z "
270380fi
271381
272382# MACARON entrypoint - Analyze command argvs
273383# Determine the template path to be mounted into ${MACARON_WORKSPACE}/template/${file_name}
274384if [[ -n " ${arg_template_path:- } " ]]; then
275385 template_path=" ${arg_template_path} "
276- assert_file_exists " ${template_path} " " -g/--template-path"
277386 file_name=" $( basename " ${template_path} " ) "
278- argv_command+=( " --template-path " " ${MACARON_WORKSPACE} /template/${file_name} " )
387+ template_path_in_container= " ${MACARON_WORKSPACE} /template/${file_name} "
279388
280- template_path= " $( to_absolute_path " ${template_path} " ) "
281- mounts+=( " -v " " ${ template_path} : ${MACARON_WORKSPACE} /template/ ${file_name} :ro " )
389+ argv_command+=( " --template-path " " $template_path_in_container " )
390+ mount_file " -g/--template-path " " $template_path " " $template_path_in_container " " ro,Z "
282391fi
283392
284393# Determine the config path to be mounted into ${MACARON_WORKSPACE}/config/${file_name}
285394if [[ -n " ${arg_config_path:- } " ]]; then
286395 config_path=" ${arg_config_path} "
287- assert_file_exists " ${config_path} " " -c/--config-path"
288396 file_name=" $( basename " ${config_path} " ) "
289- argv_command+=( " --config-path " " ${MACARON_WORKSPACE} /config/${file_name} " )
397+ config_path_in_container= " ${MACARON_WORKSPACE} /config/${file_name} "
290398
291- config_path= " $( to_absolute_path " ${config_path} " ) "
292- mounts+=( " -v " " ${ config_path} : ${MACARON_WORKSPACE} /config/ ${file_name} :ro " )
399+ argv_command+=( " --config-path " " $config_path_in_container " )
400+ mount_file " -c/--config-path " " $config_path " " $config_path_in_container " " ro,Z "
293401fi
294402
295403# Determine the sbom path to be mounted into ${MACARON_WORKSPACE}/sbom/${file_name}
296404if [[ -n " ${arg_sbom_path:- } " ]]; then
297405 sbom_path=" ${arg_sbom_path} "
298- assert_file_exists " ${sbom_path} " " -sbom/--sbom-path"
299406 file_name=" $( basename " ${sbom_path} " ) "
300- argv_command+=( " --sbom-path " " ${MACARON_WORKSPACE} /sbom/${file_name} " )
407+ sbom_path_in_container= " ${MACARON_WORKSPACE} /sbom/${file_name} "
301408
302- sbom_path= " $( to_absolute_path " ${sbom_path} " ) "
303- mounts+=( " -v " " ${ sbom_path} : ${MACARON_WORKSPACE} /sbom/ ${file_name} :ro " )
409+ argv_command+=( " --sbom-path " " $sbom_path_in_container " )
410+ mount_file " -sbom/--sbom-path " " $sbom_path " " $sbom_path_in_container " " ro,Z "
304411fi
305412
306- # Determine the provenance expectation path to be mounted into ${MACARON_WORKSPACE}/prov_expectations/${file_name}
413+ # Determine the provenance expectation path to be mounted into ${MACARON_WORKSPACE}/prov_expectations/${pe_name} where pe_name can either be a directory or a file
307414if [[ -n " ${arg_prov_exp:- } " ]]; then
308- prov_exp=" ${arg_prov_exp} "
309- assert_path_exists " ${prov_exp} " " -pe/--provenance-expectation"
310- pe_name=" $( basename " ${prov_exp} " ) "
311- argv_command+=(" --provenance-expectation" " ${MACARON_WORKSPACE} /prov_expectations/${pe_name} " )
312-
313- prov_exp=" $( to_absolute_path " ${prov_exp} " ) "
314- mounts+=(" -v" " ${prov_exp} :${MACARON_WORKSPACE} /prov_expectations/${pe_name} :ro" )
415+ prov_exp_path=" ${arg_prov_exp} "
416+ assert_path_exists " ${prov_exp_path} " " -pe/--provenance-expectation"
417+ prov_exp_name=" $( basename " ${prov_exp_path} " ) "
418+ prov_exp_path_in_container=${MACARON_WORKSPACE} /prov_expectations/${prov_exp_name}
419+ argv_command+=(" --provenance-expectation" " $prov_exp_path_in_container " )
420+
421+ if [ -d " $prov_exp_path " ]; then
422+ mount_dir_ro " -pe/--provenance-expectation" " $prov_exp_path " " $prov_exp_path_in_container "
423+ elif [ -f " $prov_exp_path " ]; then
424+ mount_file " -pe/--provenance-expectation" " $prov_exp_path " " $prov_exp_path_in_container " " ro,Z"
425+ fi
315426fi
316427
317428# MACARON entrypoint - verify-policy command argvs
318429# This is for macaron verify-policy command.
319430# Determine the database path to be mounted into ${MACARON_WORKSPACE}/database/macaron.db
320431if [[ -n " ${arg_database:- } " ]]; then
321- database=" ${arg_database} "
322- assert_file_exists " ${database} " " -d/--database"
323- file_name=" $( basename " ${database} " ) "
324- argv_command+=(" --database" " ${MACARON_WORKSPACE} /database/${file_name} " )
432+ database_path=" ${arg_database} "
433+ file_name=" $( basename " ${database_path} " ) "
434+ database_path_in_container=" ${MACARON_WORKSPACE} /database/${file_name} "
325435
326- database= " $( to_absolute_path " ${database} " ) "
327- mounts+=( " -v " " ${database} : ${MACARON_WORKSPACE} /database/ ${file_name} : rw,Z" )
436+ argv_command+=( " --database " " $database_path_in_container " )
437+ mount_file " -d/--database " " $database_path " " $database_path_in_container " " rw,Z"
328438fi
329439
330440# Determine the Datalog policy to be verified by verify-policy command.
331441if [[ -n " ${arg_datalog_policy_file:- } " ]]; then
332442 datalog_policy_file=" ${arg_datalog_policy_file} "
333- assert_file_exists " ${datalog_policy_file} " " -f/--file"
334443 file_name=" $( basename " ${datalog_policy_file} " ) "
335- argv_command+=( " --file " " ${MACARON_WORKSPACE} /policy/${file_name} " )
444+ datalog_policy_file_in_container= " ${MACARON_WORKSPACE} /policy/${file_name} "
336445
337- datalog_policy_file= " $( to_absolute_path " ${datalog_policy_file} " ) "
338- mounts+=( " -v " " ${ datalog_policy_file} : ${MACARON_WORKSPACE} /policy/ ${file_name} :ro " )
446+ argv_command+=( " --file " " $datalog_policy_file_in_container " )
447+ mount_file " -f/--file " " $datalog_policy_file " " $datalog_policy_file_in_container " " ro,Z "
339448fi
340449
341450# Determine that ~/.gradle/gradle.properties exists to be mounted into ${MACARON_WORKSPACE}/gradle.properties
342451if [[ -f " $HOME /.gradle/gradle.properties" ]]; then
343- mounts+=(" -v" " $HOME /.gradle/gradle.properties" :" ${MACARON_WORKSPACE} /gradle.properties:ro" )
452+ mounts+=(" -v" " $HOME /.gradle/gradle.properties" :" ${MACARON_WORKSPACE} /gradle.properties:ro,Z " )
344453fi
345454
346455# Determine that ~/.m2/settings.xml exists to be mounted into ${MACARON_WORKSPACE}/settings.xml
347456if [[ -f " $HOME /.m2/settings.xml" ]]; then
348- mounts+=(" -v" " $HOME /.m2/settings.xml" :" ${MACARON_WORKSPACE} /settings.xml:ro" )
457+ mounts+=(" -v" " $HOME /.m2/settings.xml" :" ${MACARON_WORKSPACE} /settings.xml:ro,Z " )
349458fi
350459
351460# Set up proxy.
@@ -419,8 +528,15 @@ if [[ -n ${MCN_DEBUG_ARGS:-} ]]; then
419528 exit 0
420529fi
421530
531+ # By default
532+ # - docker maps the host user $UID to a user with the same $UID in the container.
533+ # - podman maps the host user $UID to the root user in the container.
534+ # To make podman behave similarly to docker, we need to set the following env var.
535+ # Reference: https://docs.podman.io/en/v4.4/markdown/options/userns.container.html.
536+ export PODMAN_USERNS=keep-id
537+
422538docker run \
423- --pull ${DOCKER_PULL} \
539+ --pull " ${DOCKER_PULL} " \
424540 --network=host \
425541 --rm -i " ${tty[@]} " \
426542 -e " USER_UID=${USER_UID} " \
0 commit comments