Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: resolve podman compatibility issues #512

Merged
merged 4 commits into from
Nov 1, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
230 changes: 173 additions & 57 deletions scripts/release_scripts/run_macaron.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ if [[ "${BASH_VERSINFO[0]}" -lt "4" ]]; then
log_warning "Using bash version >=4 is recommended."
fi

# Determine the Macaron image tag.
if [[ -z ${MACARON_IMAGE_TAG:-} ]]; then
MACARON_IMAGE_TAG="latest"
fi
Expand Down Expand Up @@ -104,8 +105,14 @@ function to_absolute_path() {
# With the `set -e` option turned on, this function exits the script with
# return code 1 if the directory does not exist.
function assert_dir_exists() {
if [[ ! -d "$1" ]]; then
log_err "Directory $1 of argument $2 does not exist."
path=$1
arg_name=$2
if [[ ! -d "$path" ]]; then
if [[ -z "${arg_name:-}" ]]; then
log_err "Directory $path does not exist."
else
log_err "Directory $path of argument $arg_name does not exist."
fi
return 1
fi
}
Expand Down Expand Up @@ -140,6 +147,114 @@ function assert_path_exists() {
fi
}

# Create a directory if it does not exist.
# Arguments:
# $1: The directory to create.
function create_dir_if_not_exists() {
dir=$1
if [ ! -d "$dir" ]; then
mkdir --parents "$dir"
fi
}

# Add a directory to the list of volume mounts stored in the ``mounts`` global variable.
# Note: Do not use this function directly for mounting directories.
# Use one among these instead: `mount_dir_ro`, `mount_dir_rw_allow_create`, or
# `mount_dir_rw_forbid_create` instead.
#
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good to rename the function to indicate that it can potentially create a directory.

In addition, please add a note here that this function can have side effect, i.e., if the mounted directory does not exist, it will create it.

# Arguments:
# $1: The macaron argument from which the directory is passed into this script.
# $2: The path to the directory on the host.
# $3: The path to the directory inside the container.
# $4: Mount option. Note: this MUST be either `ro,Z` for readonly volume mounts,
# or `rw,Z` otherwise.
function _mount_dir() {
arg_name=$1
dir_on_host=$2
dir_in_container=$3
mount_option=$4

dir_on_host=$(to_absolute_path "$dir_on_host")
mounts+=("-v" "${dir_on_host}:${dir_in_container}:${mount_option}")
}

# Add a directory to the list of volume mounts stored in the ``mounts`` global variable,
# with the `ro,Z` mount option.
# If the mounted directory does not exist on the host, this function errors
# and exits the script.
#
# Arguments:
# $1: The macaron argument from which the directory is passed into this script.
# $2: The path to the directory on the host.
# $3: The path to the directory inside the container.
function mount_dir_ro() {
arg_name=$1
dir_on_host=$2
dir_in_container=$3

assert_dir_exists "$dir_on_host" "$arg_name"
_mount_dir "$arg_name" "$dir_on_host" "$dir_in_container" "ro,Z"
}

# Add a directory to the list of volume mounts stored in the ``mounts`` global variable,
# with the `rw,Z` mount option.
# If the mounted directory does not exist on the host, this function creates
# that directory before mounting.
# Note: This function ensures compatibility with podman, as podman does not
# create the directory on host if it does not exist and instead errors on mount.
#
# Arguments:
# $1: The macaron argument from which the directory is passed into this script.
# $2: The path to the directory on the host.
# $3: The path to the directory inside the container.
function mount_dir_rw_allow_create() {
arg_name=$1
dir_on_host=$2
dir_in_container=$3

create_dir_if_not_exists "$dir_on_host"
_mount_dir "$arg_name" "$dir_on_host" "$dir_in_container" "rw,Z"
}

# Add a directory to the list of volume mounts stored in the ``mounts`` global variable,
# with the `rw,Z` mount option.
# If the mounted directory does not exist on the host, this function errors and
# exits the script.
# Note: This function ensures compatibility with podman, as podman does not
# create the directory on host if it does not exist and instead errors on mount.
#
# Arguments:
# $1: The macaron argument from which the directory is passed into this script.
# $2: The path to the directory on the host.
# $3: The path to the directory inside the container.
function mount_dir_rw_forbid_create() {
arg_name=$1
dir_on_host=$2
dir_in_container=$3

assert_dir_exists "$dir_on_host" "$arg_name"
_mount_dir "$arg_name" "$dir_on_host" "$dir_in_container" "rw,Z"
}

# Add a file to the list of volume mounts stored in the ``mounts`` global variable.
#
# Arguments:
# $1: The macaron argument from which the file is passed into this script.
# $2: The path to the file on the host.
# $3: The path to the file inside the container.
# $4: Mount option. Note: this MUST be either `ro,Z` for readonly volumes,
# or `rw,Z` otherwise.
function mount_file() {
arg_name=$1
file_on_host=$2
file_in_container=$3
mount_option=$4

assert_file_exists "$file_on_host" "$arg_name"
file_on_host=$(to_absolute_path "$file_on_host")
mounts+=("-v" "${file_on_host}:${file_in_container}:${mount_option}")
}

# Parse main arguments.
while [[ $# -gt 0 ]]; do
case $1 in
Expand Down Expand Up @@ -222,130 +337,124 @@ fi
# Determine the output path to be mounted into ${MACARON_WORKSPACE}/output/
if [[ -n "${arg_output:-}" ]]; then
output="${arg_output}"
assert_dir_exists "${output}" "-o/--output"
argv_main+=("--output" "${MACARON_WORKSPACE}/output/")
else
output=$(pwd)/output
echo "Setting default output directory to ${output}."
fi

output="$(to_absolute_path "${output}")"
# Mounting the necessary .m2 and .gradle directories.
# Mount the necessary .m2 and .gradle directories.
m2_dir="${output}/.m2"
gradle_dir="${output}/.gradle"
mounts+=("-v" "${output}:${MACARON_WORKSPACE}/output:rw,Z")
mounts+=("-v" "${m2_dir}:${MACARON_WORKSPACE}/.m2:rw,Z")
mounts+=("-v" "${gradle_dir}:${MACARON_WORKSPACE}/.gradle:rw,Z")

mount_dir_rw_allow_create "" "$output" "${MACARON_WORKSPACE}/output"
mount_dir_rw_allow_create "" "$m2_dir" "${MACARON_WORKSPACE}/.m2"
mount_dir_rw_allow_create "" "$gradle_dir" "${MACARON_WORKSPACE}/.gradle"

# Determine the local repos path to be mounted into ${MACARON_WORKSPACE}/output/git_repos/local_repos/
if [[ -n "${arg_local_repos_path:-}" ]]; then
local_repos_path="${arg_local_repos_path}"
assert_dir_exists "${local_repos_path}" "-lr/--local-repos-path"
argv_main+=("--local-repos-path" "${MACARON_WORKSPACE}/output/git_repos/local_repos/")
local_repo_path_in_container="${MACARON_WORKSPACE}/output/git_repos/local_repos"

local_repos_path="$(to_absolute_path "${local_repos_path}")"
mounts+=("-v" "${local_repos_path}:${MACARON_WORKSPACE}/output/git_repos/local_repos/:rw,Z")
argv_main+=("--local-repos-path" "$local_repo_path_in_container")
mount_dir_rw_allow_create "-lr/--local-repos-path" "$arg_local_repos_path" "$local_repo_path_in_container"
fi

# Determine the defaults path to be mounted into ${MACARON_WORKSPACE}/defaults/${file_name}
if [[ -n "${arg_defaults_path:-}" ]]; then
defaults_path="${arg_defaults_path}"
assert_file_exists "${defaults_path}" "-dp/--defaults-path"
file_name="$(basename "${defaults_path}")"
argv_main+=("--defaults-path" "${MACARON_WORKSPACE}/defaults/${file_name}")
file_name="$(basename "${arg_defaults_path}")"
defaults_path_in_container="${MACARON_WORKSPACE}/defaults/${file_name}"

defaults_path="$(to_absolute_path "${defaults_path}")"
mounts+=("-v" "${defaults_path}:${MACARON_WORKSPACE}/defaults/${file_name}:ro")
argv_main+=("--defaults-path" "$defaults_path_in_container")
mount_file "-dp/--defaults-path" "$defaults_path" "$defaults_path_in_container" "ro,Z"
fi

# Determine the policy path to be mounted into ${MACARON_WORKSPACE}/policy/${file_name}
if [[ -n "${arg_policy:-}" ]]; then
policy="${arg_policy}"
assert_file_exists "${policy}" "-po/--policy"
file_name="$(basename "${policy}")"
argv_main+=("--policy" "${MACARON_WORKSPACE}/policy/${file_name}")
policy_file="${arg_policy}"
file_name="$(basename "${policy_file}")"
policy_file_in_container="${MACARON_WORKSPACE}/policy/${file_name}"

policy="$(to_absolute_path "${policy}")"
mounts+=("-v" "${policy}:${MACARON_WORKSPACE}/policy/${file_name}:ro")
argv_main+=("--policy" "$policy_file_in_container")
mount_file "-po/--policy" "$policy_file" "$policy_file_in_container" "ro,Z"
fi

# MACARON entrypoint - Analyze command argvs
# Determine the template path to be mounted into ${MACARON_WORKSPACE}/template/${file_name}
if [[ -n "${arg_template_path:-}" ]]; then
template_path="${arg_template_path}"
assert_file_exists "${template_path}" "-g/--template-path"
file_name="$(basename "${template_path}")"
argv_command+=("--template-path" "${MACARON_WORKSPACE}/template/${file_name}")
template_path_in_container="${MACARON_WORKSPACE}/template/${file_name}"

template_path="$(to_absolute_path "${template_path}")"
mounts+=("-v" "${template_path}:${MACARON_WORKSPACE}/template/${file_name}:ro")
argv_command+=("--template-path" "$template_path_in_container")
mount_file "-g/--template-path" "$template_path" "$template_path_in_container" "ro,Z"
fi

# Determine the config path to be mounted into ${MACARON_WORKSPACE}/config/${file_name}
if [[ -n "${arg_config_path:-}" ]]; then
config_path="${arg_config_path}"
assert_file_exists "${config_path}" "-c/--config-path"
file_name="$(basename "${config_path}")"
argv_command+=("--config-path" "${MACARON_WORKSPACE}/config/${file_name}")
config_path_in_container="${MACARON_WORKSPACE}/config/${file_name}"

config_path="$(to_absolute_path "${config_path}")"
mounts+=("-v" "${config_path}:${MACARON_WORKSPACE}/config/${file_name}:ro")
argv_command+=("--config-path" "$config_path_in_container")
mount_file "-c/--config-path" "$config_path" "$config_path_in_container" "ro,Z"
fi

# Determine the sbom path to be mounted into ${MACARON_WORKSPACE}/sbom/${file_name}
if [[ -n "${arg_sbom_path:-}" ]]; then
sbom_path="${arg_sbom_path}"
assert_file_exists "${sbom_path}" "-sbom/--sbom-path"
file_name="$(basename "${sbom_path}")"
argv_command+=("--sbom-path" "${MACARON_WORKSPACE}/sbom/${file_name}")
sbom_path_in_container="${MACARON_WORKSPACE}/sbom/${file_name}"

sbom_path="$(to_absolute_path "${sbom_path}")"
mounts+=("-v" "${sbom_path}:${MACARON_WORKSPACE}/sbom/${file_name}:ro")
argv_command+=("--sbom-path" "$sbom_path_in_container")
mount_file "-sbom/--sbom-path" "$sbom_path" "$sbom_path_in_container" "ro,Z"
fi

# Determine the provenance expectation path to be mounted into ${MACARON_WORKSPACE}/prov_expectations/${file_name}
# 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
if [[ -n "${arg_prov_exp:-}" ]]; then
prov_exp="${arg_prov_exp}"
assert_path_exists "${prov_exp}" "-pe/--provenance-expectation"
pe_name="$(basename "${prov_exp}")"
argv_command+=("--provenance-expectation" "${MACARON_WORKSPACE}/prov_expectations/${pe_name}")

prov_exp="$(to_absolute_path "${prov_exp}")"
mounts+=("-v" "${prov_exp}:${MACARON_WORKSPACE}/prov_expectations/${pe_name}:ro")
prov_exp_path="${arg_prov_exp}"
assert_path_exists "${prov_exp_path}" "-pe/--provenance-expectation"
prov_exp_name="$(basename "${prov_exp_path}")"
prov_exp_path_in_container=${MACARON_WORKSPACE}/prov_expectations/${prov_exp_name}
argv_command+=("--provenance-expectation" "$prov_exp_path_in_container")

if [ -d "$prov_exp_path" ]; then
mount_dir_ro "-pe/--provenance-expectation" "$prov_exp_path" "$prov_exp_path_in_container"
elif [ -f "$prov_exp_path" ]; then
mount_file "-pe/--provenance-expectation" "$prov_exp_path" "$prov_exp_path_in_container" "ro,Z"
fi
fi

# MACARON entrypoint - verify-policy command argvs
# This is for macaron verify-policy command.
# Determine the database path to be mounted into ${MACARON_WORKSPACE}/database/macaron.db
if [[ -n "${arg_database:-}" ]]; then
database="${arg_database}"
assert_file_exists "${database}" "-d/--database"
file_name="$(basename "${database}")"
argv_command+=("--database" "${MACARON_WORKSPACE}/database/${file_name}")
database_path="${arg_database}"
file_name="$(basename "${database_path}")"
database_path_in_container="${MACARON_WORKSPACE}/database/${file_name}"

database="$(to_absolute_path "${database}")"
mounts+=("-v" "${database}:${MACARON_WORKSPACE}/database/${file_name}:rw,Z")
argv_command+=("--database" "$database_path_in_container")
mount_file "-d/--database" "$database_path" "$database_path_in_container" "rw,Z"
fi

# Determine the Datalog policy to be verified by verify-policy command.
if [[ -n "${arg_datalog_policy_file:-}" ]]; then
datalog_policy_file="${arg_datalog_policy_file}"
assert_file_exists "${datalog_policy_file}" "-f/--file"
file_name="$(basename "${datalog_policy_file}")"
argv_command+=("--file" "${MACARON_WORKSPACE}/policy/${file_name}")
datalog_policy_file_in_container="${MACARON_WORKSPACE}/policy/${file_name}"

datalog_policy_file="$(to_absolute_path "${datalog_policy_file}")"
mounts+=("-v" "${datalog_policy_file}:${MACARON_WORKSPACE}/policy/${file_name}:ro")
argv_command+=("--file" "$datalog_policy_file_in_container")
mount_file "-f/--file" "$datalog_policy_file" "$datalog_policy_file_in_container" "ro,Z"
fi

# Determine that ~/.gradle/gradle.properties exists to be mounted into ${MACARON_WORKSPACE}/gradle.properties
if [[ -f "$HOME/.gradle/gradle.properties" ]]; then
mounts+=("-v" "$HOME/.gradle/gradle.properties":"${MACARON_WORKSPACE}/gradle.properties:ro")
mounts+=("-v" "$HOME/.gradle/gradle.properties":"${MACARON_WORKSPACE}/gradle.properties:ro,Z")
fi

# Determine that ~/.m2/settings.xml exists to be mounted into ${MACARON_WORKSPACE}/settings.xml
if [[ -f "$HOME/.m2/settings.xml" ]]; then
mounts+=("-v" "$HOME/.m2/settings.xml":"${MACARON_WORKSPACE}/settings.xml:ro")
mounts+=("-v" "$HOME/.m2/settings.xml":"${MACARON_WORKSPACE}/settings.xml:ro,Z")
fi

# Set up proxy.
Expand Down Expand Up @@ -419,8 +528,15 @@ if [[ -n ${MCN_DEBUG_ARGS:-} ]]; then
exit 0
fi

# By default
# - docker maps the host user $UID to a user with the same $UID in the container.
# - podman maps the host user $UID to the root user in the container.
# To make podman behave similarly to docker, we need to set the following env var.
# Reference: https://docs.podman.io/en/v4.4/markdown/options/userns.container.html.
export PODMAN_USERNS=keep-id

docker run \
--pull ${DOCKER_PULL} \
--pull "${DOCKER_PULL}" \
--network=host \
--rm -i "${tty[@]}" \
-e "USER_UID=${USER_UID}" \
Expand Down
Loading